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

132 KiB
Executable File
Raw Blame History

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

Lampac и Konka — добавлено 2026-10-30

На TrueNAS развёрнут официальный Lampac1.87.3 (amd64), обычный Compose в /mnt/RED_2TB/docker/lampac, LAN http://192.168.2.197:9118; контейнеры lampac и lampac-egress. Клиент Konka Q85 в Новосибирске: 192.168.2.124. Полная эксплуатационная заметка — personal/tech/lampac-truenas.

Отдельный egress обслуживает TMDB и постеры через существующий маршрут Kraken; глобальный прокси видео не включён, общий vless-proxy не менялся. История хранится на TrueNAS; Kraken использует ограниченный HTTPS API в существующем Caddy-сайте git.mallexxx.duckdns.org/lampac-history. Синхронизации SQLite нет. Caddy применён через reload, без перезапуска общего сервиса.

Каталог генерирует только Kraken и публикует готовые JSON через ограниченный SSH-ключ. NAS делает локальный ежедневный бэкап истории в04:27 по часовому поясу хоста, хранит30 дней. Для совместной работы uid950 бэкапа и uid1000 Lampac нужны mode0664/group1000 для TimeCode.sql и WAL/SHM; операция записи после бэкапа проверена. Остальные исторические сведения об инфраструктуре ниже этим изменением не переаудировались.

✅ ДОМАШНЯЯ АВТОМАТИЗАЦИЯ ПЕРЕНЕСЕНА НА 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, ser2net → docker 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.org → 192.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 узлов, узел server → addon: 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.197 → 192.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_h264 → Generic 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 (ФИНАЛ) — ШТАТНАЯ ПОДПИСКА РАБОТАЕТ, СТАТИКА space- ВЫЧИЩЕНА. vless-proxy ПОДКЛЮЧЁН.

Итог: egress через штатный механизм outbound_subscriptions (28 серверов sub1-*, авто-обновление 600 с). Статические space-01…10 удалены как костыль. Живой тест: vless-proxy:1080 → 104.28.219.140 / 188.239.191.18 ≠ 90.189.160.148.

Что Значение
outbound_subscriptions remark=vless-space, tag_prefix=sub1-, update_interval=600
outbounds 31 = direct+blocked+via-kraken + 28 × sub1-*
балансировщик space-balancer, selector: ["sub1-"], leastLoad
observatory burstObservatory, subjectSelector: ["sub1-"], pingConfig{sampling:2, interval:1m}
routing.rules {"user":["vless-space"],"balancerTag":"space-balancer"}
клиенты user1, kraken-user, vless-space — целы

✅ Доки актуализированы 2026-09-15 — сняты устаревшие статусы «vless-space НЕ СОЗДАН / БД откачена» и «авто-обновление не начато».

🔑 ТРИ ПИТФОЛЛА БАЛАНСИРОВЩИКА — все три обязательны

Ошибка app/dispatcher: non existing outTag: space-balancer вызывалась тремя независимыми причинами (каждая воспроизведена и снята отдельно):

# Причина Фикс
1 правило ссылалось через outboundTag → balancerTag
2 strategy: leastPing (в Xray 26.x балансировщик не создаётся) → leastLoad
3 в observatory отсутствовал sampling → "sampling": 3

🔴 ЧЕТВЁРТЫЙ ПИТФОЛЛ (стоил этой сессии) — два поля селектора + два имени секции

а) selector и subjectSelector — РАЗНЫЕ поля, менять ПАРОЙ. Сменил префикс подписки → проверь оба:

docker exec xray-admin cat /app/bin/config.json | jq -c '{bal:.routing.balancers[0].selector, obs:(.burstObservatory // .observatory).subjectSelector}'
# оба должны быть ["sub1-"]

б) Секция в UI называется burstObservatory, не observatory. Xray 26.x принимает обе; панель при сохранении может удалить observatory и создать burstObservatory. Проверять keys[], оба имени:

docker exec xray-admin cat /app/bin/config.json | jq -r 'keys[]'
docker exec xray-admin cat /app/bin/config.json | jq -c '.burstObservatory // .observatory'

в) Симптом рассинхрона — молчаливый direct: subjectSelector не матчит ни один outbound → leastLoad без живых кандидатов → трафик в первый outbound списка. Ошибок в логе НЕТ.

⚠️ xray -test печатает Configuration OK при всех этих ошибках — семантику маршрутизации ловит только рантайм-лог (non existing outTag) + живой запрос через клиент.

Артефакты: ~/tmp-xray-space/ — xui_v9.db (статика, рабочая история), xui_v10.db, xui_v10_src.db, strip_space_outbounds.sh, write_v10.sh, vless-proxy-config-new.json. Бэкапы /mnt/RED_2TB/docker/backups/xray-admin-before-cleanup-20260915-035749/ + xray-admin-before-vless-space-20260915-012057 (точка отката).


🔗 vless-proxy → xray-admin (2026-09-15)

Что было: vless-proxy (SOCKS :1080 + HTTP :1081) смотрел на мёртвый v.qentra.top → hermes-taiga (Telegram/Discord) без сети.

Что стало — /mnt/RED_2TB/docker/vless-proxy/config.json:

Поле Было Стало
vnext[0].address v.qentra.top vpn.mallexxx.duckdns.org
vnext[0].users[0].id 2D9F24C4-… a792c483-07e2-4723-9c50-78054c0abc07 (vless-space)
tlsSettings.serverName v.qentra.top vpn.mallexxx.duckdns.org
wsSettings.path /qentra /vless
wsSettings.headers.Host v.qentra.top vpn.mallexxx.duckdns.org

Порт 443, security: tls, network: ws — без изменений.

Цепочка: hermes-taiga → vless-proxy:1080 → vpn.mallexxx.duckdns.org:443 → xray-admin → 28 × sub1-* → интернет Env hermes-taiga (TELEGRAM_PROXY, DISCORD_PROXY = socks5://vless-proxy:1080) менять не нужно — рестарт не требуется, SOCKS-соединения устанавливаются на каждый запрос.

🔴 Правильная проверка egress (питфолл): wget не умеет SOCKS5 — docker exec vless-proxy wget -qO- https://api.ipify.org вернёт локальный IP контейнера 90.189.160.148 и создаст ложное впечатление «direct». Проверять только через SOCKS-прокси:

docker run --rm --network hermes_taiga_net alpine sh -c \
  "apk add -q curl; curl -s --max-time 20 --socks5-hostname vless-proxy:1080 https://api.ipify.org"
# ожидается НЕ 90.189.160.148

🔴 ДОСТУП (проверено 2026-09-15): /mnt/RED_2TB/docker/vless-proxy/ — root:root 755, config.json примонтирован :ro, внутри контейнера /etc/xray/config.json тоже Read-only file system. truenas_admin править НЕ может (touch → Permission denied; sudo требует пароль; root@192.168.2.197 → publickey denied). Файл правит только Alex от root; агент готовит конфиг локально (~/tmp-xray-space/vless-proxy-config-new.json) и отдаёт целиком.

⚠️ docker compose up -d hermes-taiga → no such service. Сервис в /mnt/RED_2TB/docker/hermes/docker-compose.yml называется taiga (hermes-taiga — это container_name). Правильно: docker compose up -d taiga.

🔴 Прежний хард-вывод «3x-ui нельзя править снаружи» — ОКОНЧАТЕЛЬНО ОПРОВЕРГНУТ. SQLite-путь работает при двух условиях: (1) в xrayTemplateConfig нет инбаунда (только api), (2) БД правится локально на Mac и кладётся файлом с rm -f *.db-wal *.db-shm + chown 950:root.

⚠️ ОТДЕЛЬНАЯ НЕЗАКРЫТАЯ ПРОБЛЕМА — kraken-user: не работает, потому что сервер Kraken недоступен (не связано с БД). Проверено 2026-09-15: ssh-kraken.qentra.top → Connection timed out during banner exchange; kraken@10.99.1.2:22 → Operation timed out; DNS kraken → NXDOMAIN. Портал на TrueNAS жив (xray-reverse-portal Up, 12345/12346 LISTEN), но соединений от бриджа ноль → ждём восстановления Kraken (решение Alex «подождём, может оживет»).

✅ РЕШЕНО 2026-09-15 (штатная подписка). Было: space-01…10 статически вбиты в шаблон — при смене списка у profilegrid всё ломалось молча. Стало: штатная таблица outbound_subscriptions 3x-ui (remark=vless-space, tag_prefix=sub1-, update_interval=600) → 28 серверов sub1-*, авто-обновление. Статика space-01…10 удалена. Балансировщик space-balancer: selector: ["sub1-"], leastLoad; наблюдение — burstObservatory с subjectSelector: ["sub1-"]. Ручная пересборка шаблона больше НЕ нужна.

Правила взаимодействия (Alex, 2026-09-15): команды — плоские однострочники, без ssh … '…'-обёртки, без sleep N, без кириллицы в bash, без execute_code/python. Правку SQLite делать локально на Mac, потом заливать готовый файл.

✅ Compose-файл xray-admin ВОССТАНОВЛЕН из docker inspect (пережил все откаты). Полный разбор, процедура повторения и таблица диагностики — personal/tech/vless-space-subscription-egress / personal/tech/xray-outbound-subscription-3xui.

Обновлено (ранее): 2026-09-15 — попытки 1–7 (провалившиеся) приводятся в personal/tech/vless-space-subscription-egress; их итог — «vless-space НЕ СОЗДАН, БД ОТКАЧЕНА», что с тех пор устарело: задача закрыта в попытке 9 и переведена на штатную подписку (см. выше ✅ РЕШЕНО). Единственный живой вывод оттуда: 3x-ui НЕЛЬЗЯ править снаружи работающего контейнера — клиенты инбаунда только через панель/API-токен; работает через SQLite лишь settings.xrayTemplateConfig (outbound'ы/правила/балансировщик). Остальные детали (7 подходов, auth/reverse=NULL, инбаунд-в-шаблоне) — исторические грабли, разобраны по ссылке.

⚠️ ПРИОРИТЕТ 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 после готовности симлинков. ⚠️ ПОСЛЕДСТВИЕ, ПОДТВЕРЖДЁННОЕ 2026-09-26 (File Browser): потеря .ix-apps = потеря всех docker NAMED VOLUMES, а не только образов. Образы = кеш, перекачаются; тома = данные, не восстанавливаются. Первый пострадавший — filebrowser: его БД пользователей жила в томах filebrowser_filebrowser_db / filebrowser_filebrowser_config → при первом старте тома создались с нуля (2026-08-24T02:04:12), File Browser сгенерировал нового admin, прежние пользователи (file_admin в т.ч.) утрачены. ✅ ЗАКРЫТО для filebrowser 2026-09-26: переведён с named volumes на bind-mount в /mnt/RED_2TB/docker/filebrowser/ — БД больше не в .ix-apps, попадает в обычный бэкап. Рецепт миграции и 5 питфоллов — §«File Browser» ниже. Остальные сервисы с томами (см. docker volume ls) — не проверены, кандидаты на ту же процедуру.

🔴 Правило для будущих переносов: перед zpool destroy/пересозданием всегда выгружать /mnt/.ix-apps/docker/volumes/ отдельным шагом — rsync -aHAX /mnt/.ix-apps/docker/volumes/ /mnt/<TARGET>/ix-apps-volumes/. Одного /mnt/RED_2TB/* НЕДОСТАТОЧНО: .ix-apps — отдельный ZFS-датасет, смонтированный поверх одноимённой папки, в глоб пула не попадает.

🔑 Как быстро найти сервисы с томами (они теряются при переносе, в отличие от bind-mount'ов):

docker volume ls
for c in $(docker ps -a --format '{{.Names}}'); do
  echo "== $c =="; docker inspect $c --format '{{json .Mounts}}' | jq -c '.[] | select(.Type=="volume") | {Name, Destination, Source}'
done

Долгосрочное лечение: переводить критичные сервисы с named volumes на bind-mount в /mnt/RED_2TB/docker/<app>/ — тогда данные попадают в обычный бэкап mailru-crypt: и переживают пересоздание пула. ✅ Первый сделан 2026-09-26 — File Browser (рецепт + 5 питфоллов: §«File Browser — детали» ниже). Остальные сервисы с томами — не проверены, тот же приём применим (см. сниппет docker inspect … select(.Type=="volume") выше).

⚠️ ДРУГОЕ (открытое): пул DEST (IronWolf) на 2026-08-24 DEGRADED — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по 192.168.2.197 — подключение давало Connection reset / kex_exchange_identification (вероятен конфликт сессий при активном входе на консоль) — рабочий путь: mallexxx.duckdns.org.

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

Пул RED_2TB пересоздан и УЖЕ зареган в TrueNAS — zpool 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 / 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 ~28–51 Мбит впритык к пикам файла). НЕ транскодинг (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 (v2.63.23) 8000 docs.mallexxx.duckdns.org → Caddy → 192.168.2.197:8000 — см. раздел «File Browser»; данные в папке, bind-mount (2026-09-26), пользователь file_admin, tokenExpirationTime=720h
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 — —
jellyfin из /mnt/RED_2TB/docker/arr/docker-compose.yml 8096 jellyfin.mallexxx.duckdns.org
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) |

⚠️ 2026-09-23 — правки reverse-пары для попытки «доступ в 192.168.2.x снаружи» (ЗАВЕРШИЛАСЬ ТУПИКОМ)

Попытка завернуть клиентов ASUS-сети на 192.168.2.x через reverse-туннель. Архитектурный тупик — reverse по дизайну не пускает forward-proxy в приватные сети. Полный разбор: personal/plans/lan-access-via-reverse-tunnel, теория: personal/tech/xray-reverse-limits-private-network.

Что осталось применённым на TrueNAS (решить — откатить или оставить):

  • /mnt/RED_2TB/docker/reverse-portal/config.json — добавлено правило роутинга 192.168.2.0/24 → direct (выше правила local → reverse-out), outbound direct с finalRules:[{action:"allow"}]. Валидация Configuration OK., портал Up, канал жив.
  • Бэкап: config.json.before-lanroute (в той же папке).
  • ⚠️ loglevel портала был debug — при откате вернуть warning, иначе лог быстро растёт.

Откат: вернуть config.json.before-lanroute → config.json, затем docker restart xray-reverse-portal.

✅ Побочно: канал впервые подтверждён end-to-end после починки гонки docker↔mount 2026-09-20 — через SOCKS портала 92.62.77.233 ≠ напрямую 90.189.160.148. WAN-IP Кра́кена изменился: 92.62.70.41 → 92.62.77.233.

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 --fork → avahi-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 + docker-compose.yml). Образ hacdias/webdav:latest, домен webdav.mallexxx.duckdns.org. ✅ активен.

Устройство (проверено live):

Параметр Значение
Образ hacdias/webdav:latest
docker-compose.yml /mnt/RED_2TB/docker/webdav/docker-compose.yml (root:root)
bind-mount /mnt/RED_2TB:/data (rw) + ./config.yml:/config.yml
сеть caddy_default (external: true)
процесс UID 0 (root) — docker top webdav → root … webdav --config /config.yml. Config.User пустой.
auth auth: true, юзер webdav / пароль в config.yml, permissions: CRUD
directory /data (то есть весь пул)
вход Caddy webdav.mallexxx.duckdns.org → reverse_proxy webdav:80 (transport http { versions 1.1 })

🔴 ГЛАВНЫЙ ВЫВОД: WebDAV работает под root, поэтому NFSv4 ACL его НЕ блокирует. Root + owner@ ALLOW → контейнер читает/пишет весь /data. «Нет доступа к папке через WebDAV» ≠ «ACL мешает WebDAV» — сначала проверить uid процесса (docker top), а не ACL.

Разбор по сырью (ls -la + midclt filesystem.getacl):

  1. /mnt/RED_2TB/Edu = root:root, drwxrwxr-x, ACL trivial: true, uid 0 / gid 0.
  2. Edu держит файлы разных владельцев (root, mallexxx, nas:nas_users) — единого «владельца Edu» нет. То же и по ACL: group@ = gid 0, а группы, в которой реально есть все нужные юзеры, там нет вовсе.

Почему truenas_admin не имеет доступа (арифметика прав): truenas_admin = uid 950, gid 950, groups=950,544(l builtin_administrators),921(transmission),999(docker),1000(nas),3000(nas_users). Для файла root:root rwxrwx---: owner = root → не он; group = gid 0 → его в группе 0 нет; everyone@ = только атрибуты. ⇒ доступ закрыт. Симметрично и для папки.

⚠️ Поэтому «файл не читается от truenas_admin» — это нормальное следствие gid 0, а не поломка FS.

🔑 Ключевое открытие для ACL-фикса: группа nas_users (gid 3000).

nas_users:x:3000:root,truenas_admin,mallexxx,nas,transmission

Одна ACE на эту группу покрывает сразу всех потребителей (админ, nas, mallexxx, transmission) — вместо россыпи персональных ACE. Альтернатива: builtin_administrators (gid 544, root,truenas_admin).

План фикса (согласован, ✅ ВЫПОЛНЕН 2026-09-23 — фактическое состояние) — из 3 шагов:

  1. Бэкап ACL (ничего не меняет):
    midclt call filesystem.getacl /mnt/RED_2TB/Edu > /mnt/RED_2TB/storage/acl-edu-before-$(date +%Y%m%d-%H%M%S).json
    
  2. Рекурсивно: владелец-группа = nas_users, ACE group@ с flags.BASIC: INHERIT — через read-modify-write (getacl → правим perms/flags → setacl), сохраняя id каждого ACE. Строить dacl с нуля нельзя → [EINVAL] ACL entry is missing required keys(s): {'id'}. stripacl:true не использовать (не сносит DENY, ломает наследование). options: {recursive: true, traverse: true}. setacl асинхронен — поллить core.get_jobs до SUCCESS, иначе читаешь старые флаги и получаешь ложный «failure». Итог фикса (2026-09-23): носитель-группа nas_users (gid 3000), рекурсия по всему Edu (~223 ГБ) выполнена.

✅ ВЫПОЛНЕНО 2026-09-23 (вечер). Выбрана nas_users (gid 3000), рекурсия по всему Edu (~223 ГБ). Фактический результат живой проверки:

drwxrwxr-x 12 root nas_users  14 Sep 22 23:47 /mnt/RED_2TB/Edu

То есть корень Edu и всё дерево = root:nas_users drwxrwxr-x, доступ у truenas_admin и через WebDAV есть. Рабочий рецепт (два прохода: ACL с INHERIT → gid) и 4 питфолла — personal/tech/truenas-nfs4-acl-and-arrmultiuser §«Sharing a whole tree by GROUP (nas_users)». ACL-бэкап: /mnt/RED_2TB/storage/acl-edu-before-<ts>.json.

⚠️ curl/wget-проверка WebDAV с Mac не проходит — сеть caddy_default живёт только внутри Docker на TrueNAS (docker network ls её видит, хост-macOS — нет). Проверять из контейнера на TrueNAS: docker run --rm --network caddy_default curlimages/curl … PROPFIND -u webdav:… http://webdav:80/Edu/.

⚠️ Контейнер hacdias/webdav — distroless: внутри нет ls, ps, cat, id (все exec валятся с executable file not found in $PATH). Диагностику делать снаружи (docker inspect, docker top, ls на хосте).

  • 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.yml → environment (там же 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=no → state=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:8123 → HTTP 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)

File Browser — детали (разобрано и ПЕРЕВЕДЕНО НА ПАПКУ 2026-09-26)

Папка: /mnt/RED_2TB/docker/filebrowser/. Порт: 8000:80 (хост 0.0.0.0:8000). Проверка: nc -z 127.0.0.1 8000. Образ: filebrowser/filebrowser:latest → v2.63.23 (проект заархивирован 2026-09-01, обновлений не будет).

Состояние ПОСЛЕ миграции (актуальный compose):

services:
  filebrowser:
    image: filebrowser/filebrowser:latest
    container_name: filebrowser
    restart: unless-stopped
    user: "0:0"          # ← root: обходит NFSv4 ACL, как и webdav
    ports:
      - "8000:80"
    volumes:
      - /mnt/RED_2TB/storage:/srv
      - /mnt/RED_2TB/Edu:/srv/Edu
      - /mnt/RED_2TB/docker/filebrowser/database:/database              # ← BIND-MOUNT
      - /mnt/RED_2TB/docker/filebrowser/settings.json:/config/settings.json  # ← BIND-MOUNT (файл)

✅ 2026-09-26: named volumes УБРАНЫ, данные переехали в папку. Причина — они жили внутри .ix-apps и утратились при пересоздании пула (см. пифолл 0 ниже). Теперь filebrowser.db лежит в /mnt/RED_2TB/docker/filebrowser/database/ и попадает в обычный бэкап mailru-crypt:. Проверка живьём: docker inspect filebrowser → /database = /mnt/RED_2TB/docker/filebrowser/database, /config/settings.json = путь на пуле.

Пользователи (после миграции): остался только file_admin (id=2, perm.admin=true, scope: /). Прежний admin (id=1) удалён 2026-09-26 по указанию Alex.

🔴 Пифолл 0 (ИСТОРИЧЕСКИЙ, причина всей истории): данные в named volumes внутри .ix-apps → потеряны при переносе пула

Было: БД жила в томах

filebrowser_filebrowser_db     → /mnt/.ix-apps/docker/volumes/filebrowser_filebrowser_db/_data/filebrowser.db
filebrowser_filebrowser_config → /mnt/.ix-apps/docker/volumes/filebrowser_filebrowser_config/_data/settings.json

Физически внутри .ix-apps (DockerRootDir=/mnt/.ix-apps/docker). Оба тома созданы с нуля 2026-08-24T02:04:12 — в день пересоздания пула. rsync шёл из /mnt/RED_2TB/* и .ix-apps (отдельный датасет поверх /mnt/.ix-apps) не включал → тома погибли, File Browser сгенерировал нового admin, все прежние пользователи (в т.ч. file_admin) исчезли.

Почему это НЕ косяк конфигурации: docker-compose.yml до и после переноса идентичен (/mnt/RED_2TB/docker.bak/filebrowser/docker-compose.yml == прежний). settings.json тоже тот же (130 б, Jul 27 20:00) — он пережил перенос, потому что лежал на пуле. Потерялись данные, не конфиг.

📌 Общее правило: любой сервис с docker NAMED VOLUMES теряет состояние при пересоздании пула, пока тома лежат в .ix-apps. Либо bind-mount на пул, либо включать .ix-apps в бэкап.

🔴 Пифолл 1: логин не работает, потому что пользователя нет / hideLoginButton: true

Симптом (2026-09-26): «не могу залогиниться как file_admin». Факт: в БД ровно один пользователь — "username":"admin" (id=1, perm.admin=true). file_admin никогда не создавался. Почему 403: в настройках "hideLoginButton": true → эндпоинт GET /api/login отдаёт 403 Forbidden (а не 401). Лог контейнера:

2026/09/26 08:44:02 /api/renew: 401 92.62.77.233   ← Кра́кен
2026/09/26 08:44:17 /api/login: 403 92.62.77.233   ← попытка логина, отбита

Прочие настройки из БД: authMethod: "json", signup: false, minimumPasswordLength: 12. ✅ hideLoginButton → false (2026-09-26) — кнопка логина вернулась, 403 на /api/login ушёл.

⏱️ tokenExpirationTime был 2h → поставлен 720h (30 дней), 2026-09-26. Причина смены: /api/renew отдаёт 401 (продление сессии не работает через Caddy-контур), поэтому любой разлогин был жёстким выбросом ровно через 2 часа. При 720h выброс снят. Корень (renew 401) НЕ лечен — если снова выкинет, смотреть cookie/refresh, не срок. Правка только при остановленном контейнере (пифолл 2). Бэкап: database/filebrowser.db.bak-before-token-20260926.

docker stop filebrowser
docker run --rm -v /mnt/RED_2TB/docker/filebrowser/database:/database \
  filebrowser/filebrowser:latest config set --tokenExpirationTime=720h -d /database/filebrowser.db
docker compose up -d   # из /mnt/RED_2TB/docker/filebrowser/

⚠️ CLI-флаг пишется --tokenExpirationTime; старый --hide-login-button deprecated → --hideLoginButton.

🌐 Адрес входа: docs.mallexxx.duckdns.org (Caddy-блок уже содержит header_up X-Forwarded-Proto https + X-Forwarded-Host {host} — это НЕ причина 403). ⚠️ Прямой POST /api/login с Host: localhost или Host: 192.168.2.197:8000 тоже даёт 403 — это не поломка, а сверка origin. Проверять логин только через реальный домен.

⚠️ «403 на логине» ≠ «контейнер сломан». Контейнер Up (healthy), HTTP 200 на /, порт слушает.

🔴 Пифолл 2: БД залочена — filebrowser users ls даёт Error: timeout

Bolt-БД держит живой процесс. Любая CLI-команда по живой БД падает:

docker exec filebrowser filebrowser users ls -d /database/filebrowser.db
# → Error: timeout

Правка пользователей/паролей только при ОСТАНОВЛЕННОМ контейнере. Порядок: docker stop filebrowser → правка/бэкап → docker start filebrowser. Читать содержимое живой БД можно без остановки через strings:

docker exec filebrowser sh -c "strings /database/filebrowser.db | grep -oE '\"username\":\"[^\"]*\"'"
docker exec filebrowser sh -c "strings /database/filebrowser.db | grep -A2 'authMethod'"

🔴 Пифолл 3: docker exec ... wget --header=... → bad address 'application'

Busybox-wget внутри контейнера не переваривает --header='Content-Type: application/json' через вложенный ssh-квотинг (аргумент рвётся). Для API-проб использовать printf в файл + wget --post-file или просто проверять код через wget -qS. Настройки также читаются прямо из тома (root-only для хоста truenas_admin):

docker exec filebrowser cat /config/settings.json
docker exec filebrowser cat /database/filebrowser.db   # бинарь, читать strings

🔴 Пифолл 4: docker compose up -d → permission denied на compose-файл (права после записи из root-контейнера)

Файл, записанный через docker run --rm -v ...:/dst alpine cp ..., получает -rw------- root root. truenas_admin (uid 950) не может его прочитать → compose падает:

open /mnt/RED_2TB/docker/filebrowser/docker-compose.yml: permission denied

Фикс (в root-контейнере): chmod 644 + chown 950:950 на compose и бэкап.

Папка /mnt/RED_2TB/docker/filebrowser/ = root:root — truenas_admin в неё писать не может, поэтому любая запись туда идёт через docker run --rm -v <пул>:/dst alpine ..., а не через cp/scp напрямую. Безопасный порядок для bind-mount-файлов: изнутри root-контейнера chown в 1000:1000 (для данных File Browser) или 950:950 (для файлов, которые читает truenas_admin как compose).

🔧 Рецепт миграции named volume → папка (выполнен 2026-09-26, воспроизводим)

# 1. STOP (обязательно: bolt-БД залочена)
docker stop filebrowser

# 2. Бэкап тома на пул (root-контейнер, пул примонтирован целиком)
docker run --rm \
  -v /mnt/.ix-apps/docker/volumes/filebrowser_filebrowser_db/_data:/src/db:ro \
  -v /mnt/.ix-apps/docker/volumes/filebrowser_filebrowser_config/_data:/src/cfg:ro \
  -v /mnt/RED_2TB/docker/filebrowser:/dst \
  alpine sh -c 'mkdir -p /dst/_vol_backup_$(date +%Y%m%d)/db /dst/_vol_backup_$(date +%Y%m%d)/cfg
                cp -av /src/db/. /dst/_vol_backup_$(date +%Y%m%d)/db/
                cp -av /src/cfg/. /dst/_vol_backup_$(date +%Y%m%d)/cfg/'

# 3. Данные в рабочую папку
docker run --rm -v /mnt/RED_2TB/docker/filebrowser:/dst alpine sh -c '
  mkdir -p /dst/database
  cp -av /dst/_vol_backup_*/db/filebrowser.db /dst/database/filebrowser.db
  cp -av /dst/_vol_backup_*/cfg/settings.json /dst/settings.json
  chown -R 1000:1000 /dst/database /dst/settings.json'

# 4. Правка compose на bind-mount (см. блок выше) + chmod 644 / chown 950:950
# 5. Правки пользователей/паролей — ТОЛЬКО при остановленном контейнере (см. пифолл 2)
# 6. Старт
cd /mnt/RED_2TB/docker/filebrowser && docker compose up -d

🔴 Пифолл 5: образ filebrowser — distroless, sh/bash НЕТ

docker run --rm filebrowser/filebrowser:latest sh -c "..." → unknown command "sh" for "filebrowser". Бинарь вызывается напрямую с аргументами:

# список пользователей
docker run --rm -v <db-dir>:/database filebrowser/filebrowser:latest users ls -d /database/filebrowser.db
# добавить пользователя-админа
docker run --rm -v <db-dir>:/database filebrowser/filebrowser:latest users add file_admin 'ПАРОЛЬ' --perm.admin -d /database/filebrowser.db
# удалить пользователя
docker run --rm -v <db-dir>:/database filebrowser/filebrowser:latest users rm admin -d /database/filebrowser.db
# снять скрытие кнопки логина (флаг deprecated: --hide-login-button → --hideLoginButton)
docker run --rm -v <db-dir>:/database filebrowser/filebrowser:latest config set --hide-login-button=false -d /database/filebrowser.db

⚠️ Правки из этих команд требуют остановленного контейнера (bolt-лок, пифолл 2).

✅ Приёмка 2026-09-26 (проверено живьём)

Проверка Результат
POST /api/login с file_admin + верный пароль HTTP 200 + JWT ✅
POST /api/login неверный пароль HTTP 403 ✅
POST /api/login старый admin HTTP 403 (удалён) ✅
GET /login HTTP 200 ✅
docker ps Up (healthy) ✅
docker inspect монтирование /database = /mnt/RED_2TB/docker/filebrowser/database ✅

**Артефакты миграции в /mnt/RED_2TB/docker/filebrowser/:** database/filebrowser.db, settings.json, docker-compose.yml, docker-compose.yml.bak-20260926, _vol_backup_20260926/{db,cfg}/`.

Открытые вопросы (решает Alex):

  1. file_admin имеет scope: / — видит весь корень включая /srv/Edu (у прежнего admin было .). Ограничить при необходимости.
  2. Пароль FileAdmin2026! прошёл через логи чата/ssh — сменить после первого входа.
  3. Стоит ли тем же приёмом перевести на bind-mount другие сервисы с named volumes (см. docker volume ls — там десятки хеш-имён от прежних compose-проектов).

⚠️ /mnt/RED_2TB/docker.bak/filebrowser/ — это НЕ бэкап данных. Там те же два файла (docker-compose.yml + settings.json, дата Apr 29), которые пережили перенос, потому что лежали на пуле. Томов там нет.

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_h264 → camera.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)
~~~~vnc.mallexxx.duckdns.org~~ (убран 2026-09-29)~~ ❌ УБРАН из Caddyfile (2026-09-29). Был noVNC-роут на flaresolverr:6080 для ручного решения капчи RuTracker. Гипотеза оказалась ложной (капча = симптом неверного пароля, Prowlarr логинится сам) → образ flaresolverr-vnc, порт 6080, volume и роут снесены. Caddy отключён от media_net. Подробно personal/tech/flaresolverr-taiga §Откат

✅ 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
vless-space (egress через external-подписку) https://vpn-panel.mallexxx.duckdns.org/sub/24df9391356b48ff
Формат ответа base64-список vless:// (стандарт «subscription channel»)
Settings в x-ui.db subDomain=vpn-panel.mallexxx.duckdns.org, subPort=443, subScheme=https; у каждого клиента своё поле subId (16 символов)

Разложенный 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:// больше вбивать не нужно.

Где искать «auto» по приложениям (ответ на вопрос Alex 2026-09-15 «какой клиент» — уточнение не понадобилось, докрыто здесь):

Клиент Как добавить Где авто-обновление
Happ (iOS/Android) «+» → Add subscription → вставить URL в настройках подписки, «Auto update» + интервал
v2rayN (Windows) Subscriptions → Add subscription «Sub update interval» (мин) в настройках подписки
NekoBox / sing-box (Android) Группа → Add subscription в свойствах группы, «Auto update» + интервал
Streisand (iOS) «+» → Subscription внутри подписки, «Auto update»
Xray/xray-core в КОНТЕЙНЕРЕ-КЛИЕНТЕ (vless-proxy) — ❌ не умеет. Только статический config.json; «auto» = внешний cron-скрипт (curl sub → base64 -d → собрать config → docker restart)
⚠️ Обязательное условие во всех: вставлять полный URL с /sub/<subId>, а не одиночный 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 + ротация. Ничего не менялось, ждём решения.

🔴 ПИТФОЛЛ: подмена x-ui.db при ЖИВОМ контейнере ТЕРЯЕТ панельные данные (2026-09-15)

Как было потеряно: снят x-ui.db при работающем контейнере → docker stop (панель сбросила WAL в файл) → поверх положен снятый ранее файл → запись outbound_subscriptions уничтожена.

Панель пишет в -wal; sqlite3 x-ui.db "SELECT …" снаружи показывает устаревшие данные (0 записей при живой подписке).

Правильный порядок: docker stop ДО скачивания БД. Если остановить нельзя — читать WAL через strings /mnt/RED_2TB/docker/xray-admin/x-ui.db-wal (не через sqlite3 на файле). Признак: SELECT COUNT(*) FROM outbound_subscriptions → 0, а панель запись показывает.

Восстановление: заново добавить подписку в UI (Xray → Outbound Subscriptions). Бэкапы БД старше правки пусты — URL подписки в доке не хранится.

🔴 ПИТФОЛЛ диагностики: jq показывает null для живой секции — проверять ОБА имени

Xray 26.x знает две секции observatory: observatory и burstObservatory (панель при сохранении создаёт вторую и удаляет первую). Диагностический запрос только по .observatory вернёт null, и это ложный вывод «секции нет» — секция есть, под другим ключом.

docker exec xray-admin cat /app/bin/config.json | jq -r 'keys[]'                  # ищем ЛЮБОЕ из двух
docker exec xray-admin cat /app/bin/config.json | jq -c '.burstObservatory // .observatory'

🔴 Правило: routing.balancers[].selector и observatory|burstObservatory.subjectSelector — два разных поля. Сменил префикс подписки (space- → sub1-) — меняй оба, иначе leastLoad не видит живых кандидатов и трафик молча уходит в direct, без ошибок в логе. Детали — personal/tech/xray-outbound-subscription-3xui.

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

Цель: 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/-shm → database disk image is malformed. Правильно: docker stop xray-admin → rm -f x-ui.db-wal x-ui.db-shm → SQL напрямую в /data/x-ui.db → chown 950:root → docker 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 ✅ СОЗДАН 2026-09-15, egress через подписку profilegrid.net (28 серверов sub1-*, space-balancer leastLoad + burstObservatory)
  • 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 → рестартит контейнер.
  • ⚠️ Поправка (2026-09-15): это НЕ значит, что у сервера нет авто-обновления. Разные механизмы, не путать:
    Где Что тянет Авто-обновление
    GUI-клиент (телефон/ноут) /sub/<subId> с xray-admin да, интервал в клиенте
    xray-admin (СЕРВЕР) внешнюю подписку profilegrid.net ✅ ДА — штатная outbound_subscriptions, tag_prefix=sub1-, update_interval=600
    vless-proxy (клиент-контейнер) — ❌ нет, только cron-скрипт
    Как работает серверное авто (штатный путь 3x-ui): запись в Xray → Outbound Subscriptions → панель сама раз в 600 с парсит подписку и создаёт outbound'ы sub1-01…sub1-28 → space-balancer (selector: ["sub1-"], leastLoad) подхватывает их по префиксу, т.к. балансировщик пересобирается из селектора, а не из списка. Новые серверы в подписке появляются сами, руками ничего не вбивать. Для leastLoad обязателен burstObservatory.subjectSelector: ["sub1-"] (тот же префикс!).
  • Панель: логин 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, burstObservatory ✅ (применились) Клиенты инбаунда — 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.

✅ 2026-09-23 — КАНАЛ ПРОВЕРЕН ЖИВЬЁМ, РАБОТАЕТ. Первая проверка после фикса гонки docker↔mount (2026-09-20). SOCKS xray-reverse-portal:12345 → 92.62.77.233 ≠ TrueNAS 90.189.160.148 ⇒ payload идёт через Кра́кен. Portal netstat: ::ffff:172.16.1.7:12346 ← ::ffff:92.62.77.233:32529 ESTABLISHED.

🔴 IP Кра́кена ИЗМЕНИЛСЯ: 92.62.70.41 → 92.62.77.233. Старый IP зафиксирован ниже в таблицах подписок и per-user egress — при проверках брать актуальный из живого запроса.

⚠️ xray-reverse-bridge на Кра́кене не имеет inbounds (ключи конфига: log/outbounds/routing; слушающих портов нет). Канал работает на отправку, но принять трафик от роутера бриджу нечем. План «доступ к 192.168.2.x как к локальным» — personal/plans/lan-access-via-reverse-tunnel.

⚠️ Проверка канала с TrueNAS (воспроизводимо):

ssh truenas_admin@mallexxx.duckdns.org \
  'docker run --rm --network caddy_default curlimages/curl:latest curl -s --max-time 20 \
   --socks5-hostname xray-reverse-portal:12345 https://api.ipify.org'
# ожидаем IP Кра́кена, НЕ 90.189.160.148

🔧 КОНФИГ ИЗМЕНЁН 2026-09-23 (задача «192.168.2.x как локальный»)

Файл: /mnt/RED_2TB/docker/reverse-portal/config.json (bind-mount :ro).

Что добавлено:

  1. outbound direct с settings.finalRules:[{action:"allow"}] + domainStrategy:"AsIs" (прежде был только безымянный placeholder freedom).
  2. routing-правило {"type":"field","ip":["192.168.2.0/24"],"outboundTag":"direct"} — поставлено ВЫШЕ правила {"inboundTag":["local"],"outboundTag":"reverse-out"}, иначе local его перехватил бы.
  3. log.loglevel сейчас debug (для диагностики, оставлен).

Валидация: docker run --rm -v /tmp:/etc/xray teddysun/xray:26.4.25 xray run -test -c … → Configuration OK. Портал перезапущен (docker restart), Up, канал жив (92.62.77.233).

Заливка в root-owned папку (паттерн):

docker run --rm -v /tmp:/src -v /mnt/RED_2TB/docker/reverse-portal:/dst alpine \
  sh -c "cp /src/portal-config-new.json /dst/config.json && chown 950:950 /dst/config.json"

Бэкап ДО: /mnt/RED_2TB/docker/reverse-portal/config.json.before-lanroute (плюс исторические config.json.bak-reality-vision-20260902-1142, .bak-plain-host-working-20260902-1146, .bak-flow-20260902-1140).

Локальный эталон на Mac: /Users/admin/tmp-lan-tunnel/portal-config-new.json

🔴 Сквозной проход НЕ подтверждён. Тест с самого Кра́кена дал HTTP 000 и счётчик REDIRECT-правила 0 — но это ложный негатив: локально-исходящий трафик идёт через nat OUTPUT, а не PREROUTING. Проверять только с постороннего хоста. Полное состояние и питфоллы — personal/plans/lan-access-via-reverse-tunnel.

Параметр Значение
Папка /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
  • Конфиги редактируются напрямую на NAS — docker 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 Off → Browsing On + добавлена строка BrowseLocalProtocols dnssd (бэкап cupsd.conf.pre-avahi).

✅ 2026-11-07: повторный сбой после перезагрузки TrueNAS устранён. Старый entrypoint принимал оставшийся /run/dbus/system_bus_socket за живой D-Bus и пропускал его запуск; Avahi завершался, CUPS продолжал работать без mDNS. Дополнительно виртуальные сети Docker исчерпали лимит multicast-групп (IP_ADD_MEMBERSHIP failed: No buffer space available), поэтому восстановленный Avahi не публиковал IPv4-анонс в LAN. Теперь Avahi ограничен allow-interfaces=enp3s0; новый entrypoint очищает runtime-файлы, проверяет готовность D-Bus → Avahi → CUPS и контролирует процессы, IPP и фактическую публикацию принтера в LAN. При отказе/зависании завершает контейнер, который восстанавливает restart: unless-stopped; добавлен Docker HEALTHCHECK. Обычный docker restart cups-splix теперь поддерживается. Проверены два перезапуска, аварийное завершение каждого из трёх сервисов и зависание Avahi; после каждого восстановлены IPP и mDNS на enp3s0 / 192.168.2.197:631. Подробности, бэкап и проверка печати: personal/tech/samsung-clx-216x.

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

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 /tmp → docker cp внутрь cups-splix:/tmp → docker 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»).

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