Files
obsidian-vault/family/how-to/truenas-infrastructure.md
T

113 KiB
Raw Blame History

TrueNAS — инфраструктура

ДОМАШНЯЯ АВТОМАТИЗАЦИЯ ПЕРЕНЕСЕНА НА HP t610 (2026-09-14). HA, zigbee2mqtt, mosquitto, mbusd, modbus-bridge и flows Node-RED переехали на t610 (HA OS, 192.168.2.176). Единый документ по t610 — family/how-to/home-automation. TrueNAS-стек автоматизации ПОГАШЕН 2026-09-14 (ночная сессия, §5-кватер-Л плана): homeassistant, mbusd, mosquitto, nodered, zigbee2mqtt, modbus-bridge, ser2netdocker stop + docker update --restart=no (НЕ удалены, папки docker/* целы — откат = docker start + --restart=unless-stopped). Проверено: порты 502/1883/8123/1880 свободны, mallexxx.* = 200, MQTT на t610 живой. Причина переноса: TrueNAS на пределе RAM (17/21 ГБ).

2026-09-14 (вечер-2, обновлено вечер-13) — Caddy ПЕРЕКЛЮЧЁН, Node-RED ПЕРЕНЕСЁН:

  • Caddy НЕ переносился и не будет: 17 из 20 доменов *.mallexxx.duckdns.org — сервисы самого TrueNAS (immich, gitea, jellyfin, radarr, webdav, transmission, portainer…). Перенос Caddy на t610 положил бы их при падении t610. ПРАВКА ЗАВЕРШЕНА (факт-проверка 2026-09-14 вечер-13): в Caddyfile остался ОДИН upstream на t610 — mallexxx.duckdns.org192.168.2.176:80 (HA, HTTP 200 ). УБРАНЫ совсем: cam.mallexxx.duckdns.org (камера на t610 по RTSP — домен не нужен) и nodered.mallexxx.duckdns.org (Node-RED — через ingress HA, решение Alex «оставляем так»). Caddyfile: /mnt/RED_2TB/docker/caddy/Caddyfile (root-owned — агент только стейджит в /tmp/, подменяет Alex), бэкап Caddyfile.bak-20260914. Порты контейнера: 8088:80, 8443:443; DNAT на роутере 192.168.2.2: wan:80→192.168.2.197:8088, wan:443→192.168.2.197:8443.
  • Node-RED flows перенесены на t610 (/addon_configs/a0d7b954_nodered/flows.json, 68 узлов, узел serveraddon: true). Наружу НЕ выпущен (порт-маппинг при host_network: true глушится, снимается только в UI) — доступ через ingress HA. Node-RED в докере TrueNAS (/mnt/RED_2TB/docker/nodered/) ПОГАШЕН 2026-09-14 (stop + --restart=no; папка цела, откат = docker start nodered + --restart=unless-stopped).
  • 🔴 Важно про доступ к HA извне: /config/.storage/http на t610 требовал trusted_proxies += 192.168.2.197/32, иначе Caddy с другого хоста даёт 400 (HA use_x_forwarded_for: true). Обобщение: IP любого внешнего reverse-proxy обязан быть в trusted_proxies. 2026-09-14 (вечер-3) — ZONT MQTT ПЕРЕНАПРАВЛЕН НА t610:
  • DNAT на роутере 192.168.2.2: firewall.@redirect[0] (name MQTT) и firewall.@rule[3] (name allow-1883) — dest_ip 192.168.2.197192.168.2.176. uci commit firewall + /etc/init.d/firewall reload. Бэкап: /root/firewall.bak-20260914-092555.
  • Результат: ZONT пишет в mosquitto-аддон на t610 (живой поток modbus/sensors/kids/*, bedroom/*). В настройках ZONT ничего не менялось (mqtt://…@192.168.0.10:1883, где .0.10 = wan-интерфейс роутера 192.168.2.2, не отдельный GPON-роутер).
  • dining/* тоже публикуется (2026-09-14, позже): прежняя версия «ZONT не публикует / мёртвый upstream» — ОПРОВЕРГНУТА. Причина была в баге сборки RTU-кадров в modbus-bridge (19-байтный кадр гостиной рвался), фикс 3748feb → все 7 полей dining живы. Подробно — family/how-to/home-automation §5-кватер-З.
  • ⚠️ «Камера на TrueNAS» — ИСПРАВЛЕНО (2026-09-14, вечер-10) + РЕШЕНО ОКОНЧАТЕЛЬНО (вечер-13): прежняя запись «камера = USB-вебка на t610, upstream cam.*:8090 к камере отношения не имеет» — НЕВЕРНА. Поиск в Caddyfile.bak доказал: cam.mallexxx.duckdns.org → 192.168.2.197:8090 — ЭТО И БЫЛА камера на TrueNAS: отдельный HTTP-MJPEG-сервис (ustreamer/mjpg-streamer, порт 8090 — канон для «USB-вебка → MJPEG»). Контейнер УТРАЧЕН при пересоздании пула (локальный образ не пережил .ix-apps; из живого Caddyfile строка удалена — cam.* больше нет). ФИНАЛ (вечер-13): вебка 046d:0825 физически в t610, работает через аддон a889bffc_go2rtc-hardware → RTSP H.264 rtsp://192.168.2.176:8554/usb_camera_h264Generic Camera camera.192_168_2_176 (зона kotelnaia, unique_id, WebRTC работает, поворот #rotate=90). Схема camera: platform: ffmpeg в Core — ОТВЕРГНУТА (Resource busy + нет unique_id). Подробно — family/how-to/home-automation §5-кватер-И-3/И-6.
  • Не перенесено с TrueNAS: погашение TrueNAS-стека (Этап 4 п.6 — заблокировано: Caddy на TrueNAS держит точку входа) ЗАКРЫТО 2026-09-14 (ночь): стек автоматизации ПОГАШЕН, Caddy остался на TrueNAS (так и задумано). См. §5-кватер-Л в family/how-to/home-automation.

Обновлено: 2026-09-15 (ВЕЧЕР — vless-space СОЗДАН И ЗАЛИТ, xui_v7.db применена успешно. Проверено фактом: in-10095-tcp clients = user1,kraken-user,vless-space одной строкой (без дубля, без порта 10096), outbounds 13, подписка /sub/24df9391356b48ff HTTP 200 — QR появился впервые за 7 попыток, kraken-user и user1 не пострадали. 🔴 ЭТО ОПРОВЕРГАЕТ прежний хард-вывод «3x-ui нельзя править снаружи». Настоящий барьер был один — инбаунд внутри xrayTemplateConfig; как только в шаблоне остаётся только api, SQLite-путь работает штатно. ⚠️ Остаточная проблема (не в клиенте): egress vless-space не идётapp/dispatcher: non existing outTag: space-balancer, туннель рвётся websocket: close 1000. 🔴🔴 КОРЕНЬ НАЙДЕН И ДОКАЗАН A/B: leastPing НЕ РАБОТАЕТ в Xray 26.x — балансировщик не регистрируется; рабочая стратегия — leastLoad (с observatory): лог даёт app/observatory: the outbound space-01 is alive:0.249334909 + taking detour [space-02]. Собран xui_v7_load.db (md5 855ff3ac2d2319b17b20fe5c788ddc59, leastPingleastLoad, integrity ok) — залит не был, это следующий шаг. ⚠️ xray -test печатает Configuration OK и для битого leastPing — семантику маршрутизации ловит только рантайм-лог. Команды для Alex: плоские однострочники, без ssh … '…'-обёртки, без sleep N, без кириллицы в bash. Compose-файл xray-admin ВОССТАНОВЛЕН из docker inspect. Полный разбор — personal/tech/vless-space-subscription-egress / personal/tech/xray-outbound-subscription-3xui.

Обновлено (ранее): 2026-09-15 (ФИНАЛ попытки 7: vless-space НЕ СОЗДАН, БД ОТКАЧЕНА Alex'ом, система в исходном состоянии — проверено: контейнер Up, панель/vpn.mallexxx/обе подписки HTTP 200, клиенты user1+kraken-user, outbound'ов 3). Главный вывод: 3x-ui НЕЛЬЗЯ править снаружи работающего контейнера. Семь подходов (SQL в копию БД, прямой SQL, auth/reverse, security, password, инбаунд-в-шаблоне, шаблон-без-инбаунда) — все отбились, при том что БД каждый раз была полностью корректна (integrity ok, типы совпадают, шаблон валиден, живой Xray давал Configuration OK). Работает только settings.xrayTemplateConfig (outbound'ы/правила/балансировщики — 13 outbound + space-balancer leastPing применились), клиенты инбаунда — только через панель/API-токен. 🔴 ХАРД-ВЫВОД: не тратить попытки на правку клиентов 3x-ui через SQLite — сразу просить доступ к панели. 🔴 НОВЫЕ ПИТФОЛЛЫ: (1) правку SQLite делать ЛОКАЛЬНО на Mac (scp базы → sqlite3/jq/integrity_check → валидация живым xray -test → заливка готового файла) — установка Alex, гонка кавычек по SSH дважды ломала команды; (2) команды для Alex давать без ssh truenas_admin@… '…'-обёртки и без sleep N (Alex, 2026-09-15: «ты заебал свой sleep 8 пихать»); (3) 3x-ui держит БД открытой — при внешней правке x-ui.db показывает старую дату; (4) 🔴 инбаунд ВНУТРИ xrayTemplateConfig ломает своих клиентов — 3x-ui мёржит шаблон с таблицей inbounds, шаблонная версия того же тега перебивает панельную (так отвалился kraken-user); в шаблоне — только outbound'ы/правила/балансировщик. Compose-файл xray-admin ВОССТАНОВЛЕН из docker inspect (это единственное, что пережило откат). Полный разбор — personal/tech/vless-space-subscription-egress. Ранее 2026-09-15 (ночь-4: попытка 2 — SQL применён, БД корректна, но Xray клиента не видит; ложный «корень» auth/reverse=NULLопровергнут; ранее ночь-3: попытка 1 провалилась с database disk image is malformed — SQL применялся к копии .db без -wal/-shm. 🔴 ПИТФОЛЛ: для WAL-базы нельзя копировать только .db. Ранее ночь-2: артефакты собраны и проверены в песочнице. Ранее 2026-09-15 (вечер: черновой план vless-space, подписка проверена; subscription-канал 3x-ui: ссылки /sub/<subId> работают, base64 vless-список). Ранее: 2026-09-02 (vpn.mallexxx:443 = РАБОЧИЙ Xray... [truncated] — провенено: контейнер Up, панель/vpn.mallexxx/обе подписки HTTP 200, клиенты user1+kraken-user, outbound'ов 3). Главный вывод: 3x-ui НЕЛЬЗЯ править снаружи работающего контейнера. Пять подходов (SQL в копию БД, прямой SQL, auth/reverse, security, password) — все отбились, при том что БД каждый раз была полностью корректна (integrity ok, типы совпадают, шаблон валиден, живой Xray давал Configuration OK). Работает только settings.xrayTemplateConfig (outbound'ы/правила/балансировщики — 13 outbound + space-balancer leastPing применились), клиенты инбаунда — только через панель/API-токен. 🔴 ХАРД-ВЫВОД: не тратить попытки на правку клиентов 3x-ui через SQLite — сразу просить доступ к панели. 🔴 НОВЫЕ ПИТФОЛЛЫ: (1) правку SQLite делать ЛОКАЛЬНО на Mac (scp базы → sqlite3/jq/integrity_check → валидация живым xray -test → заливка готового файла) — установка Alex, гонка кавычек по SSH дважды ломала команды; (2) команды для Alex давать без ssh truenas_admin@… '…'-обёртки; (3) 3x-ui держит БД открытой — при внешней правке x-ui.db показывает старую дату. Compose-файл xray-admin ВОССТАНОВЛЕН из docker inspect (это единственное, что пережило откат). Полный разбор — personal/tech/vless-space-subscription-egress. Ранее 2026-09-15 (ночь-4: попытка 2 — SQL применён, БД корректна, но Xray клиента не видит; ложный «корень» auth/reverse=NULLопровергнут; ранее ночь-3: попытка 1 провалилась с database disk image is malformed — SQL применялся к копии .db без -wal/-shm. 🔴 ПИТФОЛЛ: для WAL-базы нельзя копировать только .db. Ранее ночь-2: артефакты собраны и проверены в песочнице. Ранее 2026-09-15 (вечер: черновой план vless-space, подписка проверена; subscription-канал 3x-ui: ссылки /sub/<subId> работают, base64 vless-список). Ранее: 2026-09-02 (vpn.mallexxx:443 = РАБОЧИЙ Xray-сервер, проверено end-to-end; vless-proxy outbound мёртв)

⚠️ ПРИОРИТЕТ 2026-09-01: VPS qentra.top УДАЛЁН → vless-proxy и сетевые туннели сломаны

  • VPS 91.207.28.205 больше НЕ существует (вся его Xray/OpenVPN/WG-инфраструктура утрачена). Подробно: family/how-to/vps-qentra.
  • Контейнер vless-proxy (teddysun/xray): inbound SOCKS 0.0.0.0:1080 + HTTP 0.0.0.0:1081, но outbound ⇒ мёртвый v.qentra.top:443 (VLESS+WS+TLS, path /qentra, id 2D9F24C4-21FE-4784-9843-F11C384DA67A). ⇒ Hermes-Taiga (ходит через vless-proxy:1080) сейчас БЕЗ рабочего прокси. Уточнено 2026-09-02: v.qentra.top по-прежнему ресолвится, но в Cloudflare IP (104.21.54.239, 2606:4700:...) — DNS-запись на qentra.top осталась в Cloudflare, хотя VPS сам удалён; origin'а за ней нет, поэтому трафик через прокси не идёт. Контейнер vless-proxy сам ЖИВ (Up 8 days), путь через его SOCKS наружу не проходит.
  • ⚠️ На корневом mallexxx.duckdns.org:443 НЕ Xray, а обычный Caddy/nginx с валидным Let's Encrypt сертификатом (проверено openssl s_client 2026-09-01). НО на поддомене vpn.mallexxx.duckdns.org:443 — РАБОЧИЙ Xray-сервер (см. раздел xray-admin ниже, проверено end-to-end 2026-09-02).
  • Наружу открыты только 22 (SSH) и 443 (HTTPS/TLS) с Kraken; 8443/8964/8080/9000 closed.
  • План замены (выход клиентов сети TrueNAS через Kraken, Xray reverse — НЕ внедрён): personal/tech/xray-reverse-tunnel-kraken-truenas.

СТАТУС на 2026-08-25: пул ONLINE, docker поднят, почти все контейнеры Up

Пул RED_2TB пересоздан (2026-08-21) и работает: zpool status ONLINE, rsync возврата данных завершён, /mnt/RED_2TB/ смонтирован. Docker: ПОДНЯТ на 2026-08-25. Почти все контейнеры Up (zigbee2mqtt, webdav, vless-proxy, homeassistant, caddy, transmission, syncthing, mosquitto, nodered, immich*, gitea, filebrowser, portainer*, hermes-taiga и др.). cups-splix поднят 2026-08-26 — образ собран заново (docker build -t cups-splix .), контейнер запущен docker compose up -d, порт 631 открыт, принтер Samsung_CLX-216x_Series активен (USB 04e8:3425). Причина былого падения: образ локальный, потерян при восстановлении пула (.ix-apps не переносился), вручную не пересобирали. Рецепт — ниже, раздел «Печать / cups-splix». Ещё не подняты (проверить при надобности): inpxer/inpx-web/arr/ser2net. ⚠️ ИСТОРИЧЕСКАЯ проблема modbus-bridge/mbusd — гонка с udev при рестарте TrueNAS ( БОЛЬШЕ НЕАКТУАЛЬНА):

  • После перезагрузки docker стартует раньше udev, поэтому /dev/ttyZONT и /dev/ttyVent на момент старта контейнеров ещё не существуют.
  • НЕАКТУАЛЬНО с 2026-09-14: USB-адаптеры (CH340 ZONT/вентиляция) физически перенесены на t610 → на TrueNAS узлов /dev/ttyZONT / /dev/ttyVent нет вообще, а сами контейнеры mbusd, modbus-bridge, ser2net погашены (stop + --restart=no). Проверка: ls /dev/ttyUSB* → пусто; /sys/bus/usb/devices содержит только принтер Samsung 04e8:3425 (lsusb на TrueNAS не установлен — использовать /sys/bus/usb/devices).
  • Актуальная гонка udev живёт на t610 — см. family/how-to/zont-modbus-bridge-udev-race-protection.
  • ⚠️ Историческая справка (если когда-нибудь откатывать): restart: unless-stopped НЕ перезапускает контейнер, упавший на start из-за отсутствующего device-узла (отказ до старта процесса, ExitCode 128/255, RestartCount=0); лечилось ручным docker start modbus-bridge mbusd после готовности симлинков. ⚠️ ДРУГОЕ (открытое): пул DEST (IronWolf) на 2026-08-24 DEGRADED — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по 192.168.2.197 нестабилен — использовать mallexxx.duckdns.org.

🔒 ИСТОРИЯ: статус до восстановления (2026-08-24)

Пул RED_2TB пересоздан и УЖЕ зареган в TrueNASzpool status ONLINE (mirror-0{sdc,sdf}+mirror-1{sde,sdd}), midclt call pool.query id=1 RED_2TB ONLINE. rsync возврата данных ЗАВЕРШЁН (storage 3.29T, immich 353G, backup 287G, Edu 214G, Photos 146G, old-bu 65G, docker, docker.bak, system — все смонтированы). .ix-apps датасет (docker storage, был 24G) НЕ перенесён — rsync шёл из /mnt/RED_2TB/* и не включал монтируемый в /mnt/.ix-apps системный датасет. Образы = кеш → перекачаются из registry сами; конфиги целы в /mnt/RED_2TB/docker/<app>. Контейнеры запускались через docker-compose, НЕ через TrueNAS Apps (TrueCharts/Custom App). daemon.json data-root:/mnt/.ix-apps/docker. .ix-apps = просто data-root docker, не TrueNAS Apps. ⚠️ ДРУГОЕ (проверено 2026-08-24): пул DEST (IronWolf, источник спасения) на момент проверки DEGRADED в zpool list — стоит разобраться, почему (вероятно отвалился mirror-член). Также SSH с Mac к TrueNAS по 192.168.2.197 нестабилен (Connection reset/reset by peer, kex_exchange_identification read), возможен конфликт сессий при активном входе на консоль — использовать mallexxx.duckdns.org и ретраи.

⚠️ СТАТУС на 2026-08-21: пул RED_2TB — данные СПАСЕНЫ, пул OFFLINE, пересоздаём

Выгрузка успешно завершена (подтверждено Alex): данные RED_2TB (4.56T) на IronWolf (пул DEST, /mnt/IRONWOLF). Пул RED_2TB — статус OFFLINE в БД TrueNAS, НЕ импортирован. Конфиги docker (caddy, transmission, HA, immich и т.д.), Obsidian vault и git-репо спасены на /mnt/IRONWOLF (system/, docker.bak/, docker/, storage/obsidian, storage/git). ПЛАН (следующий шаг): пересоздать пул RED_2TB с новой топологией mirror {sdc,sdf} + mirror {sde,sdd} (включаем WD2TB#2 зеркалом к WD2TB#1). Команды zpool labelclear + zpool create — в family/how-to/truenas-sata-ports-and-zfs-pools.md (раздел «Пересоздание пула 2026-08-21»). Затем вернуть данные rsync с IronWolf и восстановить инфраструктуру. ПРОТОКОЛ ПОВРЕЖДЕНИЯ (история): пул паниковал на rw-импорте (adding existent segment to range tree, повреждённая space map). Работал только zpool import -o readonly=on. In-place починки нет (mav/iXsystems) — только спасать данные и пересоздавать. Полный рецепт — в family/how-to/truenas-sata-ports-and-zfs-pools.md.

Доступ

  • Host (external): mallexxx.duckdns.org (DuckDNS) — единственный способ SSH/API из 192.168.1.x
  • SSH: truenas_admin@mallexxx.duckdns.org -i ~/.ssh/id_rsa
  • Web UI: http://truenas.mallexxx.duckdns.org
  • Portainer: https://portainer.mallexxx.duckdns.org
  • Host (local network): 192.168.2.197⚠️ ИСПОЛЬЗОВАТЬ ssh truenas_admin@mallexxx.duckdns.org. НЕ ИСПОЛЬЗОВАТЬ локальный IP для SSH доступа!
    • ⚠️ Eagle (Mac, 192.168.1.x) и Kraken (192.168.1.15) находятся в другой подсети
    • ⚠️ Кра́кен и TrueNAS — разные сети (192.168.1.x vs 192.168.2.x). Доступ с Кракена на TrueNAS по локальному IP не работает

⚠️ Измеренный потолок канала Mac/ТВ (192.168.1.x) → TrueNAS (192.168.2.x) — 2026-09-02: ⚠️ Измеренный потолок канала Mac/ТВ (192.168.1.x) → TrueNAS (192.168.2.x) — 2026-09-02, ПЕРЕСМОТРЕНО:
Между этими двумя сетями нет LAN — только обход через внешку провайдеров (ТТК дом A ↔ Ростелеком дом B). Замерено:

  • Single TCP flow ≈ 28 Мбит/с, но 4 параллельных потока ≈ 51 Мбит/с (агрегат РАСТЁТ с параллельностью) → это per-TCP-flow / BDP-штраф за ~104 мс RTT, а НЕ лимит линии TrueNAS.
  • ⚠️ ПОЗДНЕЙШИЙ ЗАМЕР С САМОГО NAS ОПРОВЕРГ раннюю запись «ап-линия TrueNAS ~30 Мбит/с»: NAS → Cloudflare даёт ~184 Мбит/с down / ~117 Мбит/с up (curl https://speed.cloudflare.com/__down?bytes=50000000 и POST __up). ovh/tele2 speedtest из RU заблокированы — юзать Cloudflare-эндпоинты.
  • ~104 мс RTT, из них ~50 мс на одном межоператорском хопе 194.186.168.65 (TTK 3–6 мс → прыжок до ~54 мс). Per-hop loss: моя ISP-грань чиста (0%, 3 мс); дальние хопы дают спорадич. LOSS (ICMP-деприоритизация, не устойчивые потери). Re-route 104мс полностью не уберёт (пиринг/география).
  • Следствие: высокобитрейтный медиа-плейбек (720p BluRay и выше) через jellyfin на этом пути тормозит/грузится кусками (HLS одним TCP + 104мс RTT, single-flow ~2851 Мбит впритык к пикам файла). НЕ транскодинг (direct-play). Jellyfin не умеет мультистримить один плейбек.
  • Пересмотренный разбор + команды: family/how-to/arr-stack-taiga.md → «Плейбек по сети → per-TCP-flow/BDP». Решения: дать локальный маршрут (если TrueNAS в одном здании/роутере), ограничить jellyfin-битрейт < ~20 Мбит, или прокси с мульти-TCP-загрузкой файла, или WireGuard-туннель через VPS.

Пользователи и группы (ключевые)

uid Имя gid Назначение
950 truenas_admin 950 SSH-пользователь, управление docker
911 transdamon 911 Процесс Transmission внутри контейнера
921 transmission 921 Старый пользователь (не используется контейнером)
3000 nas_users 3000 Общая группа доступа к NAS

Структура папок

/mnt/RED_2TB/
├── docker/          ← конфиги docker-контейнеров (бэкапятся → mailru-crypt:)
│   ├── caddy/
│   ├── filebrowser/
│   ├── ha/          ← Home Assistant
│   ├── hermes/      ← Hermes-Taiga
│   ├── homeassistant/
│   ├── immich/
│   ├── inpx-web/
│   ├── inpxer/
│   ├── mbusd/
│   ├── modbus-bridge/
│   ├── mosquitto/
│   ├── nodered/
│   ├── portainer/
│   ├── python/
│   ├── rclone/
│   ├── ser2net/
│   ├── transmission/ ← конфиг Transmission (settings.json, torrents, resume...)
│   ├── vless-proxy/
│   ├── watchtower/
│   ├── webdav/
│   └── zigbee2mqtt/
├── storage/
│   ├── Downloads/   ← данные торрентов (монтируется в контейнер как /mnt/storage)
│   │   ├── transmission/ ← старый путь конфига (больше не используется)
│   │   └── [медиафайлы]
│   └── obsidian/    ← vault (read-only для hermes-taiga)
├── backup/          ← ручные бэкапы (бэкапятся → mailru-crypt:)
│   └── transmission-config/ ← снапшот конфига от 2026-04-30
├── Photos/          ← фото (бэкапятся → mailru:Photos/Photos)
├── old-bu/          ← старый архив (бэкапятся → mailru:Photos/old-bu)
└── immich-photos-upload/ ← библиотека Immich (бэкапятся → mailru:Photos/immich)

NFSv4 ACL — важно

TrueNAS использует NFSv4 ACL, а не стандартный POSIX chmod/chown.

  • ls -la показывает ---------- даже если ACL есть → всегда проверять через midclt call filesystem.getacl <path>
  • Добавить запись: midclt call filesystem.setacl '{...}'
  • truenas_admin не имеет passwordless sudo → root-операции только через midclt или TrueNAS UI

Docker-контейнеры

Контейнер Image Порт Домен
transmission linuxserver/transmission:latest 9091, 51413 transmission.mallexxx.duckdns.org
hermes-taiga hermes-taiga:latest
vless-proxy teddysun/xray:latest
filebrowser filebrowser/filebrowser:latest
webdav hacdias/webdav:latest webdav.mallexxx.duckdns.org
homeassistant home-assistant:stable 8123 ПОГАШЕН 2026-09-14 — переехал на t610
immich-server immich-app/immich-server:release 2283 immich.mallexxx.duckdns.org
immich-postgres tensorchord/pgvecto-rs:pg14-v0.2.0
immich-redis redis:7
nodered nodered/node-red:latest 1880 ПОГАШЕН 2026-09-14 — flows на t610 (ingress)
mosquitto eclipse-mosquitto:latest 1883 ПОГАШЕН 2026-09-14 — брокер на t610
caddy caddy:latest 80, 443 reverse proxy для всего
rclone rclone/rclone:latest бэкап по cron
portainer portainer/portainer-ce:latest 9000 portainer.mallexxx.duckdns.org
watchtower containrrr/watchtower:latest авто-обновление образов
inpxer ghcr.io/hedger/inpxer:latest 18080 books.mallexxx.duckdns.org
zigbee2mqtt koenkk/zigbee2mqtt:latest — (переехал на t610)
mbusd 3cky/mbusd:latest 502 Modbus (переехал на t610)
modbus-bridge modbus-bridge — (переехал на t610)
ser2net ghcr.io/jippi/docker-ser2net 502 ПОГАШЕН 2026-09-14 — spare-master, конфликт порта с mbusd
cups-splix cups-splix 631 принтер
xray-admin ghcr.io/mhsanaei/3x-ui:latest 2053 (панель), 10095 (vless-ws), 443 (sub) vpn-panel.mallexxx.duckdns.org, vpn.mallexxx.duckdns.org

🔴 xray-admin: compose-файл УТРАЧЕН (обнаружено 2026-09-15). В /mnt/RED_2TB/docker/xray-admin/ лежат только x-ui.db, -shm, -wal, system_metrics.gob. Docker label указывает на docker-compose.yml, но файла нет. Причина (найдено через Zulip DB, personal/zulip router issues, id=86681): 2026-09-01 05:40:08 UTC агент выполнил docker exec xray-admin rm -f /etc/x-ui/docker-compose.yml — volume смонтирован как /etc/x-ui (bind-mount), поэтому rm внутри контейнера снёс файл на хосте, через 1,5 минуты после создания. Пересоздать контейнер из папки сейчас НЕЛЬЗЯ — только из docker inspect. Подробно и параметры для восстановления: family/plans/reverse-xray-3xui-kraken. Проверить перед любым docker compose по этому сервису. | xray-reverse-portal | teddysun/xray:latest | 12345 (SOCKS), 12346 (VLESS-TCP REALITY interconn) | — (см. personal/tech/xray-reverse-tunnel-kraken-truenas.md) |

cups-splix — принтер Samsung CLX-216x ( поднят 2026-08-26; mDNS-фикс 2026-08-31 завершён)

Статус: контейнер работает, принтер Samsung_CLX-216x_Series idle / enabled / accepting. CUPS слушает 0.0.0.0:631 (host-сеть). mDNS-анонс включён — штатная Android print service теперь видит принтер по mDNS (подробно: mac-print-shared-services). См. ниже раздел « mDNS/AirPrint анонс принтера».

Папка: /mnt/RED_2TB/docker/cups/Dockerfile, entrypoint.sh, docker-compose.yml, data//etc/cups, cache//var/cache/cups, spool//var/spool/cups, uld/, бэкап backup_20260831-003619.tar.gz.

  • Image: cups-splix (локальная сборка из Dockerfile; старый образ сохранён как cups-splix-old для отката)
  • Dockerfile (debian:12-slim): cups-daemon cups-client cups-common printer-driver-splix avahi-daemon avahi-utils dbus usbutils nano procps; cupsadmin:admin (группа lpadmin); COPY entrypoint.sh; EXPOSE 631; ENTRYPOINT ["/entrypoint.sh"]
  • entrypoint.sh: dbus-daemon --system --forkavahi-daemon --no-drop-root --syslog (фон) → exec cupsd -f
  • compose: image: cups-splix, network_mode: host, privileged: true, volume /dev/bus/usb:/dev/bus/usb, restart unless-stopped (содержит устаревший command: [cupsd -f], но ENTRYPOINT переопределяет — правится только через root/UI, файл 600 root)
  • Сборка/поднятие (⚠️ полное пересоздание, НЕ docker restart):
cd /mnt/RED_2TB/docker/cups/
docker build -t cups-splix-new .
docker stop cups-splix && docker rm cups-splix
docker tag cups-splix-new cups-splix && docker tag cups-splix cups-splix-old 2>/dev/null
docker compose up -d

Полный разбор и симптом «телефон не видит принтер»: mac-print-shared-services

Инвентарь compose-файлов по папкам (проверено 2026-08-24)

Каждый контейнер = своя папка /mnt/RED_2TB/docker/<app>/. Модель — не один общий compose, а per-service compose (контейнеры поднимались docker compose up -d из своей папки / docker run).

Есть docker-compose.yml (поднимаются docker compose -f ... up -d) — 22 шт: arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, mbusd, mosquitto, nodered, portainer-mcp, portainer, rclone, ser2net, syncthing, transmission, vless-proxy, watchtower, xray-admin (3x-ui, добавлен 2026-09-01)

🔴 ВАЖНО (2026-09-14): mbusd, mosquitto, nodered, ser2net погашены — поднимать их обратно НЕ НАДО (переехали на t610). Остальные — активны.

⚠️ НЕТ compose-файла — только конфиг (восстанавливать вручную, параметры из доки ниже):

  • ha — Home Assistant: /mnt/RED_2TB/docker/ha/ (automations.yaml)🔴 ПОГАШЕН 2026-09-14. Папка сохранена как ЭТАЛОН конфига (configuration.yaml, modbus-блок построчно идентичен t610, 32 заслонки) — не удалять.
  • webdav/mnt/RED_2TB/docker/webdav/ (config.yml). Образ hacdias/webdav:latest, домен webdav.mallexxx.duckdns.org. активен (compose на самом деле есть, см. строку выше).
  • modbus-bridge/mnt/RED_2TB/docker/modbus-bridge/🔴 ПОГАШЕН 2026-09-14 (Exited (0) с 14.09 01:59 — узел /dev/ttyZONT исчез). Папка цела.
  • zigbee2mqtt/mnt/RED_2TB/docker/zigbee2mqtt/🔴 ПОГАШЕН 2026-09-14 (Exited (2) — координатор на t610).
  • homeassistant — папка docker/homeassistant/ПУСТАЯ и не использовалась; рабочая была ha/ (см. выше).

Порядок восстановления docker-стека (зависимости)

  1. docker engine: systemctl enable --now docker (после создания data-root, см. шапку). Проверка: docker info | grep -iE "Server Version|Docker Root Dir".
  2. Инфраструктура/сеть: mosquitto (MQTT) → zigbee2mqtt (нужен mosquitto) → nodered (MQTT)🔴 все три ПОГАШЕНЫ 2026-09-14, на TrueNAS НЕ ВОССТАНАВЛИВАТЬ (живут на t610). Остаётся: caddy (прокси, тянет все домены) → vless-proxy (SOCKS5 для hermes).
  3. Умный дом: на TrueNAS БОЛЬШЕ НЕ ВОССТАНАВЛИВАТЬ — переехало на t610 (см. «Декомиссия стека автоматизации»), стек ПОГАШЕН 2026-09-14. mbusd (Modbus TCP:502) → modbus-bridge (через mbusd) → ha (homeassistant, нужен caddy для домена) — всё это теперь аддоны на 192.168.2.176.
  4. Медиа/хранилище: transmission (нужен caddy) → arr (radarr/sonarr/prowlarr) → inpxer (books), inpx-web, library → rclone, syncthing, filebrowser, webdav, gitea. ⚠️ inpxer/inpx-web — на 2026-09-14 в циклическом краше (НЕ трогать по указанию Alex); library — погашен 2026-09-14 (см. декомиссию).
  5. Сервисы/свои: hermes-taiga (нужен vless-proxy), portainer, portainer-mcp, watchtower, cups. ser2netпогашен 2026-09-14 (конфликт порта 502 с mbusd).
  6. Проверка: docker ps. HA (если когда-нибудь поднимать обратно): docker exec homeassistant python -m homeassistant --script check_config --config /config — но 🔴 контейнер погашен, живая HA = аддон на t610 192.168.2.176.

Декомиссия стека автоматизации TrueNAS (2026-09-14) — КАНОН

Погашено 7 контейнеров (docker stop + docker update --restart=no, НЕ удалены):

homeassistant, mbusd, mosquitto, nodered, zigbee2mqtt, modbus-bridge, ser2net

  • Почему: всё это работает на t610 (HA OS, 192.168.2.176) как HA-аддоны; на TrueNAS ресурсы дублировались впустую, а mbusd/modbus-bridge/zigbee2mqtt вообще были мертвы (USB-адаптеры переехали физически).
  • Папки /mnt/RED_2TB/docker/* ЦЕЛЫ. Откат: docker start <name> + docker update --restart=unless-stopped <name>.
  • rm НЕ делали — удаление отдельным шагом, не раньше чем через 2–3 дня стабильной работы.
  • Секрет: HA_TOKEN лежит открытым текстом в /mnt/RED_2TB/docker/modbus-bridge/docker-compose.ymlenvironment (там же MQTT_PASS: mqtt1z3$) — кандидат на .env + ротацию. Папку не трогать/не публиковать до ротации.
  • Полный разбор — §5-кватер-Л в family/how-to/home-automation.

⚠️ Минные поля, найденные при аудите (НЕ трогались, отдельное решение Alex):

Контейнер Проблема
library Restarting циклически, RestartCount=29752 ПОГАШЕН 2026-09-14 (по команде Alex): docker stop library + docker update --restart=nostate=exited, restart=no. Caddy-домен library.mallexxx.duckdns.orgмёртв (и был мёртв до гашения). Не удалён, папка цела. Открыто: почему падал (image: library-app:latest из build: . — локальная сборка; тот же паттерн, что утерянные cups-splix/камера при пересоздании пула)
inpx-web / inpxer оба Exited (1), RestartCount=13; books.mallexxx.duckdns.org:18080 (мёртвый inpxer). По указанию Alex НЕ трогать

Диагностические питфоллы TrueNAS (проверено 2026-09-14):

  • ⚠️ curl http://192.168.2.176:8123HTTP 000 — ЭТО НОРМА. HA на t610 живёт за Caddy; её :8123 закрыт, доступ = :80 / mallexxx.duckdns.org. Не принимать за поломку.
  • lsusb на TrueNAS НЕ установлен → USB-устройства смотреть через /sys/bus/usb/devices/ (product, manufacturer, idVendor/idProduct).
  • midclt call app.query[] (TrueNAS Apps не используются), /mnt/.ix-apps/app_configs пуст. Всё — per-service compose из своей папки, Portainer stacks не используются.
  • sudo на TrueNAS требует пароль (passwordless нет) — root-операции только через root-SSH/Shell.
  • Кто чем управляется: docker inspect <name> --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}'.

Transmission — детали

  • Config: /mnt/RED_2TB/docker/transmission/ (монтируется как /config; внутри /config/docker-compose.yml)
  • Данные: /mnt/RED_2TB/storage (монтируется как /mnt/storage)
  • Download dir: /mnt/storage/Downloads
  • UID/GID: ⚠️ по факту работает как ROOT (uid 0), НЕ 911/911. Причина: в /mnt/RED_2TB/docker/transmission/docker-compose.yml НЕ задан PUID/PGID → linuxserver /init (s6-overlay) оставляет контейнер root (подтверждено docker exec transmission id → root). Пользователь transdamon/911 (док) — это владелец конфига на хосте (drwx------ 911 911), но НЕ процесс внутри контейнера.
    • Зачем важно: root-трансмишен пишет файлы как root и переживает права 0000 медиа → это причина, почему он "работает" на сломанных после restore папках. Но для pipeline с jellyfin/radarr (не-root) root-создаваемые файлы барьер.
    • План фикса (Вариант A, одобрен 2026-09-02): добавить PUID=950 PGID=950 и пересоздать контейнер → работает под truenas_admin. План: family/documents/vault-sync/2026-09-02-restore-privilege-scope.md §5.
  • RPC whitelist: 172.16.6.*
  • Web: https://transmission.mallexxx.duckdns.org
  • Порты: 9091 (RPC/web), 51413 (TCP/UDP peers)

Caddy — домены

Домен
mallexxx.duckdns.org HA на t610 192.168.2.176:80 (2026-09-14)
transmission.mallexxx.duckdns.org Transmission :9091
immich.mallexxx.duckdns.org Immich :2283
nodered.mallexxx.duckdns.org УБРАН из Caddyfile (2026-09-14): Node-RED теперь аддон на t610, наружу НЕ выпущен — доступ через ingress HA. Решение Alex «оставляем так»
webdav.mallexxx.duckdns.org WebDAV
books.mallexxx.duckdns.org Inpxer :18080 🔒 basicauth (user: books-admin) — ⚠️ upstream мёртв (inpxer Exited (1), не трогать)
library.mallexxx.duckdns.org library-app :8080 🔒 basicauth (user: books-admin) — ⚠️ upstream мёртв (library погашен 2026-09-14)
portainer.mallexxx.duckdns.org Portainer :9000
truenas.mallexxx.duckdns.org TrueNAS UI :80
cam.mallexxx.duckdns.org УБРАН из Caddyfile (2026-09-14). Исторический upstream: 192.168.2.197:8090 — отдельный HTTP-MJPEG-сервис (ustreamer), контейнер утрачен при пересоздании пула. Камера теперь на t610: аддон a889bffc_go2rtc-hardware → RTSP H.264 rtsp://192.168.2.176:8554/usb_camera_h264camera.192_168_2_176 (зона Котельная, WebRTC работает, поворот #rotate=90). Домен не нужен. Подробно family/how-to/home-automation §5-кватер-И-6
vpn-panel.mallexxx.duckdns.org 3x-ui панель :2053 (добавлен 2026-09-01)
vpn.mallexxx.duckdns.org Xray VLESS-WS (путь /vless) → xray-admin:10095 (добавлен 2026-09-01)

xray-admin — 3x-ui панель (Xray server, добавлена 2026-09-01)

SUBSCRIPTION-КАНАЛ (auto-обновление клиентов) — работает, проверено 2026-09-15

Прямой ответ на вопрос Alex «можно поменять на xray subscription channel (auto)?»: да — он УЖЕ есть, включать ничего не надо. Ошибка была в том, что в клиент вбивали одиночный vless://…, а нужна ССЫЛКА ПОДПИСКИ.

Что Значение (проверено живьём 2026-09-15)
Базовый sub-URL https://vpn-panel.mallexxx.duckdns.org/sub/HTTP 200
user1 (direct, TrueNAS 90.189.160.148) https://vpn-panel.mallexxx.duckdns.org/sub/68c5cy5n5ui138yh
kraken-user (egress через Kraken 92.62.70.41) https://vpn-panel.mallexxx.duckdns.org/sub/f43074a029dc656e
Формат ответа base64-список vless:// (стандарт «subscription channel»)
Settings в x-ui.db subDomain=vpn-panel.mallexxx.duckdns.org, subPort=443, subScheme=https; у каждого клиента своё поле subId (16 символов) и subId есть только у клиентов user1 / kraken-user

Разложенный payload user1 (для проверки совпадения с ручным конфигом):

vless://ce320965-6956-4759-84bb-7cb71cfc6252@vpn.mallexxx.duckdns.org:443?encryption=none&host=vpn.mallexxx.duckdns.org&path=%2Fvless&security=tls&type=ws#vless-ws-user1
vless://93a5dc4b-1b8d-4af5-9363-eb0091734293@vpn.mallexxx.duckdns.org:443?encryption=none&host=vpn.mallexxx.duckdns.org&path=%2Fvless&security=tls&type=ws#vless-ws-kraken-user

Как включить авто-обновление в клиенте (3 шага): ① удалить вручную вбитый профиль/сервер; ② «Add subscription» → вставить ПОЛНЫЙ путь …/sub/<subId> (без /sub не работает); ③ включить auto update interval (6–12 ч). Новые клиенты, добавленные в панели, после этого появляются в клиенте сами — руками vless:// больше вбивать не нужно.

Команды проверки подписки (с TrueNAS, без правки чего-либо):

ssh truenas_admin@mallexxx.duckdns.org
curl -sk -o /tmp/s.txt -w 'HTTP %{http_code} size %{size_download}\n' https://vpn-panel.mallexxx.duckdns.org/sub/<subId>
curl -sk https://vpn-panel.mallexxx.duckdns.org/sub/<subId> | base64 -d        # → vless://… построчно

Где брать subId (в контейнере нет sqlite3):

docker exec xray-admin sh -c "strings /etc/x-ui/x-ui.db | grep -o '\"subId\":\"[a-z0-9]*\"'"

⚠️ jq/python3 в контейнере xray-admin не проверялись — использован strings (проверенный на TrueNAS приём, см. диагностические питфоллы ниже).

Что панель ТЕКУЩЕЙ версии (3.7.0) умеет и не умеет по подпискам:

  • Есть: subId на клиента, sub-сервер (/sub/<subId> → base64 vless-список), настройки subEnable/subPath/subURI/subJsonEnable/subJsonPath/subJsonURI/subClashEnable/subClashPath/subClashURI/subTitle/subListen/subUpdates/subDomain/subPort/subScheme/subCertFile/subKeyFile, шаблоны custom-subscription-templates, таблица sub_balancers, last_sub_fetch в client_traffics (панель видит, кто и когда тянул подписку).
  • НЕТ «subscription channel» как отдельной сущности с ветками/каналами (типа mihomo-«channel»/Nekoray-«channel»): в бинарнике /app/x-ui нет ни одной строки channel в этом смысле и нет API-роутов каналов. Есть категории subJsonURI / subJsonPath — это JSON/Mihomo-формат той же подписки, XUI/subClashEnableRouting — mihomo-специфика. То есть «channel» = ссылка подписки + клиентский auto-update, отдельного механизма в панели нет.
  • Роуты панели по темам подписок (из strings /app/x-ui): /panel/api/clients/sub, /panel/api/sub-balancers*, /panel/api/xray/outbound-subs*. (outbound-subs = панель сама тянет ВНЕШНИЕ подписки в свои outbound — противоположное направление, не клиентская подписка.)

🔴 ОТКРЫТЫЙ ВОПРОС БЕЗОПАСНОСТИ (задан Alex 2026-09-15, решения НЕТ): путь /sub/<subId> отдаётся без авторизации/sub/abc тоже даёт 200. Кто знает subId — получает рабочий ключ. Возможный фикс: подписка по токену/subUpdates-проверке в настройках панели либо короткий subId + ротация. Ничего не менялось, ждём решения.


РЕАЛИЗАЦИЯ 2026-09-15: клиент vless-space на ВНЕШНЕЙ outbound-подписке — АРТЕФАКТЫ ГОТОВЫ, ПРИМЕНЕНИЕ НЕ ВЫПОЛНЕНО

Задача Alex: добавить в xray-admin третьего клиента vless-space, чей трафик идёт через внешнюю Xray-подписку profilegrid.net с авто-обновлением серверов. user1 и kraken-user НЕ трогать. Серверы — «авто брать» (все, с балансировкой).

Разбор путаницы (обе версии были в диалоге, верна ВТОРАЯ):

  • «Сервер не может ходить через чужую подписку, он только принимает» — НЕВЕРНО, агент сам себя опроверг в том же ответе. Alex справедливо на это указал.
  • ВЕРНО: 3x-ui так УМЕЕТ. Но реализовано это НЕ через таблицу outbound_subscriptions (как предполагалось в черновике), а через xrayTemplateConfig: серверы подписки разворачиваются в обычные outbound'ы шаблона, а выбор клиента делается routing-правилом. См. «Как реализовано» ниже.
  • 🔑 Два разных «subscription» в 3x-ui — не путать:
    Направление Где Кто использует
    /sub/<subId> сервер → клиентам subDomain/subPort/subScheme Happ/v2rayN на телефоне
    outbound_subscriptions панель → тянет извне таблица outbound_subscriptions (штатный путь 3x-ui; здесь НЕ использован)

Целевая схема

[клиент vless-space] → vpn.mallexxx:443 → xray-admin → outbound space-01…space-10 → интернет (DE/LV/NL…)

Шаг 1 ВЫПОЛНЕН — подписка проверена фактом (только чтение)

  • URL: https://go.profilegrid.net/sub/djMsNDc3MjgsMTc4OTQ1OTg5NA.WjZEVaps9Xl3s5dkD6x7KRyNIGi7MlDUNAVPMKBUOdk
  • curl -sk -m 25 с TrueNASHTTP 200, size=12412, content_type=text/plain; charset=utf-8
  • base64 -d28 строк vless://, все security=reality + type=tcp + flow=xtls-rprx-vision
  • Один UUID на весь список: c67ce742-d94f-4e56-889e-9f894ae59940; на каждом сервере свои pbk/sid/sni/spx
  • Питфолл: 28 строк → 10 уникальных серверов. Подписка отдаёт несколько записей на один хост с разными pbk/sid (перебор ключей). Дедуп по host + pbk + sid. Даже после дедупа встречаются повторы хостов с разными ключами.
  • 10 уникальных: edge-{de,lv,nl,ee,pl,fr,us}.mirrorgrid.net, packages-{nl,se}.repocache.com, md.repodelivery.com — теги space-01space-10 (в отчёте на Mac сохранены маскировочные имена: 🇩🇪 Germany, 🇱🇻 Latvia | YT …)

Шаг 2 ВЫПОЛНЕН — бэкап

/mnt/RED_2TB/docker/backups/xray-admin-before-vless-space-20260915-012057/x-ui.db + x-ui.db-shm + x-ui.db-wal + system_metrics.gob (копия всей папки).

🔑 КЛЮЧЕВОЕ ОТКРЫТИЕ: правка идёт через xrayTemplateConfig в БД, панель НЕ нужна

Черновой вывод «нужен доступ к панели 3x-ui» — НЕВЕРЕН, снят в этой же сессии. Факты:

  • Таблица settings, ключ xrayTemplateConfig (2128 б) — это и есть шаблон, из которого 3x-ui генерирует /app/bin/config.json при старте. Именно сюда вносятся outbound'ы и routing-правила. Не править /app/bin/config.json — он перезаписывается.
  • Все ключи settings в базе: secret, subDomain, subPort, subScheme, panelGuid, xrayTemplateConfig. Ключа webBasePath НЕТ.
  • Таблица outbound_subscriptions существует, но ПУСТА (0 записей) — выбран другой путь (см. ниже).
  • POST /login с admin/adminHTTP 403; корень панели /HTTP 200.

Шаг 3 ВЫПОЛНЕН (на Mac) — собран новый xrayTemplateConfig

Рабочая папка на Mac: ~/tmp-xray-space/

Файл Что
xui_copy.db копия живой БД (выгружена docker cpscp)
template_config.json текущий xrayTemplateConfig (из settings)
sub_decoded.txt подписка, base64 развёрнут — 28 строк
build_template.py парсер vless:// → xray-outbound + сборка шаблона
space_outbounds.json 10 новых outbound'ов (отчёт)
template_config.new.json итоговый шаблон (11 140 б)
make_sql.py генератор SQL-скрипта
apply_space.sql готовый SQL для живой БД
test_apply.db песочница (копия БД + применённый SQL)

Что добавлено в шаблон (существующее не тронуто):

  • outbounds += 10 штук space-01space-10 (protocol vless, vnext[], REALITY в streamSettings.realitySettings: serverName/publicKey/shortId/spiderX/fingerprint=firefox)
  • routing.rules += правило: {"type":"field","user":["vless-space"],"outboundTag":"space-balancer","ruleTag":"vless-space-via-subscription"}
  • routing.balancers = [{"tag":"space-balancer","selector":["space-"],"strategy":{"type":"leastPing"}}]
  • observatory = {"subjectSelector":["space-"],"probeUrl":"https://www.google.com/generate_204","probeInterval":"30s","enableConcurrency":true}обязателен для leastPing (иначе балансировщик не знает задержки)
  • Питфолл REALITY в outbound: формат realitySettingsserverName + publicKey + shortId + spiderX + fingerprint; flow: xtls-rprx-vision кладётся в users[0].flow (в подписке он приходит как query-параметр).
  • Питфолл парсера подписки: spx в ссылке URL-энкодирован (%2F…) — обязателен unquote, иначе Xray падает на spiderX.

Шаг 4 ВЫПОЛНЕН (на Mac) — клиент vless-space + SQL, проверен в песочнице

Параметр Значение
email vless-space
клиентский UUID a792c483-07e2-4723-9c50-78054c0abc07
subId 24df9391356b48ff
sub-ссылка (будет) https://vpn-panel.mallexxx.duckdns.org/sub/24df9391356b48ff

apply_space.sql делает 3 вещи: ① UPDATE inbounds.settings (id=1, tag in-10095-tcp) — добавляет клиента к user1/kraken-user; ② UPDATE settings.xrayTemplateConfig — новый шаблон; ③ INSERT INTO clients — строка клиента для учёта в панели.

Результат прогона в песочнице (test_apply.db) — совпал с ожиданием:

Проверка Результат
Клиенты в БД user1, kraken-user, vless-space
UUID user1/kraken-user не изменились
Outbound'ов 13 (3 старых + 10 новых)
Routing-правила kraken-user-via-reverse, vless-space-via-subscription
Балансировщик space-balancer, leastPing
Валидность JSON VALID

⏸️ Шаг 5 НЕ ВЫПОЛНЕН — применение в живую БД остановлено (продолжать отсюда)

Что произошло: SSH-сессия к TrueNAS оборвалась ровно на docker stop xray-admin (Connection to mallexxx.duckdns.org closed by remote host). Контейнер поднялся сам (restart: unless-stopped), БД осталась нетронутой.

Факт-проверка после обрыва (БД НЕ изменена): vless-space в конфиге — 0, outbound'ов 3, правил 1, balancernull.

Порядок применения (одна короткая команда — SSH к TrueNAS рвётся на длинных операциях):

# на TrueNAS, из /mnt/RED_2TB/docker/xray-admin/
docker stop xray-admin && rm -f x-ui.db-shm x-ui.db-wal \
  && sqlite3 x-ui.db < /tmp/apply_space.sql \
  && docker start xray-admin

⚠️ Питфолл: docker stop у 3x-ui сам корректно закрывает БД и сливает WAL в основной файл — поэтому -wal/-shm надо удалять после остановки, иначе правка уйдёт в файл, который потом перезапишется из WAL. ⚠️ Если правка выполняется при жизни WAL без остановки — риск потери изменений и порчи базы. sqlite3 в самом контейнере отсутствует (which sqlite3 пусто) — работать только хостовым бинарём или через alpine-контейнер.

Шаг 6 (проверка фактом) — не начат: временным клиентом с id vless-space дёрнуть curl и убедиться, что egress НЕ 90.189.160.148 (TrueNAS) и НЕ 92.62.70.41 (Kraken), а IP сервера из подписки.

📋 Обновлённая таблица шагов

# Шаг Статус
1 Проверить URL подписки фактом готово (28 строк → 10 серверов, HTTP 200)
2 Бэкап x-ui.db (+-wal,-shm) готово (backups/xray-admin-before-vless-space-20260915-012057)
3 Собрать xrayTemplateConfig (10 outbound + balancer + rule) готово на Mac (template_config.new.json)
4 Клиент vless-space + apply_space.sql, проверка в песочнице готово (песочница прошла)
5 Применить SQL в живую БД (стоп → SQL → старт) остановлено (SSH оборвался)
6 Проверка фактом: egress = IP из подписки не начат
7 Обновить доки не начат

🔴 ИСПРАВЛЕНИЕ (2026-09-15, финал): «панель не нужна» — НЕВЕРНО. Панель нужна.

Прежний вывод «панель 3x-ui не нужна для этой задачи» — благополучно опровергнут шестью попытками. Через БД работает только xrayTemplateConfig (outbound'ы + правила + балансировщик — они применились фактом). Клиентов инбаунда через SQLite добавить нельзя — 3x-ui рендерит их из внутреннего состояния.

🔴 ЕЩЁ ОДИН ПИТФОЛЛ (6-я попытка): попытка положить существующий инбаунд in-10095-tcp (с тремя клиентами) внутрь xrayTemplateConfig сломала kraken-user. 3x-ui мёржит шаблон с таблицей inbounds, и шаблонная версия того же тега перебивает панельную. В шаблоне — только outbounds/routing.rules/balancers/observatory. Инбаунды — эксклюзив панели.

Итог: БД откачена Alex'ом, система в исходном состоянии (user1 + kraken-user, 3 outbound'а). Задача ждёт доступа к панели: (А) Alex добавляет клиента через UI; (Б) Alex выдаёт API-токен (Settings → API Tokens). Подробный разбор — personal/tech/vless-space-subscription-egress §«ПИТФОЛЛ: инбаунд внутри xrayTemplateConfig».

⚠️ Питфоллы, выявленные в этой сессии

  • 🔴 SSH к TrueNAS обрывается на docker stop xray-admin. Первое выполнение docker stop завершилось closed by remote host — контейнер при этом перезапустился сам (restart: unless-stopped). Длинные операции с остановкой контейнеров делать одной короткой командой, а не серией вызовов.
  • Панель 3x-ui не нужна ОПРОВЕРГНУТО (см. выше). Для клиентов инбаунда панель обязательна.
  • Xray-сервер ≠ Xray-клиент. vless-proxy — клиент (SOCKS → наружу), xray-admin — сервер (принимает). xray-admin ходит наружу только через свои outbound'ы; подписка превращается в набор outbound'ов внутри xrayTemplateConfig.
  • docker exec <c> sh -c "strings <file>" — штатный приём чтения бинарных/config-файлов внутри контейнера TrueNAS, где нет sqlite3/jq/python3.
  • docker run --rm -v /mnt/RED_2TB/docker/...:/d alpine cat ... — рабочий приём чтения root-owned конфигов TrueNAS (docker cp с копированием БД на хост тоже работает).
  • outbound_subscriptions vs разворачивание в шаблон: таблица outbound_subscriptions (штатный путь 3x-ui, роуты /panel/api/xray/outbound-subs[/parse]) осталась пустой. Выбранный путь — «развернуть серверы подписки в обычные outbound'ы + leastPing-балансировщик + routing-правило по user». Плюс: не зависит от панели. Минус: авто-обновление списка серверов при смене подписки не автоматическое — потребуется повторно собрать шаблон (тот же build_template.py) и применить. Для настоящего «auto» нужен cron-скрипт (тянет подписку → пересобирает шаблон → применяет SQL).

ПОДЗАДАЧА 2026-09-15: hermes-taiga переключить с мёртвого vless-proxy (НЕ ВЫПОЛНЕНА)

Факт: hermes-taiga ходит НЕ через xray-admin/user1, а через отдельный контейнер vless-proxy.

  • env: TELEGRAM_PROXY=socks5://vless-proxy:1080, DISCORD_PROXY=socks5://vless-proxy:1080
  • сети hermes-taiga: hermes_taiga_net, ha_default; xray-admin — в caddy_default (разные сети, по имени не видят друг друга)
  • vless-proxy: teddysun/xray:latest, Up, SOCKS :1080 + HTTP :1081, единственный outbound → мёртвый v.qentra.top:443 (VPS удалён)
  • ⇒ Telegram/Discord бота сейчас без сети.

Готовый план (4 поля, user1 и kraken-user не трогаются):

Поле в /mnt/RED_2TB/docker/vless-proxy/config.json Сейчас Станет
outbounds[0].settings.vnext[0].address v.qentra.top vpn.mallexxx.duckdns.org
…vnext[0].users[0].id 2D9F24C4-21FE-… ce320965-6956-4759-84bb-7cb71cfc6252 (user1) — или 93a5dc4b-… (kraken-user, egress Kraken, предпочтительнее)
streamSettings.tlsSettings.serverName v.qentra.top vpn.mallexxx.duckdns.org
streamSettings.wsSettings.path / .headers.Host /qentra / v.qentra.top /vless / vpn.mallexxx.duckdns.org

port: 443, security: tls, network: ws — без изменений. Порядок: бэкап → правка локально на Mac (не sed на сервере) → залив → docker restart vless-proxy → проверка api.telegram.org = 200.

Файлы /mnt/RED_2TB/docker/vless-proxy/: config.json (1091 б), config.json.bak-20260707-102922, config.json.bak-switch-ws-client-20260707-103233, docker-compose.yml (336 б).

Важное про «auto»: Xray-клиент (в т.ч. vless-proxy) подписки не умеет — авто-обновление живёт только в GUI-клиентах (Happ/v2rayN/NekoBox/sing-box). Для контейнера «auto» = cron-скрипт: curl подписки → base64 -d → собрать config.jsondocker restart vless-proxy. Отдельный кусок, не начат.

Цель: 3x-ui frontend для Xray-reverse туннеля Kraken↔TrueNAS (выход клиентов сети TrueNAS через Kraken). Подробно: personal/tech/xray-reverse-tunnel-kraken-truenas.

Параметр Значение
Папка /mnt/RED_2TB/docker/xray-admin/
Контейнер xray-admin (имя важно — Caddyfile резолвит по нему)
Образ ghcr.io/mhsanaei/3x-ui:latest (3.7.0, Xray 26.7.28)
Volume /mnt/RED_2TB/docker/xray-admin:/etc/x-ui (там x-ui.db)
Сеть caddy_default (внешняя)
Панель https://vpn-panel.mallexxx.duckdns.org/ (Caddy → xray-admin:2053)
Inbound vless-ws port 10095, tag in-10095-tcp, path /vless, host vpn.mallexxx.duckdns.org; clients: user1 (direct TrueNAS), kraken-user (reverse via Kraken), vless-space (подписка profilegrid — см. ниже)
Sub-сервер [::]:443 (path /sub), панель [::]:2053
Env TZ=Asia/Novosibirsk, PUID=950, PGID=950, XUI_IN_DOCKER=true, XUI_MAIN_FOLDER=/app, XUI_ENABLE_FAIL2BAN=true, XUI_DB_TYPE=, XUI_DB_DSN=
Ports (host) 54321:54321 (не используется панелью — внутри панель на 2053, можно убрать)
Compose /mnt/RED_2TB/docker/xray-admin/docker-compose.yml ВОССТАНОВЛЕН 2026-09-15 из docker inspect (был утрачен 2026-09-01, см. family/plans/reverse-xray-3xui-kraken). docker compose config валиден, docker compose ps распознаёт контейнер.

🔴 ПИТФОЛЛ xray-admin (bind-mount /etc-x-ui): правка/удаление файлов внутри контейнера в пути /etc/x-ui/ бьёт прямо по хосту — это тот же самый каталог. Именно так 2026-09-01 был уничтожен docker-compose.yml (docker exec xray-admin rm -f /etc/x-ui/docker-compose.yml). Никогда не делать rm/mv в /etc/x-ui изнутри контейнера. Файлы складывать на хост через docker run --rm -v /tmp:/src -v /mnt/RED_2TB/docker/xray-admin:/dst alpine cp ….

🔴 ПИТФОЛЛ правки SQLite x-ui.db (WAL): база работает в WAL-режиме. Нельзя копировать только .db и класть рядом со старыми -wal/-shmdatabase disk image is malformed. Правильно: docker stop xray-adminrm -f x-ui.db-wal x-ui.db-shm → SQL напрямую в /data/x-ui.dbchown 950:rootdocker start. Лучше всего — вообще править через панель.

🔴 ПИТФОЛЛ ручного INSERT в таблицу clients: SQLite ставит NULL в колонки, не указанные в INSERT. Заполнять все текстовые колонки (auth, reverse, flow, password, group_name, security) пустой строкой '' / значением по образцу живого клиента. НО: проверено 2026-09-15 — даже при полностью корректной БД (все типы совпадают, integrity ok, шаблон валиден, Xray принимает конфиг Configuration OK) клиент, добавленный в clients снаружи, в config.json НЕ появляется. Причина — 3x-ui рендерит список клиентов из своего внутреннего состояния, а не из файла БД. Правка клиентов инбаунда возможна ТОЛЬКО через панель (/panel/api/inbounds/update/:id) или её API-токен. См. personal/tech/vless-space-subscription-egress.

🔴 3x-ui держит БД открытой: при живом контейнере x-ui.db на диске показывает старую дату — правки уходят в -wal. Удаление -wal перед правкой уничтожает актуальные данные 3x-ui. Признак, что правка не применилась: ls -la /app/bin/config.json /etc/x-ui/x-ui.db → если БД датирована раньше правки, 3x-ui её не перечитал.

ПРАВИЛЬНЫЙ способ правки SQLite (установка Alex, 2026-09-15): базу scp на Mac → править и проверять локально (sqlite3, jq, PRAGMA integrity_check) → валидировать шаблон живым Xray-бинарником (docker cp … && ./xray-linux-amd64 run -test -c …Configuration OK.) → заливать готовый файл одной командой cp + chown 950:root. Не гонять SQL по SSH — вложенные кавычки в ssh '… sh -c \"…\"' ломаются (unrecognized token: ""PRAGMA", no such column: "").

⚠️ Панель на /login отдаёт 403 — это не поломка и не отсутствие доступа, просто другой путь у API. Логин панели — vpn-admin, пароль в БД лежит bcrypt-хэшем ($2a$10$JJscByJjUHJyqmp1a8LZ7egLY0g.XbIoY…), агент его не читает. secret из settings (RuERf2DTzPTw3CoMcVjk7tGXKCQOk0Z4) для логина не подходит (403), API-путь даёт 404 без webBasePath.

📌 Как генерируется config.json: 3x-ui собирает /app/bin/config.json из БД. Outbound'ы и routing берутся из xrayTemplateConfig (таблица settings — правится целиком и реально применяется), а список клиентов — из внутреннего состояния 3x-ui (не из inbounds.settings и не из таблицы clients при внешней правке).

Точка правки Xray-конфига: таблица settings → ключ xrayTemplateConfig в /etc/x-ui/x-ui.db. ⚠️ /app/bin/config.json — генерируемый, не править (перезапишется). sqlite3 внутри контейнера отсутствует — работать хостовым бинарём или alpine-контейнером.

Статус (2026-09-02): контейнер Up, панель HTTP 200. Reverse portal развёрнут отдельным контейнером xray-reverse-portal; per-user egress работает end-to-end.

ПРОВЕРЕНО РАБОТАЕТ (2026-09-02): vpn.mallexxx.duckdns.org:443 — это ФУНКЦИОНАЛЬНЫЙ Xray-СЕРВЕР, НЕ только reverse-frontend. Проверено end-to-end юзером с Mac. Ключевые факты с живой машины:

  • Контейнеры xray-admin (Up 21h) и caddy (Up 20h) оба живы. Панель vpn-panel → HTTP 200. TCP vpn.mallexxx.duckdns.org:443 снаружи открыт.
  • Inbound in-10095-tcp (реальный конфиг из bin/config.json, Xray 26.7.28): VLESS-WS, security: none, WS path /vless, host vpn.mallexxx.duckdns.org.
    • client id: ce320965-6956-4759-84bb-7cb71cfc6252 (email user1)
  • Outbound: freedom/direct — сервер имеет СОБСТВЕННЫЙ выход в интернет через TrueNAS (не через Kraken!). routing: geoip:private + bittorrent → blocked.
  • Тест с Mac (временный xray-клиент в docker): VLESS+WS через vpn.mallexxx.duckdns.org:443 → HTTP 200, выходной IP 90.189.160.148 (TrueNAS). Сервер полностью рабочий.
  • ⚠️ Так и твой клиент должен подключаться: TLS терминирует Caddy на 443, inbound security: none → в конфиге КЛИЕНТА network: ws, TLS поверх на vpn.mallexxx.duckdns.org (НЕ включать двойной TLS внутрь WS).
  • ⚠️ Xray 26.7.28 удалил allowInsecure в клиентских tlsSettings (мигрировано на pinnedPeerCertSha256/verifyPeerCertByName). Если в клиентском конфиге был allowInsecure: true — клиент падает. Это частая причина «не подключается».

Per-user egress (2026-09-02):

  • user1, ID ce320965-6956-4759-84bb-7cb71cfc6252 → default outbound direct → TrueNAS IP 90.189.160.148.
  • kraken-user, ID 93a5dc4b-1b8d-4af5-9363-eb0091734293 → routing rule user: ["kraken-user"] → SOCKS outbound via-kraken at xray-reverse-portal:12345 → Kraken IP 92.62.70.41.
  • Private destinations and BitTorrent remain blocked before the per-user rule.
  • Persistent global template is stored in settings.key=xrayTemplateConfig; do not edit /app/bin/config.json manually because it is generated.
  • Verified with the local xray-test-client: unchanged user1 returned TrueNAS IP; changing only the client UUID to kraken-user returned Kraken IP over both HTTP and HTTPS.
  • Pre/post backups: /mnt/RED_2TB/docker/backups/xray-per-user-20260902-1200/.

Sub-канал (проверено 2026-09-15):

Клиент subId sub-ссылка Egress
user1 68c5cy5n5ui138yh https://vpn-panel.mallexxx.duckdns.org/sub/68c5cy5n5ui138yh TrueNAS 90.189.160.148
kraken-user f43074a029dc656e https://vpn-panel.mallexxx.duckdns.org/sub/f43074a029dc656e Kraken 92.62.70.41
vless-space 24df9391356b48ff https://vpn-panel.mallexxx.duckdns.org/sub/24df9391356b48ff подписка profilegrid.net (10 серверов, space-balancer leastPing) — НЕ СОЗДАН, БД откачена 2026-09-15
  • Sub-сервер отдаёт base64-список vless://… (проверено: HTTP 200, text/plain). Пример тела: vless://ce320965-…@vpn.mallexxx.duckdns.org:443?encryption=none&host=vpn.mallexxx.duckdns.org&path=%2Fvless&security=tls&type=ws#vless-ws-user1.
  • /sub/<subId> отдаётся БЕЗ авторизации — любой, кто знает subId, получает рабочий ключ. Открытый вопрос безопасности.
  • Авто-обновление подписки — функция GUI-клиента (Happ / v2rayN / NekoBox / sing-box: «Add subscription» + auto-update interval). Xray в docker (и vless-proxy, и HA-аддон) подписки не умеет — там только статический config.json; «auto» реализуется внешним cron-скриптом, который тянет /sub/<subId> → генерит config.json → рестартит контейнер.
  • Панель: логин vpn-admin, пароль — bcrypt-хэш в таблице users ($2a$10$JJscByJjUHJyqmp1a8LZ7egLY0g.XbIoY…), агенту недоступен. /login с admin/admin → 403.

🔴 ПИТФОЛЛ (критичный): 3x-ui НЕЛЬЗЯ править через SQLite снаружи

Проверено четырьмя подходами 2026-09-15, все провалились (подробно — personal/tech/xray-outbound-subscription-3xui):

Можно через SQL Нельзя через SQL
settings.xrayTemplateConfig — outbound'ы, routing.rules, routing.balancers, observatory (13 outbound'ов применились) Клиенты инбаундаinbounds.settings, таблица clients

Почему: 3x-ui держит БД открытой и пишет в -wal; при рестарте список клиентов берёт из своей внутренней памяти, а не из файла. Правки в clients/inbounds.settings молча игнорируются, config.json перегенерируется в урезанном виде (2978 б вместо 11 990).

Признак невключившейся правки: ls -la /app/bin/config.json /etc/x-ui/x-ui.db — если БД показывает дату раньше правки, 3x-ui её не перечитал. Правильный путь: клиенты — только через панель (/panel/api/inbounds/update/:id) или API-токен (Settings → API Tokens). kraken-user в 2026-09-02 добавлялся именно так.

⚠️ ПИТФОЛЛ bind-mount: folder /mnt/RED_2TB/docker/xray-admin смонтирована в контейнер как /etc/x-ui. Любой rm/mv внутри контейнера по этому пути удаляет файл на хосте. Так был утрачен docker-compose.yml 2026-09-01 (docker exec xray-admin rm -f /etc/x-ui/docker-compose.yml). Не чистить этот каталог изнутри контейнера.

⚠️ База x-ui.db была уже настроена под эту Caddy-интеграцию (inbound vless-ws:10095, subDomain vpn-panel), поэтому панель заработала «из коробки». Бэкап базы/Caddyfile до изменений: /mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/. Бэкап перед попыткой vless-space: /mnt/RED_2TB/docker/backups/xray-admin-before-vless-space-20260915-012057/.

xray-reverse-portal — Xray reverse portal (TrueNAS, добавлен 2026-09-01)

Цель: portal-часть Xray-reverse туннеля: принимает исходящий трафик локальных клиентов сети TrueNAS (через SOCKS :12345) и пересылает по reverse-каналу на Kraken (bridge) → интернет через Kraken. Подробно: personal/tech/xray-reverse-tunnel-kraken-truenas.

Параметр Значение
Папка /mnt/RED_2TB/docker/reverse-portal/
Контейнер xray-reverse-portal
Образ teddysun/xray:latest (Xray 26.7.28)
Volume config.json:/etc/xray/config.json:ro
Сеть caddy_default
interconn :12346 VLESS (принимает reverse-канал от Kraken) — сейчас на TCP+REALITY (внутр. порт 12346, проброс 12346:12346)
local :12345 SOCKS (точка входа для клиентов сети TrueNAS), проброс 12345:12345
Env LOGLEVEL

Reverse работает end-to-end (2026-09-02). Portal работает на Xray 26.4.25, TCP+REALITY+Vision (12346:12346); OpenWrt DNAT внешний:12346 → 192.168.2.197:12346. Bridge на Kraken также закреплён на 26.4.25 и обязательно использует network_mode: host; Docker bridge/NAT сбрасывал reverse mux. HTTP/HTTPS egress проверен как 92.62.70.41 (Kraken). Детали и rollback: personal/tech/xray-reverse-tunnel-kraken-truenas.

Home Assistant — детали

  • Image: ghcr.io/home-assistant/home-assistant:stable
  • Порт: 8123:8123
  • Volume: /mnt/RED_2TB/docker/ha/config
  • Конфиги редактируются напрямую на NASdocker cp не нужен, изменения применяются после reload/restart HA.

Home Assistant на TrueNAS ХОЛОСТОЙ ЭКЗЕМПЛЯР (аудит 2026-09-14)

СТАТУС (2026-09-14, ночь): КОНТЕЙНЕР ПОГАШЕН. docker stop homeassistant + docker update --restart=no. Причина: modbus.host в /mnt/RED_2TB/docker/ha/configuration.yaml указывает на .197 (сам TrueNAS) — шины там больше нет (адаптеры на t610), инстанс холостой. Живая HA — аддон на t610 192.168.2.176, домен mallexxx.duckdns.org ведёт туда (Caddy → 192.168.2.176:80). Папки и конфиги целы — откат: docker start homeassistant && docker update --restart=unless-stopped homeassistant. Подробно — §5-кватер-Л в family/how-to/home-automation. 📌 Эталон конфига старой HA сохранён: /mnt/RED_2TB/docker/ha/configuration.yaml — modbus-блок построчно идентичен тому, что уехал на t610 (32 заслонки). Использовался как эталон при сверке зон/устройств. ⚠️ Папки docker/ha/ и docker/homeassistant/homeassistant/ ПУСТАЯ, рабочая — ha/.

Папка /mnt/RED_2TB/docker/ha//config. Образ ghcr.io/home-assistant/home-assistant:stable, порт 8123.

Ключевые файлы конфига:

Файл Назначение
configuration.yaml Главный конфиг: интеграции, template sensors, http trusted_proxies
automations.yaml Все автоматизации (подключён через !include)
scripts.yaml Скрипты
.storage/lovelace.home_plan Dashboard с планом этажей (JSON, управляется HA UI)
www/floorplan/floor1_ha.svg SVG фон первого этажа
www/floorplan/floor2_ha.svg SVG фон второго этажа

Перезапуск после редактирования конфига:

ssh truenas_admin@mallexxx.duckdns.org "docker restart homeassistant"

Проверка конфига перед перезапуском:

ssh truenas_admin@mallexxx.duckdns.org "docker exec homeassistant python -m homeassistant --script check_config --config /config"

mbusd — Modbus RTU → TCP gateway ПЕРЕЕХАЛ НА t610 (2026-09-14)

СТАТУС (аудит 2026-09-14): контейнер на TrueNAS БОЛЬШЕ НЕ РАБОЧИЙ. USB-адаптеры (CH340 ZONT/вентиляция) физически переехали на t610 → в /sys/bus/usb на TrueNAS только принтер Samsung 04e8:3425. /dev/ttyVent не существует. Контейнер формально Up с 2026-08-25 (RestartCount=0), но спамит tty_reopen(): can't open tty device /dev/ttyUSB0 (No such device or address). Маппинг /dev/ttyVent докер толерирует, пока device не пересоздавали. Кандидат на снос (п.6 плана family/how-to/home-automation). 🔴 ⚠️ ИСТОРИЯ (устранено 2026-09-14): mbusd и ser2net оба публиковали 0.0.0.0:502 И оба просили /dev/ttyVent. ser2net был в state Created (никогда не запущен) — при start ser2net был бы конфликт портов. Оба погашены 2026-09-14 (stop + --restart=no), порт 502 на TrueNAS свободен. Не поднимать оба одновременно.

Мост Modbus RTU → TCP: пробрасывает серийный порт в TCP 502. Используется и для вентиляции (AT2), и для ZONT-шины.исторически; на 2026-09-14 обе линии обслуживает mbusd на t610.

  • Image: 3cky/mbusd, compose в /mnt/RED_2TB/docker/mbusd/
  • Порт: 502:502 (TCP)
  • Config: /mnt/RED_2TB/docker/mbusd/mbusd.conf/etc/mbusd.conf (device=/dev/ttyUSB0 speed=9600 mode=8n1, port=502)
  • Device: devices: - /dev/ttyVent:/dev/ttyUSB0
  • Entrypoint: ["/usr/bin/mbusd","-d","-L","-","-c","/etc/mbusd.conf"]
  • Pitfall udev-race: см. ниже «Проблема modbus-bridge/mbusd после рестарта».

modbus-bridge — 485-датчики + виртуальные slaves для ZONT ПЕРЕЕХАЛ НА t610 (2026-09-14)

СТАТУС (аудит 2026-09-14): ОСТАНОВЛЕН. Exited (0) с 2026-09-14 01:59:34 (один рестарт, потом тишина) — /dev/ttyZONT перестал существовать в момент переезда USB на t610. network_mode: host + ha.url: http://localhost:8123на TrueNAS он теперь и не смог бы работать: локальный HA смотрит на .197-шину, которой нет. Рабочая копия — аддон modbus-bridge на t610. Кандидат на снос (п.6 плана family/how-to/home-automation). 🔴 Побочная находка: HA_TOKEN лежит открытым текстом в /mnt/RED_2TB/docker/modbus-bridge/docker-compose.yml (env). Кандидат на ротацию вместе с токеном из remote nolvu-landing.

Кастомный Python-мост (modbus_ha_bridge.py, репо HA-ZONT-Modbus), контейнер /mnt/RED_2TB/docker/modbus-bridge/.

⚠️ Уточнение (аудит 2026-09-14): docker-compose.yml ЗДЕСЬ ЕСТЬ — пункт ниже («НЕ имеет compose-файла») устарел. Compose содержит devices: /dev/ttyZONT:/dev/ttyUSB0, env HA_TOKEN/MQTT_USER=zont/MQTT_PASS, network_mode: host, логирование json-file 10m×5.

  • Image: modbus-bridge (локальная сборка, --no-cache). НЕ имеет compose-файла — создавался через docker-compose-подобный run; для восстановления использовать параметры ниже.
  • Device: devices: - /dev/ttyZONT:/dev/ttyUSB0 (внутри контейнера слушает /dev/ttyUSB0)
  • Volumes: config.yml/app/config.yml (ro), modbus_ha_bridge.py/app/modbus_ha_bridge.py (ro)
  • Env (из compose): HA_TOKEN, MQTT_USER=zont, MQTT_PASS=...
  • network_mode: host; MQTT broker localhost:1883 (mosquitto), HA http://localhost:8123.

Роль (важно — два режима работы):

  1. Sniff (чтение) — сниффит реальные 485-датчики на шине ZONT: Dining=slave 1, Kids=slave 2, Bedroom=slave 3 (CO₂/температура/влажность, регистры 2 и 100) и публикует в MQTT (modbus/sensors/<room>/...), а также пишет в HA.
  2. Mappings (виртуальные slaves для ZONT) — подставляет на slave 101/102/103 (регистр 100) значения temperature от 485-датчиков: Dining→101, Kids→102, Bedroom→103. ZONT (Modbus master) опрашивает 101/102/103 как свои внешние датчики температуры. Есть также wifi-термостат как slave 100 (sensor.0xa4c13862d39377e6_temperature) и Socket 1 = slave 101 через switch (обратим внимание: 101 занят и Dining temp — переиспользуется на одном slave с разными функциями; сверить в config.yml).
  3. Также через mbusd может работать с AT2 вентиляции.

Если modbus-bridge не слушает ttyZONT (упал/не запущен) → ZONT не получает ответ на запросы slave 101/102/103 → в интерфейсе ZONT 485-датчики отображаются «недоступные».

Проблема modbus-bridge/mbusd после рестарта TrueNAS (гонка с udev)

Симптом: после перезагрузки TrueNAS /dev/ttyZONT и /dev/ttyVent присутствуют (ttyZONT→ttyUSB1, ttyVent→ttyUSB0, создаются init script id=1), НО контейнеры modbus-bridge/mbusd упали на старте и не перезапустились; 485-датчики в ZONT «недоступные».

Причина: docker стартует раньше udev → при start контейнера устройство ещё не существует → падение ДО запуска процесса:

docker inspect <c> --format '{{.State.Error}}'
error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory
# ExitCode 128 / 255, RestartCount=0

restart: unless-stopped такой отказ не подхватывает (RestartCount=0), и задержка внутри entrypoint не поможет (device mount происходит до старта процесса).

Ручной фикс: docker start modbus-bridge mbusd (после того как симлинки созданы).

Защита от рецидива (план, НЕ внедрён, ждёт OK Alex): family/how-to/zont-modbus-bridge-udev-race-protection.md — POSTINIT init script /mnt/RED_2TB/system/start-modbus.sh, который ждёт появления ttyZONT/ttyVent (≤25с) и делает docker start modbus-bridge mbusd.

USB device aliases

Файл правил: /mnt/RED_2TB/system/99-tty-alias.rules

SUBSYSTEM=="tty", KERNEL=="ttyUSB*", KERNELS=="?-1.6:1.0", SYMLINK+="ttyZONT"
SUBSYSTEM=="tty", KERNEL=="ttyUSB*", KERNELS=="?-1.5:1.0", SYMLINK+="ttyVent"

? — wildcard на префикс USB-шины (2, 3 и т.д.): правила работают даже если хаб переопределяется под другой контроллер (например, после подключения USB3-устройства к тому же хабу).

Применить после изменений:

cp /mnt/RED_2TB/system/99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger

/etc/udev/rules.d/ на TrueNAS — tmpfs, не переживает перезагрузку. Правила применяются автоматически через TrueNAS Init/Shutdown Scripts (POSTINIT).

Просмотреть/изменить: TrueNAS UI → System → Advanced → Init/Shutdown Scripts, или:

midclt call initshutdownscript.query

Текущая запись (id 1, POSTINIT, comment: "Map ttyUSB"):

cp /mnt/RED_2TB/system/99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger

Hermes-Taiga агент

Параметр Значение
Контейнер hermes-taiga
Telegram через общий токен, SOCKS5 прокси vless-proxy:1080
Модель DeepSeek Chat (deepseek/deepseek-chat)
Auxiliary OpenRouter (openrouter/auto)
Vault (хост) /mnt/RED_2TB/storage/obsidian
Vault (контейнер) /vault:rw
obsidian-mcp /opt/data/.local/bin/mcpvault /vault
Scope sparse: personal/ + family/
Toolsets hermes-cli, file, web, browser
web_search Tavily (TAVILY_API_KEY в .env)
web_extract HTTP-парсинг
browser Playwright/Chromium (headless, JS-heavy сайты)
Прокси SOCKS5 vless-proxy:1080 (HTTP/HTTPS/Telegram — все через прокси)

SOUL.md — identity & persona (обновлено 2026-05-13)

Файл: /opt/data/SOUL.md (монтируется в контейнер, читается Hermes на каждый тёрн).

Ключевые изменения 2026-05-13:

  • Добавлен блок ## Identity — Тайга не ассистент, а лес: не извиняется, не суетится, говорит прямо
  • Добавлен uncertainty posture: при отсутствии данных говорит "не знаю" / "нет данных в vault", не строит истории
  • Тон исправлен: убрано "тёплая" (активировало female-helper архетип), оставлено "спокойная, уверенная, немногословная"
  • Добавлена обязанность читать и писать в Obsidian (RULE 2, Vault Access с правильными MCP-командами)
  • display.personality в config.yaml изменён с helpful на neutral — убирает Hermes-level "helpful" прайминг поверх soul

Почему важно: display: personality: helpful в config.yaml инжектировался поверх soul.md и был основным источником извинений и гиперкомпенсации.

Починка root-проблемы (2026-05-13)

Hermes обновился — появилась проверка на root. Контейнер падал с Refusing to run as root. Фикс: HERMES_ALLOW_ROOT_GATEWAY=1 + UV_CACHE_DIR=/tmp/uv-cache в docker-compose.yml + пересборка с --no-cache.

⚠️ При обновлении образа — всегда docker build --no-cache, иначе .venv остаётся от root-слоя и ломает permissions.

Obsidian Sync (Taiga)

Скрипт: ~/sync-vault.sh (запускается на хосте, не в контейнере) Крон: Hermes cron job 0 * * * * Bare repo: file:///mnt/RED_2TB/storage/git/obsidian-vault.git Лог: /tmp/vault-sync.log

# Запустить sync вручную:
bash ~/sync-vault.sh

# Посмотреть лог:
tail -20 /tmp/vault-sync.log

# История коммитов:
git -C /mnt/RED_2TB/storage/git/obsidian-vault.git log --oneline -10

⚠️ Скрипт запускается от truenas_admin — только этот пользователь имеет ZFS ACL доступ к bare repo и vault папке.

Подробности: obsidian-sync

Home Assistant — что настроено

configuration.yaml

  • http: раздел: use_x_forwarded_for: true, trusted_proxies: 172.16.0.0/12 — обязательно для работы через reverse proxy (Caddy)
  • Modbus интеграция для вентиляторов AT2 и заслонок
  • Template sensors (в блоке template: - sensor:):
Сенсор Пример Описание
dining_summary "24° 450ppm" Темп и CO₂ в столовой
dining_air_summary "65tvoc 3pm" TVOC и частицы в столовой
kids_summary "22° 600ppm" Темп и CO₂ в детской
bedroom_summary "21° 500ppm" Темп и CO₂ в спальне
at2_1_summary "Off" / "45%" AT2-1: объединённые on/off + скорость
at2_2_summary "Off" / "45%" AT2-2: объединённые on/off + скорость

automations.yaml

  • ГВС циркуляция: вкл (09:30) / выкл (23:00)
  • Вентиляционный вентилятор вкл в 05:00
  • Проходной выключатель кабинета → toggle света в кабинете (not_from: [unavailable, unknown] — защита от ложных срабатываний при запуске HA)
  • Подсветка лестницы: вкл/выкл по датчику освещённости
  • Диммер спальни: toggle и цикл яркости
  • Ночной свет в душе: присутствие + освещённость
  • Уведомление: датчик протечки (котельная)
  • Уведомления: низкий заряд батареи (несколько устройств)

Floor Plan Dashboard (lovelace.home_plan)

Два вида — Ground Floor (floor1) и Second Floor (floor2) — picture-elements поверх SVG фона.

Первый этаж (floor1):

  • Приточные заслонки: столовая (левая/правая), кабинет
  • Вытяжные заслонки: кухня, туалет 1F
  • Вентилятор 3 (кухонная вытяжка)
  • Метки AT2-1 / AT2-2 (sensor.at2_1_summary / sensor.at2_2_summary)
  • Сауна, обогревательный кабель
  • Свет кабинет (левый/правый)
  • Метка столовой (sensor.dining_summary) и качество воздуха (sensor.dining_air_summary)

Второй этаж (floor2):

  • Приточные заслонки: детская, спальня, север
  • Вытяжные заслонки: ванная, душ 2F
  • Свет спальни (диммер)
  • Метки: sensor.kids_summary, sensor.bedroom_summary

SVG dark mode — встроенный CSS в SVG-файлах:

<style>
@media (prefers-color-scheme: dark) {
  path, line, polyline, polygon, rect, circle, ellipse { stroke: white; }
}
</style>

ЖJSON Lovelace зафиксирован в git по пути floorplan/lovelace.home_plan.json (справочный снимок, HA не подгружает его автоматически).


🔻 Декоммиссия стека автоматизации TrueNAS → t610 (аудит 2026-09-14)

Контекст: миграция умного дома TrueNAS → HP t610 (HA OS) завершена (п.5-мк плана family/how-to/home-automation закрыт). Остался п.6 — погасить дублирующий стек на TrueNAS. Вместо слепого «гасим всё» проведён аудит фактом (что реально живо, что мёртво, что нельзя трогать).

Что искали и как (методика аудита)

Шаг Команда Зачем
Список контейнеров docker ps -a --format '{{.Names}}\t{{.Status}}\t{{.Image}}\t{{.Ports}}' кто жив/умер, какие порты торчат
Кто чем управляется for c in $(docker ps -a --format '{{.Names}}'); do docker inspect $c --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}'; done 🔑 все оказались per-service compose из /mnt/RED_2TB/docker/<app>/ (не Portainer-стек). В portainer/data/compose/пусто.
Почему умер docker inspect <c> --format '{{.State.Error}} {{.State.ExitCode}} {{.State.FinishedAt}}' + docker logs --tail 20 <c> точное время и причина
Есть ли железо ls /sys/bus/usb/devices/ + cat .../product,idVendor:idProduct на TrueNAS только принтер Samsung 04e8:3425 (Intel 8087:0024 = USB-контроллеры). CH340/координатора НЕТ.
lsusb/dmesg недоступны truenas_admin (command not found); dmesg пуст без root. Использовать /sys/bus/usb.
Кто ссылается grep -nE '...' /mnt/RED_2TB/docker/caddy/Caddyfile не сломать рабочие домены

🔑 Питфолл: docker inspect <c> работает под truenas_admin без sudo, а midclt call ... и dmesgнет (нужен root). Для аудита хватает docker + /sys.

Вердикт по каждому контейнеру

Контейнер Состояние Причина Решение
homeassistant Up 5 дн холостой — modbus.host=192.168.2.197, шины там нет ПОГАШЕН 2026-09-14
mbusd Up (ложно), 14:42 can't open /dev/ttyUSB0 /dev/ttyVent не существует (USB уехал) ПОГАШЕН 2026-09-14
mosquitto Up 3 нед ZONT переключён на .176 (DNAT) ПОГАШЕН 2026-09-14
nodered Up (healthy) flows перенесены на t610 (68 узлов) ПОГАШЕН 2026-09-14 (решение Alex: «Гасим nodered»)
zigbee2mqtt Exited (2) 14.09 01:59 Adapter disconnected — координатор на t610 restart=no 2026-09-14
modbus-bridge Exited (0) 14.09 01:59 /dev/ttyZONT исчез restart=no 2026-09-14
caddy Up 17 доменов TrueNAS + mallexxx.* → t610 🔴 НЕ ТРОГАТЬ (не тронут)
ser2net Created (никогда не стартовал) конфликт 502 с mbusd ПОГАШЕН 2026-09-14 (по команде Alex)
library Restarting, restart=29752 🔴 циклический краш, Caddy ссылается (library:8080) ПОГАШЕН 2026-09-14 (по команде Alex); причина краша открыта
inpx-web, inpxer Exited (1), 13 рестартов, 3 нед циклический краш 🔴 НЕ ТРОГАТЬ (указание Alex)

Ключевой факт-маркер переезда: zigbee2mqtt и modbus-bridge оба легли в 2026-09-14T01:59 — синхронно, в момент физического переноса USB-адаптеров. Это доказательство, что дубль перестал работать сам, а не «сломался от чего-то».

Порядок безопасного гашения (одобренный шаблон)

# 1) ГАСИМ, НЕ УДАЛЯЕМ (откат возможен)
docker stop homeassistant mbusd mosquitto nodered zigbee2mqtt modbus-bridge
# 2) Снять автозапуск, чтобы не поднялись после ребута
docker update --restart=no homeassistant mbusd mosquitto nodered zigbee2mqtt modbus-bridge
# 3) Проверки
curl -s -o /dev/null -w '%{http_code}\n' https://mallexxx.duckdns.org   # ожидаем 200 (t610)
# ZONT MQTT: живой поток в mosquitto на .176, а НЕ на .197
# 4) Папки /mnt/RED_2TB/docker/* НЕ удалять — 2-3 дня, потом rm отдельным шагом

Правила этого шага:

  • НЕ docker rm, не удалять /mnt/RED_2TB/docker/<app>/ — сначала «погасить», откат = docker start + вернуть restart: unless-stopped.
  • Caddy не гасить и не переносить — 17 из 20 доменов это сервисы TrueNAS.
  • inpx-*не трогать (указание Alex). libraryпогашен отдельной командой Alex (2026-09-14), причина краша не выяснена.
  • ⚠️ Порт 502: mbusd и ser2net не поднимать одновременно (оба погашены).
  • Факт выполнения 2026-09-14: погашено 9 контейнеров (7 автоматизации + ser2net + library). Проверено: 502/1883/8123/1880 на TrueNAS свободны, mallexxx.duckdns.org = 200, MQTT на .176 живой, RTSP :8554 OPEN.

Печать / cups-splix (2026-08-26, починено)

Принтер Samsung CLX-216x подключён по USB к TrueNAS (не в сети!). Единственный путь печати — контейнер cups-splix, который раздаёт CUPS на 192.168.2.197:631.

Почему телефон не видел принтер (2026-08-26): после пересоздания пула контейнер cups-splix не был поднят — образ локальный (не registry), стёрлся вместе с .ix-apps; при восстановлении его не пересобирали (пометка «проверить при надобности»). Конфиг /mnt/RED_2TB/docker/cups/data (это /etc/cups) цел → принтер прописан и подцепился после рестарта сам.

Рецепт подъёма (при «не вижу принтер»):

cd /mnt/RED_2TB/docker/cups
docker build -t cups-splix .          # образ локальный, собрать заново (~3.5 мин)
docker compose up -d                  # поднять (privileged + /dev/bus/usb)
docker exec cups-splix lpstat -p -d   # проверить принтер
nc -z 192.168.2.197 631               # проверить порт наружу
  • Принтер: usb://Samsung/CLX-216x%20Series?serial=9566BAGQ213134Z.&interface=1 (USB ID 04e8:3425 Samsung CLX-216x).
  • Порт 631: открыт наружу после подъёма.

mDNS/AirPrint анонс принтера — включён 2026-08-31 (Android print service видит принтер)

Проблема: Android штатная служба печати (в отличие от Samsung Mobile Print, который ходит прямо по IP) ищет принтер только через mDNS/Bonjour (_ipp._tcp.local). CUPS не анонсировал: в контейнере не было avahi-daemon, а printer-dns-sd-name в IPP был no-value → Android помечал принтер «недоступен», даже добавленный вручную по IP.

Решение (выполнено): пересобрали cups-splix — теперь запускает dbus-daemon + avahi-daemon рядом с cupsd через entrypoint.sh, и в cupsd.conf включено Browsing On + BrowseLocalProtocols dnssd. После этого CUPS регистрирует принтер в avahi → mDNS-анонс с mopria-certified=1.3 на IPv4 192.168.2.197 физического интерфейса enp3s0. Android (Mopria) теперь находит принтер сам в локальной сети.

Что изменилось в конфиге (папка /mnt/RED_2TB/docker/cups/):

  • Dockerfile: добавлен avahi-daemon в apt, написан entrypoint.sh, ENTRYPOINT вместо CMD (.old образ сохранён как cups-splix-old).
  • entrypoint.sh: стартует dbus-daemon --system, затем avahi-daemon --no-drop-root, затем exec cupsd -f.
  • data/cupsd.conf: Browsing OffBrowsing On + добавлена строка BrowseLocalProtocols dnssd (бэкап cupsd.conf.pre-avahi).

⚠️ Важный питфолл: после правки конфига НЕ использовать docker restart cups-splix — он убивает avahi-daemon (defunct), перед новым подъёмом обязателен docker stop cups-splix && docker rm cups-splix && docker compose up -d (полный пересоздание, чтобы entrypoint перевыполнился с нуля).

Проверка анонса:

docker exec cups-splix sh -c "timeout 6 avahi-browse -rt -p _ipp._tcp | grep ';enp3s0;IPv4;'"
# должно показать: ... Samsung\032CLX-216x... truenas.local;192.168.2.197;631; "mopria-certified=1.3" ...

Бэкап конфига (2026-08-31): /mnt/RED_2TB/docker/cups/backup_20260831-003619.tar.gz (md5 0e303a6a57ae767d1e14cd72c8039fe4) — tar из /etc/cups, /var/spool/cups, /var/cache/cups.

Диагностика и полное объяснение: mac-print-shared-services

⚠️ 2026-08-31: топология изменена. TrueNAS больше НЕ в локальной сети (только публичный DNS mallexxx.duckdns.org) — из других подсетей/внешки 192.168.2.197 недостижим, и снаружи mallexxx.duckdns.org:631 закрыт. НО из самой подсети 192.168.2.x TrueNAS достижима (телефон 192.168.2.141 успешно печатал по 192.168.2.197:631 — CUPS access_log это подтверждает). → Samsung Mobile Print (app) печатает (висит на локальном IPP внутри подсети), а штатная Android print service с ipp://192.168.2.197:631/... показывала «недоступен» из-за отсутствия mDNS/AirPrint-анонса (avahi-daemon не запущен; printer-dns-sd-name = no-value). Исправлено (см. раздел « mDNS/AirPrint анонс принтера»): cups-splix пересобран с avahi-daemon, cupsd.conf получил Browsing On + BrowseLocalProtocols dnssd → принтер анонсируется по mDNS (mopria-certified=1.3, IPv4 192.168.2.197); Android-служба теперь находит принтер сама. Детали и откат: mac-print-shared-services.

2026-09-02: печать ИЗВНЕ сети TrueNAS работает через SSH → cups-splix. Хотя mallexxx.duckdns.org:631 (IPP) снаружи закрыт, документ (PDF, 1 стр A4) успешно напечатан с клиента вне подсети: scp → TrueNAS /tmpdocker cp внутрь cups-splix:/tmpdocker exec cups-splix lp -d Samsung_CLX-216x_Series -o media=A4 file.pdf → job в completed, Rendering completed. CUPS сам конвертит PDF→PS (gs/pdftops есть, PPD *cupsFilter: 0 pstoqpdl). Полный рецепт — mac-print-shared-services (раздел «Печать PDF извне сети TrueNAS»).

Связанные заметки