--- tags: - raspberry-pi - nas - openmediavault - how-to created: '2026-05-11' updated: '2026-05-12' status: hermes-pending ip: 192.168.1.14 --- # OpenMediaVault на Raspberry Pi 5 **Статус:** Контейнеры запущены, Time Machine pending (май 2026) **Цель:** NAS на RPi 5 — OS на SD-карте, хранилище на USB 3.0 HDD ## Прогресс | Шаг | Статус | Заметки | |-----|--------|---------| | 1 — Флашим SD | ✅ | Bookworm 2025-05-13, RPi Imager | | 2 — Первый запуск + обновление | ✅ | apt upgrade выполнен | | 3 — Установка OMV | ✅ | OMV 7 установлен | | 4 — Первый вход в веб-интерфейс | ✅ | Пароль сменён | | 5 — Сеть | ✅ | DHCP static lease `192.168.1.14` (eth0 MAC `2c:cf:67:64:03:f3`); WiFi включён (wlan0, ASUS5, 192.168.1.15, 2026-05-19) | | 6 — USB HDD | ✅ | 12TB Seagate ST12000NT001, EXT4, UUID `49e8f586-3839-4c5d-a1e1-58bfc3579ade`, смонтирован через OMV в `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade` | | 7 — omv-extras + Docker | ✅ | omv-extras 7.0.6, Docker 29.4.3, kraken в группе docker | | 8 — Контейнеры | ✅ | Все через отдельные docker compose, конфиги на HDD (см. ниже) | | 9 — Time Machine share | ✅ | `mbentley/timemachine:smb`, расписание 10:00-22:00 GMT+6, HDD/timemachine | | 10 — Перенос данных | N/A | не входит в этот гайд | | 11 — Hermes агент Кракен | ✅ | Запущен, Telegram @kraken_htpc_bot живой, mcpvault ✅, obsidian RW, SOUL.md, browser/Playwright ✅, Spotify ✅ | | 11а — Docker на HDD | ✅ | data-root + containerd перенесены на HDD через symlink, SD освободилась до 22% | | 12 — Obsidian sync (Taiga↔Kraken↔Eagle) | ✅ | Все 3 узла работают, кроны активны, двусторонний sync протестирован | || 13 — Vault wiki (llm-wiki) | ✅ | Eagle: scheduled wiki-curation job, Karpathy-style. Active 2026-05-13. | | 14 — SMB media share | ✅ | Samba вручную, шара `media` read-only guest. smbd enabled. | --- ## Железо - Raspberry Pi 5 (4 или 8 GB RAM) - SD-карта ≥16 GB (Samsung/SanDisk A1 Class 10+) - USB 3.0 HDD для хранения данных - Проводной Ethernet (обязателен) --- ## Шаг 1 — Флашим SD-карту **Образ:** Raspberry Pi OS Lite **64-bit (Bookworm / Debian 12)** > ⚠️ Брать именно Bookworm, не Trixie (Debian 13) — OMV не поддерживается на Trixie! - Последний Bookworm: **2025-05-13** - Прямая ссылка: https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2025-05-13/2025-05-13-raspios-bookworm-arm64-lite.img.xz **Инструмент:** Raspberry Pi Imager (https://www.raspberrypi.com/software/) > ⚠️ Не Balena Etcher — только RPi Imager поддерживает OS Customisation! > При выборе образа из каталога (не custom file) появляется кнопка "Edit Settings" **Настройки (Edit Settings → шестерёнка):** - Hostname: `kraken` - Username: `kraken` (не `admin` — зарезервировано для OMV!) - Password: сохранён в 1Password (запись "Kraken RPi") - SSH: Enable → Allow public-key authentication → вставить `~/.ssh/id_rsa.pub` После флаша вставить карту в Pi и включить. --- ## Шаг 2 — Первый запуск, обновление и настройка сети SSH подключение (пока через WiFi/роутер): ```bash ssh -i ~/.ssh/id_rsa kraken@kraken ``` Обновление системы: ```bash sudo apt-get update && sudo apt-get upgrade -y ``` Static IP на eth0 (прямой кабель Mac ↔ Pi для установки): ```bash sudo nmcli con add type ethernet ifname eth0 con-name eth0-static \ ipv4.method manual \ ipv4.addresses 192.168.100.2/24 \ ipv4.gateway 192.168.100.1 \ ipv4.never-default yes \ connection.autoconnect yes sudo nmcli con up eth0-static ``` > ⚠️ `ipv4.never-default yes` — обязательно! Иначе интернет пойдёт через Mac, а не WiFi, и установка зависнет. --- ## Шаг 3 — Установка OMV ```bash # Pre-install wget -qO- https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/preinstall | sudo bash sudo reboot # После перезагрузки — основная установка (~30 мин) wget -qO- https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install | sudo bash ``` Pi перезагрузится автоматически по окончании. --- ## Шаг 4 — Первый вход в веб-интерфейс - URL: `http://192.168.100.2` (или `http://kraken` через LAN) - Логин: `admin` - Пароль: `openmediavault` - **Сразу сменить пароль!** (System → General Settings → Web Administrator Password) --- ## Шаг 5 — Сеть: DHCP + static lease, отключить WiFi Переключить кабель Pi → роутер. Настроить DHCP через netplan (OMV управляет `/etc/netplan/20-openmediavault-eth0.yaml`): ```yaml network: ethernets: eth0: match: macaddress: "2c:cf:67:64:03:f3" dhcp4: yes dhcp6: no link-local: [] ``` В роутере (ASUS): добавить static lease в `dhcp_staticlist` через nvram: ```bash ssh -i ~/.ssh/id_rsa admin@192.168.1.1 \ "nvram set dhcp_staticlist='...<2C:CF:67:64:03:F3>192.168.1.14>kraken>' && nvram commit && service restart_dnsmasq" ``` Отключить WiFi навсегда (modprobe blacklist): ```bash sudo sh -c 'echo blacklist brcmfmac > /etc/modprobe.d/disable-wifi.conf' < /dev/null sudo sh -c 'echo blacklist brcmutil >> /etc/modprobe.d/disable-wifi.conf' < /dev/null sudo update-initramfs -u -k all < /dev/null ``` > ⚠️ Все sudo команды через SSH требуют `< /dev/null` — иначе sudo ждёт stdin и зависает --- ## Шаг 6 — USB HDD 1. Подключить HDD к синему (USB 3.0) порту Pi 2. Проверить скорость: `sudo apt install hdparm && sudo hdparm -t --direct /dev/sda` → должно быть ~200-250 MB/s 3. Разметить: `sudo parted -s /dev/sda mklabel gpt mkpart primary 0% 100%` 4. Форматировать (агент не может — только вручную или через скрипт): ```bash sudo bash /tmp/fmt.sh # скрипт с mkfs.ext4 -L storage /dev/sda1 ``` 5. OMV Web UI → Storage → File Systems → выбрать `/dev/sda1` → Mount 6. OMV монтирует в: `/srv/dev-disk-by-uuid-/` > ⚠️ Не монтировать вручную через fstab — OMV должен управлять монтированием сам --- ## Шаг 7 — omv-extras + Docker ```bash # omv-extras wget -qO- https://github.com/OpenMediaVault-Plugin-Developers/packages/raw/master/install | sudo bash < /dev/null # Docker curl -fsSL https://get.docker.com -o /tmp/get-docker.sh && sudo sh /tmp/get-docker.sh < /dev/null sudo usermod -aG docker kraken < /dev/null ``` --- ## Шаг 8 — Docker контейнеры Каждый сервис — отдельный `docker-compose.yml` в `/home/kraken//`. Все конфиги на HDD: `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker//` | Сервис | Compose | URL | Данные | |--------|---------|-----|--------| | Portainer | `/home/kraken/portainer/` | :9000 | HDD/docker/portainer | | Watchtower | `/home/kraken/watchtower/` | — | stateless | | Home Assistant | `/home/kraken/homeassistant/` | :8123 | HDD/docker/homeassistant | | Jellyfin | `/home/kraken/media/` | :8096 | HDD/docker/jellyfin, media:ro | | Transmission | `/home/kraken/media/` | :9091 | HDD/docker/transmission, HDD/media/downloads | | Prowlarr | `/home/kraken/radarr/` | :9696 | HDD/docker/prowlarr | | Radarr | `/home/kraken/radarr/` | :7878 | HDD/docker/radarr, media:rw | | Sonarr | `/home/kraken/radarr/` | :8989 | HDD/docker/sonarr, media:rw | | Rclone | `/home/kraken/rclone/` | — | cron воскр. 03:00 → mailru-crypt:kraken/docker | Управление: ```bash cd /home/kraken/ && sudo docker compose up -d # запустить cd /home/kraken/ && sudo docker compose restart # рестарт cd /home/kraken/ && sudo docker compose pull && sudo docker compose up -d # обновить ``` > ⚠️ Watchtower: нужна переменная `DOCKER_API_VERSION=1.54` — иначе крашится (API mismatch) > ⚠️ sudo через SSH требует `< /dev/null` для каждой команды с tee/pipe --- ## Media pipeline — Transmission hook + PGS→SRT **Статус: ✅ (2026-05-18)** ### Схема ``` Transmission → on-download-complete.sh → media-pipeline:kraken sync (NFO, библиотека) → pgs-to-srt.sh (PGS субтитры → SRT) ``` ### Файлы ``` HDD/docker/media-pipeline/ on-download-complete.sh — монтирован в Transmission как /config/on-download-complete.sh (ro) pgs-to-srt.sh — конвертация PGS→SRT через pgsrip config.json — конфиг media-pipeline download-complete.log — лог загрузок pgs-to-srt.log — лог конвертации ``` ### on-download-complete.sh Запускается Transmission синхронно при завершении загрузки (`script-torrent-done-filename`). Получает `TR_TORRENT_DIR` и `TR_TORRENT_NAME` — пути **внутри контейнера** (`/downloads/...`). Вызывает `pgs-to-srt.sh` с путём `/downloads/complete/radarr/...` — скрипт сам переводит в хостовый путь. > ⚠️ Скрипт выполняется **внутри контейнера Transmission** — хостовые пути недоступны напрямую. > `/downloads` → `HDD/media/downloads`, `/media` → `HDD/media` смонтированы в контейнере. > Не вызывать бинарники с хостовых путей (`$HDD/...`) — они недоступны внутри контейнера. ### pgs-to-srt.sh - Живёт на **хосте** (`HDD/docker/media-pipeline/`), вызывается из `on-download-complete.sh` - Использует `mkvmerge -i` для детекции PGS/VobSub (быстрее `mkvinfo`) - PGS → `~/.local/bin/pgsrip -l ru -l en` - VobSub → `SKIP` (не реализовано) - Маркер `.sub-checked` рядом с mkv — пропускать уже проверенные файлы при bulk-скане - Флаг `-l ru -l en` (два отдельных флага, не через запятую!) ### Библиотека субтитров (итог скана 2026-05-18) | Папка | Тип | Статус | |-------|-----|--------| | documentaries-series/пингвины. шпион в толпе (3 файла) | HDMV PGS | ✅ .ru.srt + .en.srt | | documentaries-series/жизнь птиц 1998 (10 файлов) | VobSub | ❌ не конвертированы (SKIP) | | Всё остальное | SRT внутри mkv | ✅ транскода нет | ### Remote path mapping (Radarr/Sonarr) Transmission пишет в `/downloads/complete/{radarr,sonarr}/...` (внутри контейнера). Radarr/Sonarr видят файлы через `/media/downloads/...`. Маппинг добавлен: `host=transmission, remotePath=/downloads/, localPath=/media/downloads/`. --- ## Шаг 9 — Time Machine share Контейнер: `mbentley/timemachine:smb` Compose: `/home/kraken/timemachine/docker-compose.yml` Данные: `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/timemachine/` **Расписание** (root crontab): - `0 4 * * *` UTC (10:00 GMT+6) → `/usr/local/bin/tm-start.sh` — поднять контейнер ✅ добавлен 2026-05-14 - `0 16 * * *` UTC (22:00 GMT+6) → `/usr/local/bin/tm-stop.sh` — остановить контейнер ✅ добавлен 2026-05-14 - `restart: no` — при загрузке Pi не стартует автоматически **Credentials:** - Пользователь: `timemachine` - Пароль: `timemachine` ⚠️ сменить позже **Подключение с Mac:** 1. Finder → `⌘K` → `smb://kraken` 2. Логин: `timemachine` / `timemachine` 3. System Preferences → Time Machine → Add Disk → выбрать `kraken` Лог cron: `/var/log/timemachine-cron.log` --- ## Шаг 14 — SMB media share **Статус: ✅ (2026-05-16)** Samba установлена как часть OMV, но плагин `openmediavault-samba` не используется — конфиг управляется вручную. `/etc/samba/smb.conf` (шара добавлена в конец файла): ```ini [media] path = /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/media comment = Kraken Media browseable = yes read only = yes guest ok = yes force user = kraken ``` `smbd` включён в автозапуск: `sudo systemctl enable smbd` **Подключение с Mac:** Finder → `⌘K` → `smb://kraken` → шара `media` → гостевой доступ. > ⚠️ OMV не управляет smb.conf (плагин не установлен) — правки не слетают при `omv-salt deploy run`. > ⚠️ nmbd не нужен (`disable netbios = yes` в глобальных настройках OMV). --- ## Шаг 10 — Перенос данных ### Фильмы с Mac на NAS ```bash rsync -avh --progress /path/to/movies/ kraken@kraken:/srv/.../media/movies/ ``` ### Time Machine > ⚠️ Старый TM-бэкап перенести нельзя напрямую — TM привязывает бэкап к конкретному диску/хосту. > Начать новый бэкап на NAS, старый HDD хранить как архив или отформатировать после нескольких успешных новых бэкапов. --- ## Hermes агент — ограничения и архитектура > Важно знать при отладке поведения агента. Агент работает **внутри** контейнера `hermes-kraken`. Это означает: | Возможность | Статус | Способ | |---|---|---| | Читать/писать vault | ✅ | `/vault/` через mcpvault MCP | | Писать файлы на хост | ✅ только через alpine+bind `/:/host` | Portainer API | | docker / docker cp | ❌ нет в контейнере | только Portainer API | | SSH на хост | ❌ нет ключей | — | | apt install | ⚠️ слетает при rebuild | не использовать | | Portainer endpoint ID | **3** (не 1!) | проверять: `GET /api/endpoints` | ### Передача файлов на хост — только base64 ```bash # Контент → base64 → Cmd alpine-контейнера → decode на хосте B64=$(printf '%s' 'content' | base64 | tr -d '\n') # Cmd: ["sh", "-c", "echo | base64 -d > /host/path && echo DONE"] # HostConfig.Binds: ["/:/host"] ``` **Никогда не использовать:** echo с кавычками, printf escaping, heredoc — все они ломаются при передаче через Docker Cmd array. ### Токены в Portainer API — не через shell-переменные Hermes маскирует секреты как `***` в terminal output. `$TOKEN` в JSON передаётся буквально. Правильно: интерполировать значение ДО построения JSON (через Python), не в shell-строке curl. ### Правило трёх попыток Если действие не удаётся 3 раза — агент должен остановиться и сообщить пользователю. --- ## Шаг 11 — Hermes агент Кракен **Статус: ✅ запущен (2026-05-12), mcpvault ✅ (2026-05-13)** ### Файлы ``` /home/kraken/hermes/ Dockerfile — образ hermes-kraken:latest docker-compose.yml — restart: unless-stopped, network_mode: host .env — API ключи ``` Конфиги и данные на HDD: ``` /srv/dev-disk-by-uuid-49e8f586.../docker/hermes/config/ config.yaml — основной конфиг Hermes .local/bin/mcpvault — symlink → ../lib/node_modules/@bitbonsai/mcpvault/dist/server.js .local/lib/node_modules/@bitbonsai/mcpvault/ — persistent, не слетает при rebuild ``` ### Toolsets (актуально 2026-05-13) | Toolset | Статус | |---------|--------| | hermes-cli | ✅ | | terminal | ✅ | | file | ✅ | | web (web_search + web_extract) | ✅ Tavily | | browser (Playwright/Chromium) | ✅ (добавлен 2026-05-13) | | memory | ✅ | | spotify | ✅ токен скопирован с Eagle (PKCE, client_secret не нужен) | | cronjob | ✅ | > ⚠️ При сборке Кракена: `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` убран, `npx playwright install --with-deps chromium --only-shell` добавлен в Dockerfile > ⚠️ Spotify — plugin toolset. Нужно: 1) `spotify` в `toolsets:` в config.yaml, 2) `known_plugin_toolsets.telegram: [spotify]` в config.yaml, 3) `auth.json` скопирован с Eagle (содержит refresh_token, PKCE). `client_secret` не нужен. > ⚠️ SOUL.md не должен содержать `curl ... $TOKEN/KEY/SECRET` — Hermes блокирует файл по паттерну `exfil_curl`. Заменять на псевдокод (`# GET /api/...`). ### Модели (актуально 2026-05-13) | Модель | Статус | |--------|--------| | `gemini-2.5-flash` | ✅ primary | | openrouter fallbacks | ✅ | > ⚠️ **Gemini prepaid кредиты исчерпаны (2026-05-14)** — HTTP 429 RESOURCE_EXHAUSTED. Пока не пополнено, Кракен работает на OpenRouter free fallback (не поддерживает vision — изображения из Telegram не обрабатываются). Пополнить: https://aistudio.google.com/projects ### Telegram бот - Имя: Кракен / Bot: [@kraken_htpc_bot](https://t.me/kraken_htpc_bot) ### MCP серверы | Server | Команда | Vault | |--------|---------|-------| | obsidian | `/opt/data/.local/bin/mcpvault /vault` | `/home/kraken/obsidian` → `/vault:rw` | > ⚠️ mcpvault установлен через `npm install -g --prefix /opt/data/.local` — живёт на HDD, переживает rebuild образа > ⚠️ Vault монтируется как `/vault:rw` (не `:ro`!) — иначе mcpvault не может писать заметки > ⚠️ config.yaml: указывать **полный путь** `/opt/data/.local/bin/mcpvault` — PATH в контейнере его не включает > ⚠️ args: `/vault` (путь внутри контейнера), не `/home/kraken/obsidian` ### Деплой / пересборка ```bash # Сборка (осторожно — npm install съедает место на SD!) cd /home/kraken/hermes && docker build -t hermes-kraken:latest . # Если ENOSPC при сборке — сначала почистить build cache: docker builder prune -af # Запуск (docker compose не работает через SSH из-за long-lived process detection) docker stop hermes-kraken && docker rm hermes-kraken docker run -d --name hermes-kraken --restart unless-stopped --network host \ -v /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/hermes/config:/opt/data \ -v /home/kraken/obsidian:/vault:rw \ -e HERMES_UID=1000 -e HERMES_GID=1000 -e HERMES_ALLOW_ROOT_GATEWAY=1 \ --env-file /home/kraken/hermes/.env hermes-kraken:latest # Проверка docker logs hermes-kraken --tail 20 docker inspect hermes-kraken --format 'Status={{.State.Status}} Restarts={{.RestartCount}}' ``` ### TODO - [ ] Настроить HA → создать Long-Lived token → вписать в HASS_TOKEN в .env - [x] ~~Перенести Spotify auth~~ ✅ скопирован с Eagle - [ ] Проверить SD backup cron (ручной запуск ✅ 6.3G/12мин; автозапуск — первое воскресенье 03:00) > Запуск контейнера: `docker run ... hermes-kraken:latest gateway run` — `gateway run` уже в команде, compose не используется. --- ## Шаг 11а — Docker и containerd на HDD **Статус: ✅ (2026-05-13)** SD карта 14GB быстро заполняется Docker образами. Всё перенесено на HDD. ### Docker data-root ```bash # /etc/docker/daemon.json {"data-root": "/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker-data"} ``` ### containerd → symlink на HDD ```bash sudo systemctl stop docker docker.socket containerd sudo rsync -a /var/lib/containerd/ /srv/.../containerd/ sudo mv /var/lib/containerd /var/lib/containerd.bak sudo ln -s /srv/.../containerd /var/lib/containerd sudo systemctl start containerd docker sudo rm -rf /var/lib/containerd.bak ``` ### Build cache (buildkit) — живёт на SD! Buildkit cache НЕ управляется data-root — растёт на SD. Cron очистки: ``` # /etc/cron.d/docker-buildcache-cleanup 0 4 * * * root docker builder prune -af --filter until=24h > /dev/null 2>&1 ``` При ручной сборке перед build: `docker builder prune -af` ### Текущее состояние SD (после всех переносов) - SD: ~22% используется (2.9GB из 14GB), 11GB свободно - HDD: docker-data + containerd + build cache → не мусорят SD --- ## Шаг 12 — Obsidian sync (Eagle ↔ Taiga ↔ Kraken) **Статус: ✅ работает на всех 3 узлах (протестировано 2026-05-13)** Подробная документация: [[obsidian-sync]] **Схема:** ``` Eagle (полный vault ~/obsidian) ──push/pull──┐ Taiga (sparse: personal/ family/) ────────────├── TrueNAS bare repo Kraken (sparse: personal/ family/) ───────────┘ mallexxx.duckdns.org:/mnt/RED_2TB/storage/git/obsidian-vault.git ``` **Скрипты и кроны:** | Узел | Скрипт | Крон | Vault | |------|--------|------|-------| | Eagle | `~/scripts/sync-vault.sh` | `0 * * * *` | `~/obsidian` (full) | | Kraken | `~/scripts/sync-vault.sh` | `0 * * * *` | `~/obsidian` (sparse) | | Taiga | `~/sync-vault.sh` (на хосте!) | Hermes cron `0 * * * *` | `/mnt/RED_2TB/docker/hermes/vault` (sparse) | > ⚠️ Тайга: скрипт запускается на **хосте TrueNAS** (не внутри контейнера) — только truenas_admin имеет ZFS ACL доступ к bare repo. ## Шаг 13 — Vault wiki (llm-wiki / Karpathy approach) Eagle-only: scheduled Hermes job раз в сутки запускает wiki-curation: - Упорядочивает `wiki/` папку по SCHEMA.md - Строит cross-references между страницами - Резолвит git-конфликты вручную (semantic merge) - Lint: orphans, broken links, stale content **TODO:** - [x] ~~Создать `wiki/SCHEMA.md`, `wiki/index.md`, `wiki/log.md`~~ ✅ 2026-05-13 - [x] ~~Добавить cron job на Eagle: ежедневно 02:00, skill `llm-wiki`~~ ✅ 2026-05-13 - [x] ~~Настроить `WIKI_PATH=~/obsidian/wiki` в Eagle `.env`~~ ✅ 2026-05-13 --- ## Уроки (что пошло не так при установке) - **Balena Etcher** не поддерживает OS Customisation — использовать только **RPi Imager** - **`userconf.txt`** deprecated на Bookworm — правильный способ через RPi Imager (он пишет `custom.toml`) - **`systemd.run=` в cmdline.txt** нужно указывать `/usr/lib/raspberrypi-sys-mods/firstboot`, а не свой скрипт - **`ipv4.never-default yes`** при настройке static IP на eth0 — обязательно, иначе интернет идёт через Mac и установка зависает - **OMV install script** при зависании — скорее всего нет интернета, проверить маршруты (`ip route`) --- ## Полезные ссылки - Официальный вики OMV: https://wiki.omv-extras.org/ - Install script: https://github.com/OpenMediaVault-Plugin-Developers/installScript - RPi Imager: https://www.raspberrypi.com/software/ - RPi Downloads: https://www.raspberrypi.com/software/operating-systems/