[2026-09-14] eagle: family/how-to/truenas-access.md family/how-to/truenas-rclone-backup.md family/plans/t610-backup-to-truenas.md family/plans/t610-home-automation.md

This commit is contained in:
Alexey Martemyanov
2026-09-14 20:34:14 +06:00
parent 75c7522faf
commit 68a3398b41
4 changed files with 153 additions and 38 deletions
+2
View File
@@ -90,6 +90,8 @@ docker run --rm alpine sh -c 'apk add -q openssh sshpass && sshpass -p 1316261 s
> ⚠️ **ВАЖНО (2026-09-14):** `1316261` — пароль **только от OpenWrt-роутера `192.168.2.2`**. Это **НЕ пароль от TrueNAS** (Alex: «Это не пароль от truenas»). Не использовать его для root-операций на TrueNAS. > ⚠️ **ВАЖНО (2026-09-14):** `1316261` — пароль **только от OpenWrt-роутера `192.168.2.2`**. Это **НЕ пароль от TrueNAS** (Alex: «Это не пароль от truenas»). Не использовать его для root-операций на TrueNAS.
> >
> 🔑 **Root-операции на TrueNAS делать через WebUI → System → Shell** — этот шелл работает под root, пароль не требуется. Так сделаны `mkdir -p /mnt/.ix-apps/app_configs` и `chown nas:nas /mnt/RED_2TB/backup/t610`. `truenas_admin` **не имеет passwordless sudo** (подтверждено многократно). > 🔑 **Root-операции на TrueNAS делать через WebUI → System → Shell** — этот шелл работает под root, пароль не требуется. Так сделаны `mkdir -p /mnt/.ix-apps/app_configs` и `chown nas:nas /mnt/RED_2TB/backup/t610`. `truenas_admin` **не имеет passwordless sudo** (подтверждено многократно).
>
> 🧑 **У Alex ЕСТЬ root-SSH на TrueNAS** (2026-09-14: `root@truenas[/mnt/RED_2TB/backup/t610]#`). Агент не должен предлагать ему WebUI-инструкции, если он уже сказал, что работает под root-shell. Агенту root-SSH **недоступен** — только `truenas_admin`.
> 💡 **Бэкап firewall OpenWrt перед любой правкой redirect-правил** (вошло в практику 2026-09-01): > 💡 **Бэкап firewall OpenWrt перед любой правкой redirect-правил** (вошло в практику 2026-09-01):
+3 -3
View File
@@ -48,11 +48,11 @@
| Источник | Куда класть | Статус | | Источник | Куда класть | Статус |
|---|---|---| |---|---|---|
| Конфиги **t610** (HA OS): `/config/{configuration,automations,scripts,scenes,secrets}.yaml`, `/config/.storage/`, `/config/go2rtc.yaml`, `zigbee2mqtt`, `/addons/{mbusd,modbus-bridge,ustreamer}`, `/addon_configs/{zigbee2mqtt,nodered}` | `/mnt/RED_2TB/backup/t610/` | 🔶 **план, вечер-14 (2026-09-14)**см. `[[family/plans/t610-home-automation]]` §5-кватер-К | | Конфиги **t610** (HA OS): `/config/{configuration,automations,scripts,scenes,secrets}.yaml`, `/config/.storage/`, `/config/go2rtc.yaml`, `zigbee2mqtt`, `/addons/{mbusd,modbus-bridge,ustreamer}`, `/addon_configs/{zigbee2mqtt,nodered}` | `/mnt/RED_2TB/backup/t610/` | **РАБОТАЕТ (2026-09-14)**крон TrueNAS id=3, юзер `nas`, 03:30 ежедневно, ротация 14 архивов. Детали, питфоллы, команды — `[[family/plans/t610-backup-to-truenas]]` |
**Как ходить с t610 на NAS (факт-проверка 2026-09-14):** `t610 → 192.168.2.197` **ping OK**, а вот **Mac → 192.168.2.197 ping FAIL** (прямого пути нет). То есть бэкап на сторону NAS делается от **t610**, а не от Mac. **Как работает (проверено 2026-09-14):** крон на TrueNAS от юзера **`nas`** → `ssh` на t610 (ключ `/mnt/RED_2TB/backup/t610/.ssh/id_ed25519`, ограничен `from="192.168.2.197"`) → `tar czf -` собирается НА t610 → архив `t610-config-<ts>.tar.gz` (~605 КБ, 111 файлов) в `/mnt/RED_2TB/backup/t610/` → датасет `backup` целиком уходит в `mailru-crypt:` по воскресеньям. **Лог:** `backup.log` в той же папке.
⚠️ Запись в `/mnt/RED_2TB/backup/` требует **root**; у `truenas_admin` **нет passwordless sudo**. Варианты: root-ключ / отдельный share / стейджинг в `/tmp/` + подмена Alex'ом. ⚠️ **Важно про права (обновлено 2026-09-14):** запись в `/mnt/RED_2TB/backup/` требует root (было `root:root 775`), **но** целевой датасет `backup/t610``nas:nas 770`, поэтому сам бэкап пишется **без root**. `truenas_admin` добавлен в группу `nas`. Root нужен был только для `chown nas:nas /mnt/RED_2TB/backup/t610` (один раз). ⚠️ **Пароль `1316261` — НЕ от TrueNAS** (он от OpenWrt-роутера), root-операции — через System → Shell.
- **rclone remotes на Mac отсутствуют** (`rclone listremotes` пуст) — конфиг с `mailru-crypt` живёт **только на TrueNAS**. Бэкап проектировать на стороне NAS, не Mac. - **rclone remotes на Mac отсутствуют** (`rclone listremotes` пуст) — конфиг с `mailru-crypt` живёт **только на TrueNAS**. Бэкап проектировать на стороне NAS, не Mac.
- **Точки входа:** `ssh truenas_admin@mallexxx.duckdns.org` (внешний), `192.168.2.197` (LAN, только с t610). - **Точки входа:** `ssh truenas_admin@mallexxx.duckdns.org` (внешний), `192.168.2.197` (LAN, только с t610).
+147 -34
View File
@@ -4,7 +4,7 @@ created: 2026-09-14
updated: 2026-09-14 updated: 2026-09-14
type: tech type: tech
namespace: family namespace: family
tags: [truenas, t610, backup, smb, ssh, cron, ha-os] tags: [truenas, t610, backup, smb, ssh, cron, ha-os, done]
related: related:
- "[[family/plans/t610-home-automation]]" - "[[family/plans/t610-home-automation]]"
- "[[family/how-to/truenas-access]]" - "[[family/how-to/truenas-access]]"
@@ -43,7 +43,17 @@ Mail.ru Cloud (зашифровано)
4. **SMB-шара `t610`** — не для доставки (HA OS не умеет SMB-пуш), а **для ручного доступа Alex** к бэкапам с Mac/телефона без ssh. 4. **SMB-шара `t610`** — не для доставки (HA OS не умеет SMB-пуш), а **для ручного доступа Alex** к бэкапам с Mac/телефона без ssh.
5. **Ключ ограничен** на стороне t610: `from="192.168.2.197"` + `no-port-forwarding,no-pty,no-X11-forwarding,no-agent-forwarding`. Т.е. даже при утечке — только стянуть архив, шелла нет. 5. **Ключ ограничен** на стороне t610: `from="192.168.2.197"` + `no-port-forwarding,no-pty,no-X11-forwarding,no-agent-forwarding`. Т.е. даже при утечке — только стянуть архив, шелла нет.
## Что сделано (2026-09-14) ## ✅ СТАТУС: РАБОТАЕТ (проверено живым прогоном 2026-09-14)
```
cron TrueNAS (юзер nas, 03:30 ежедневно)
└─ /mnt/RED_2TB/backup/t610/backup-t610.sh
└─ ssh t610-backup "tar czf - <14 путей>" → 605 КБ архив
└─ /mnt/RED_2TB/backup/t610/t610-config-<ts>.tar.gz (ротация 14)
└─ rclone (вс 03:00, контейнер) → mailru-crypt: (Mail.ru, шифровано)
```
### Что сделано
| # | Шаг | Статус | Детали | | # | Шаг | Статус | Детали |
|---|-----|--------|--------| |---|-----|--------|--------|
@@ -52,19 +62,49 @@ Mail.ru Cloud (зашифровано)
| 3 | SMB-шара | ✅ | `id=3 name=t610 path=/mnt/RED_2TB/backup/t610 enabled=true ro=false` | | 3 | SMB-шара | ✅ | `id=3 name=t610 path=/mnt/RED_2TB/backup/t610 enabled=true ro=false` |
| 4 | ssh-ключ для pull | ✅ | Создан на Mac: `~/tmp-t610/backup-key/t610_backup_ed25519` (+`.pub`), ed25519, без пароля, comment `t610-backup-pull`, fingerprint `SHA256:PKDB/sTjM8WFitIjSG+vT27x1TOY3F2Vi6y8YFwK5wo` | | 4 | ssh-ключ для pull | ✅ | Создан на Mac: `~/tmp-t610/backup-key/t610_backup_ed25519` (+`.pub`), ed25519, без пароля, comment `t610-backup-pull`, fingerprint `SHA256:PKDB/sTjM8WFitIjSG+vT27x1TOY3F2Vi6y8YFwK5wo` |
| 5 | Публичный ключ на t610 | ✅ | `/root/.ssh/authorized_keys` (+1 строка, было 1 — ключ Alex). Бэкап: `authorized_keys.bak-20260914-210532` | | 5 | Публичный ключ на t610 | ✅ | `/root/.ssh/authorized_keys` (+1 строка, было 1 — ключ Alex). Бэкап: `authorized_keys.bak-20260914-210532` |
| 6 | Приватный ключ на TrueNAS | ✅ | `/mnt/RED_2TB/storage/nas/.ssh/id_ed25519` (+ `config` с хостом-алиасом `t610-backup`), права `nas:nas 600` | | 6 | Приватный ключ на TrueNAS | ✅ | **`/mnt/RED_2TB/backup/t610/.ssh/id_ed25519`** (+ `config` с алиасом `t610-backup`), `nas:nas 600`. ⚠️ Итоговое место — **внутри `backup/t610`**, НЕ в `~nas/.ssh` (см. питфолл №9) |
| 7 | Скрипт бэкапа | | Не написан | | 7 | Скрипт бэкапа | | `/mnt/RED_2TB/backup/t610/backup-t610.sh` (v3, `nas:nas 755`) |
| 8 | Крон-задача под `nas` | | Не создана (`midclt call cronjob.create`, сейчас cron-задач на TrueNAS **нет**) | | 8 | Крон-задача под `nas` | | `cronjob` **id=3**, user=`nas`, `30 3 * * *`, enabled=true |
| 9 | Живой прогон + проверка архива | | Не делался | | 9 | Живой прогон + проверка архива | | 2 прогона: `OK ... (605504 bytes)`, `OK ... (605873 bytes)`, `.err` пустой |
| 10 | Проверка состава архива | ✅ | **111 файлов**; ключевые на месте: `configuration.yaml`, `automations.yaml`, `go2rtc.yaml`, `secrets.yaml`, `.storage/http` (фикс `trusted_proxies`), `addons/modbus-bridge/data/config.template.tmpl` (реле slave 104), `nodered/flows.json` |
| 11 | Выход в облако | ✅ | `run_sync "backup" /data/backup "mailru-crypt:"` в `backup.sh`; контейнер `rclone``Up 5 days`; правок не требовалось |
**Путь для архива на TrueNAS:** `/mnt/RED_2TB/backup/t610/` (пока пусто). **Путь для архивов на TrueNAS:** `/mnt/RED_2TB/backup/t610/t610-config-<YYYYmmdd-HHMMSS>.tar.gz`, лог — `backup.log` рядом.
### Как проверять (без ожидания 03:30)
```bash
# лог + список архивов
ssh truenas_admin@mallexxx.duckdns.org 'cat /mnt/RED_2TB/backup/t610/backup.log; ls -la /mnt/RED_2TB/backup/t610/'
# статус задачи
ssh truenas_admin@mallexxx.duckdns.org 'midclt call cronjob.query "[[\"id\",\"=\",3]]" | jq -r ".[] | {id,user,enabled,command,schedule}"'
```
> ⚠️ **НЕ проверять через `midclt call cronjob.run`** — даёт ложный `exit 137`/`143`. См. питфолл №10.
### ⚠️ НЕ ЗАКРЫТО — что ещё стоит добавить в архив (обсуждалось 2026-09-14, вечер-15)
Alex задал вопрос: «что НЕ входит в архив, но что мы задолбаемся восстанавливать?». Ответ (проверено на живом t610):
| # | Что | Где лежит | Почему критично |
|---|-----|-----------|-----------------|
| 1 | 🔴 **Опции всех 11 аддонов** | `/data/options.json` внутри контейнера аддона + Supervisor API `/addons/<slug>/options` | mbusd (привязка `by-path`, гнездо 4), modbus-bridge (`usb-0:3`, **пароль mosquitto `mqtt1z3$`**, ZONT host/slave), zigbee2mqtt (**`network_key`** + порт `/dev/ttyACM0`), Node-RED (**крипто-секрет `0ce08a59caa2077e607b5f34044af0b0c`**, пароль админки), Mosquitto (user/pass), Terminal&SSH (`authorized_keys`) |
| 2 | 🔴 **Zigbee `network_key`** | в **опциях** аддона zigbee2mqtt (не в `/config/zigbee2mqtt/`) | `coordinator_backup.json` в архиве есть, но без `network_key` сеть **не поднять** — все устройства перепаривать |
| 3 | 🔴 **Node-RED `flows_cred.json`** | `/addon_configs/a0d7b954_nodered/` (не читается обычным листингом; секрет `$` — в опциях) | без крипто-секрета креды не расшифруются → **все ноды HA подключать заново** |
| 4 | 🟡 `home-assistant_v2.db` (9.2M) + `-wal` (4.1M) | `/config/` | история сенсоров, **статистика энергии**, климат. Бэкапить на живой системе рискованно (неконсистентность) — через SQLite backup API |
| 5 | 🟡 Файлы `*.bak-*` | `/config/` (6 config + 4 automations) | точки отката миграции, размер мизерный |
**Полный список аддонов t610 (проверено через Supervisor API):** `core_ssh`, `core_mosquitto`, `a0d7b954_nodered`, `core_samba` (stopped), `core_configurator`, `45df7312_zigbee2mqtt`, `local_mbusd`, `local_modbus-bridge`, `local_ustreamer` (stopped), `a889bffc_go2rtc` (stopped), `a889bffc_go2rtc-hardware`.
**Не нужно бэкапить:** `/config/.cache`, `deps`, `tts`, `.cloud` (пустые/кеш), `.HA_VERSION`, `home-assistant_v2.db-shm`.
**Решение (предложено, ожидает ответа Alex):** добавить в `backup-t610.sh` выгрузку опций аддонов через Supervisor API в JSON перед `tar`. Целевой размер архива ~10–15 МБ.
## Ключевые питфоллы (найдены в этой сессии) ## Ключевые питфоллы (найдены в этой сессии)
### 1. 🔴 `from="192.168.2.197"` — Mac НЕ подходит для проверки ключа ### 1. 🔴 `from="192.168.2.197"` — Mac НЕ подходит для проверки ключа
Mac заходит на t610 как **`192.168.2.157`** (через NAT Rasputin), а не как `.197`. Поэтому `ssh -i <ключ> root@192.168.2.176` **с Mac всегда даёт `Permission denied (publickey)`** — это **правильное поведение** ограничения, а не поломка ключа. Проверять pull-ключ **только с TrueNAS**: Mac заходит на t610 как **`192.168.2.157`** (через NAT Rasputin), а не как `.197`. Поэтому `ssh -i <ключ> root@192.168.2.176` **с Mac всегда даёт `Permission denied (publickey)`** — это **правильное поведение** ограничения, а не поломка ключа. Проверять pull-ключ **только с TrueNAS** (путь к конфигу — итоговый, см. питфолл №9):
```bash ```bash
ssh -F /mnt/RED_2TB/storage/nas/.ssh/config t610-backup 'echo ok' ssh -F /mnt/RED_2TB/backup/t610/.ssh/config t610-backup 'echo ok'
``` ```
> ⚠️ Это тот же питфолл `.157` = NAT Rasputin, что уже задокументирован для логов HA. > ⚠️ Это тот же питфолл `.157` = NAT Rasputin, что уже задокументирован для логов HA.
@@ -96,62 +136,135 @@ setfacl -m user:truenas_admin:rwx /mnt/RED_2TB/backup/t610
### 6. `zfs`/`zpool` не в PATH у `truenas_admin` ### 6. `zfs`/`zpool` не в PATH у `truenas_admin`
`zfs list` → пусто/`command not found`. Вызывать по абсолютному пути: **`/sbin/zfs`**, **`/sbin/zpool`**. (Иначе можно ошибочно решить, что датасетов нет.) `zfs list` → пусто/`command not found`. Вызывать по абсолютному пути: **`/sbin/zfs`**, **`/sbin/zpool`**. (Иначе можно ошибочно решить, что датасетов нет.)
### 7. `truenas_admin` не может писать в `~nas` — и `.ssh` надо чинить chown'ом ### 7. `truenas_admin` не может писать в `~nas` — итог: ключ держим в `backup/t610/.ssh` (см. №9)
`~nas` = `/mnt/RED_2TB/storage/nas` (`drwxrwx--- truenas_admin`). `truenas_admin` файлы туда **положить может**, но создаёт их владельцем `truenas_admin``nas` их не прочитает. Поэтому после укладки ключа обязателен `chown -R nas:nas ~nas/.ssh`. `~nas` = `/mnt/RED_2TB/storage/nas`. Промежуточная попытка класть ключ туда **провалилась** (см. №9) — итоговое место ключа: **`/mnt/RED_2TB/backup/t610/.ssh/`**.
### 8. Пароль `1316261` — ❌ НЕ от TrueNAS ### 8. Пароль `1316261` — ❌ НЕ от TrueNAS
В доке `[[family/how-to/truenas-access]]` строка «Пароль root: `1316261`» **ошибочна** для TrueNAS. Alex: «Это не пароль от truenas». `1316261` — пароль от OpenWrt-роутера `192.168.2.2` (там он и правильный). **Для TrueNAS root-операций использовать WebUI → System → Shell** (работает под root, пароль не нужен). В доке `[[family/how-to/truenas-access]]` строка «Пароль root: `1316261`» **ошибочна** для TrueNAS. Alex: «Это не пароль от truenas». `1316261` — пароль от OpenWrt-роутера `192.168.2.2` (там он и правильный). **Для TrueNAS root-операций использовать WebUI → System → Shell** (работает под root, пароль не нужен).
> 📌 Alex работает под root по SSH сам — **не предлагать ему WebUI-инструкции**, если он уже сказал, что у него есть root-shell.
## Команды (для воспроизведения) ### 9. 🔴 Ключ класть в `backup/t610/.ssh`, НЕ в `~nas/.ssh` — родительский `storage/` непроходим для `nas`
**Симптом:** `Can't open user config file /mnt/RED_2TB/storage/nas/.ssh/config: Permission denied` — при том что сам `.ssh` был `nas:nas 700`.
**Причина:** `nas` не может пройти **сквозь родителей**:
```
/mnt/RED_2TB/storage drwxr-x--- truenas_admin:truenas_admin ← nas не владелец, группы хватает только на r-x
/mnt/RED_2TB/storage/nas drwxrwx--- truenas_admin:truenas_admin ← nas не владелец и не в группе → нет x
/mnt/RED_2TB/storage/nas/.ssh drwx------ nas:nas ← сам в порядке, но путь закрыт
```
`truenas_admin`**не владелец** `~nas` (после chown), а группа имеет только `r-x`**создавать там файлы нельзя** (`mkdir: Permission denied`).
**Решение (root НЕ нужен):** `/mnt/RED_2TB/backup/t610``nas:nas 770`, группа имеет `rwx`, `truenas_admin` в группе `nas` → пишет свободно. Ключ и `config` кладутся туда, затем `chown nas:nas` (работает **без root**, т.к. `truenas_admin` — владелец созданных файлов):
```bash
mkdir -p /mnt/RED_2TB/backup/t610/.ssh
cp /tmp/bk_key /mnt/RED_2TB/backup/t610/.ssh/id_ed25519
# ... config ...
chown nas:nas /mnt/RED_2TB/backup/t610/.ssh/{config,id_ed25519} # ← БЕЗ root, работает
```
> 💡 **Урок:** `chown nas:nas` на **свои** файлы проходит без root. Root нужен только для чужих. Прежде чем просить Alex'а — проверить `ls -ld` по всей цепочке родителей и `touch` на запись.
### 10. 🔴 `midclt call cronjob.run` даёт ЛОЖНЫЙ `exit 137`/`exit 143` — не признак поломки скрипта
**Симптом:** задача падает за ~1 сек с `CronTask "..." exited with 137 (non-zero) exit status` — хотя скрипт рабочий.
**Причина:** middleware прибивает таск (SIGKILL=137 / SIGTERM=143), когда родительский job `cronjob.run` завершается раньше дочернего процесса. Это баг API-пути, а не скрипта.
**Как отличить:** смотреть **несколько** job'ов и **файловый лог скрипта**. Реальные ошибки скрипта видны как его собственные коды (`exit 2`, `exit 3`) + запись в `backup.log`/`.err`.
**Правильная проверка:** ставить задачу на `* * * * *`, **ждать реального срабатывания** и смотреть появившийся архив, потом вернуть расписание:
```bash
midclt call cronjob.update 3 '{"schedule":{"minute":"30","hour":"3","dom":"*","month":"*","dow":"*"}}'
```
> ⚠️ Не «проверять» циклом `sleep` вслепую — узнавать по факту появления файла/записи в логе.
### 11. 🔴 Список путей для `tar` через ssh: не передавать многострочной переменной
**Симптом:** `tar: empty archive` + `bash: line N: config/configuration.yaml: Permission denied` (пути выполняются как команды).
**Причина:** многострочная `$FILES`, подставленная в ssh-команду, интерпретируется **на удалённой стороне** как отдельные команды.
**Фикс:** список путей — **одной строкой прямо в ssh-команде**:
```sh
ssh -F "$SSHCFG" "$SSHHOST" 'tar czf - -C / config/configuration.yaml config/automations.yaml ...' > "$OUT"
```
### 12. `scp` поверх чужого файла не работает, но `mv` в групповом `rwx`-каталоге — работает
`scp` даёт `Permission denied` при перезаписи файла, принадлежащего `nas`. Обход: положить под новым именем и сделать `mv` (каталог `770` даёт группе `rwx`). ⚠️ После `mv` владелец/права **сбрасываются** на копирующего → обязателен `chmod 755` + `chown nas:nas`.
### 13. `cronjob.run` вызывается кроном как `midclt call cronjob.run <id> true` — задачи от `nas` работают
Проверено: `/etc/cron.d/middlewared` содержит `* * * * * root ... midclt call cronjob.run 2 true`. Системный `cron -f` + `busybox crond -f` живут. Задачи от `nas` **выполняются штатно** (job state=SUCCESS, файлы появляются) — «крон не работает» было ложной тревогой от проверки файла до первой минуты.
### 14. `set -u` + `exit` в циклах на zsh-стороне ломает проверки
Проверки через `ssh ... 'ls /path/*.tar.gz'` на **zsh**-цели дают `zsh:1: no matches found` и рвут цикл (скрипт выходит до `sleep`). Использовать `bash -c` на удалённой стороне или `test -f` / `ls -1 ... 2>/dev/null`.
## Команды (итоговые, воспроизведение)
```bash ```bash
# ─── Создание ключа (Mac) ─── # ─── 1. Создание ключа (Mac) ───
ssh-keygen -t ed25519 -N '' -C 't610-backup-pull' -f ~/tmp-t610/backup-key/t610_backup_ed25519 ssh-keygen -t ed25519 -N '' -C 't610-backup-pull' -f ~/tmp-t610/backup-key/t610_backup_ed25519
# fingerprint: SHA256:PKDB/sTjM8WFitIjSG+vT27x1TOY3F2Vi6y8YFwK5wo
# ─── Публичный ключ на t610 (с ограничениями) ─── # ─── 2. Публичный ключ на t610 (с ограничениями по IP и без шелла) ───
KEYBODY=$(awk '{print $2}' ~/tmp-t610/backup-key/t610_backup_ed25519.pub) KEYBODY=$(awk '{print $2}' ~/tmp-t610/backup-key/t610_backup_ed25519.pub)
ENTRY="from=\"192.168.2.197\",no-port-forwarding,no-pty,no-X11-forwarding,no-agent-forwarding ssh-ed25519 ${KEYBODY} t610-backup-pull" ENTRY="from=\"192.168.2.197\",no-port-forwarding,no-pty,no-X11-forwarding,no-agent-forwarding ssh-ed25519 ${KEYBODY} t610-backup-pull"
ssh root@192.168.2.176 'cp -a /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bak-$(date +%Y%m%d-%H%M%S)' ssh root@192.168.2.176 'cp -a /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bak-$(date +%Y%m%d-%H%M%S)'
printf '%s\n' "$ENTRY" | ssh root@192.168.2.176 'cat >> /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys' printf '%s\n' "$ENTRY" | ssh root@192.168.2.176 'cat >> /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys'
# ─── Приватный ключ на TrueNAS в ~nas/.ssh ─── # ─── 3. Приватный ключ на TrueNAS в backup/t610/.ssh (НЕ в ~nas/.ssh — см. питфолл 9) ───
scp ~/tmp-t610/backup-key/t610_backup_ed25519 truenas_admin@mallexxx.duckdns.org:/tmp/ scp ~/tmp-t610/backup-key/t610_backup_ed25519 truenas_admin@mallexxx.duckdns.org:/tmp/bk_key
ssh truenas_admin@mallexxx.duckdns.org ' ssh truenas_admin@mallexxx.duckdns.org '
cp /tmp/t610_backup_ed25519 /mnt/RED_2TB/storage/nas/.ssh/id_ed25519 mkdir -p /mnt/RED_2TB/backup/t610/.ssh
cat > /mnt/RED_2TB/storage/nas/.ssh/config <<EOF cp /tmp/bk_key /mnt/RED_2TB/backup/t610/.ssh/id_ed25519
chmod 600 /mnt/RED_2TB/backup/t610/.ssh/id_ed25519
cat > /mnt/RED_2TB/backup/t610/.ssh/config <<EOF
Host t610-backup Host t610-backup
HostName 192.168.2.176 HostName 192.168.2.176
User root User root
Port 22 Port 22
IdentityFile /mnt/RED_2TB/storage/nas/.ssh/id_ed25519 IdentityFile /mnt/RED_2TB/backup/t610/.ssh/id_ed25519
IdentitiesOnly yes IdentitiesOnly yes
StrictHostKeyChecking no StrictHostKeyChecking no
EOF' EOF
chmod 600 /mnt/RED_2TB/backup/t610/.ssh/config
chown nas:nas /mnt/RED_2TB/backup/t610/.ssh /mnt/RED_2TB/backup/t610/.ssh/config /mnt/RED_2TB/backup/t610/.ssh/id_ed25519
'
# ─── Под ROOT (WebUI → System → Shell) ─── # ─── 4. Под ROOT (ТОЛЬКО этот шаг требует root) ───
mkdir -p /mnt/.ix-apps/app_configs mkdir -p /mnt/.ix-apps/app_configs # лечит UI «Failed to load datasets»
chown nas:nas /mnt/RED_2TB/backup/t610 && chmod 770 /mnt/RED_2TB/backup/t610 chown nas:nas /mnt/RED_2TB/backup/t610 && chmod 770 /mnt/RED_2TB/backup/t610
chown -R nas:nas /mnt/RED_2TB/storage/nas/.ssh && chmod 700 /mnt/RED_2TB/storage/nas/.ssh \ groupmod -n nas -m truenas_admin 2>/dev/null || usermod -a -G nas truenas_admin # truenas_admin в группу nas
&& chmod 600 /mnt/RED_2TB/storage/nas/.ssh/id_ed25519 /mnt/RED_2TB/storage/nas/.ssh/config
# ─── SMB-шара (от truenas_admin, midclt) ─── # ─── 5. SMB-шара (от truenas_admin, midclt) ───
midclt call sharing.smb.query > /mnt/RED_2TB/storage/shares-before-$(date +%Y%m%d-%H%M%S).json # ДАМП ПЕРЕД
midclt call sharing.smb.create '{"purpose":"DEFAULT_SHARE","path":"/mnt/RED_2TB/backup/t610", midclt call sharing.smb.create '{"purpose":"DEFAULT_SHARE","path":"/mnt/RED_2TB/backup/t610",
"name":"t610","comment":"Backup t610 (HA OS) configs","ro":false,"browsable":true, "name":"t610","comment":"Backup t610 (HA OS) configs","ro":false,"browsable":true,
"guestok":false,"timemachine":false,"enabled":true}' "guestok":false,"timemachine":false,"enabled":true}'
# ─── Дамп шар ПЕРЕД правкой (обязательно) ─── # ─── 6. Скрипт бэкапа (v3) + права ───
midclt call sharing.smb.query > /mnt/RED_2TB/storage/shares-before-$(date +%Y%m%d-%H%M%S).json scp ~/tmp-t610/backup-t610-v3.sh truenas_admin@mallexxx.duckdns.org:/mnt/RED_2TB/backup/t610/backup-t610.sh
ssh truenas_admin@mallexxx.duckdns.org '
chmod 755 /mnt/RED_2TB/backup/t610/backup-t610.sh
chown nas:nas /mnt/RED_2TB/backup/t610/backup-t610.sh'
# ─── Проверка pull-ключа — ТОЛЬКО С TrueNAS ─── # ─── 7. Крон-задача (id=3, юзер nas, 03:30 ежедневно) ───
ssh -F /mnt/RED_2TB/storage/nas/.ssh/config t610-backup 'echo ok' midclt call cronjob.create '{"user":"nas","command":"/mnt/RED_2TB/backup/t610/backup-t610.sh",
"description":"Backup t610 HA configs","enabled":true,
"schedule":{"minute":"30","hour":"3","dom":"*","month":"*","dow":"*"},
"stdout":false,"stderr":false}'
# ─── 8. Проверка pull-ключа — ТОЛЬКО С TrueNAS ───
ssh -F /mnt/RED_2TB/backup/t610/.ssh/config t610-backup 'echo ok'
``` ```
## Состав бэкапа t610 (план) ## Состав бэкапа t610 (✅ фактический — 111 файлов, ~605 КБ)
Из `/config`: `configuration.yaml`, `automations.yaml`, `scripts.yaml`, `scenes.yaml`, `secrets.yaml`, `.storage/` (**без** `home-assistant_v2.db*` — это большая БД), `go2rtc.yaml`, `zigbee2mqtt/`. Из `/config`: `configuration.yaml`, `automations.yaml`, `scripts.yaml`, `scenes.yaml`, `secrets.yaml`, `.storage/` (**без** `home-assistant_v2.db*`), `go2rtc.yaml`, `zigbee2mqtt/`, `www/`.
Плюс `/addons/{mbusd,modbus-bridge,ustreamer}` (код + `data/config.template.tmpl` там правка реле slave 104), `/addon_configs/{zigbee2mqtt,nodered}` (flows/settings). Плюс `/addons/{mbusd,modbus-bridge,ustreamer}` (код + `data/config.template.tmpl` — правка реле slave 104), `/addon_configs/{45df7312_zigbee2mqtt,a0d7b954_nodered}` (flows/settings).
Плюс локально `Caddyfile` (root-owned, лежит на Mac в `~/tmp-caddy/Caddyfile.new`). **Ротация:** `KEEP=14` архивов (`t610-config-<ts>.tar.gz`).
**Ротация:** хранить N последних архивов (N согласовать). > ⚠️ НЕ входит (и стоит добавить): **опции аддонов**, `network_key` Zigbee, `flows_cred.json`, `home-assistant_v2.db`. Детали — раздел «НЕ ЗАКРЫТО» выше.
### Скрипт (суть)
```sh
DEST=/mnt/RED_2TB/backup/t610 ; SSHCFG=$DEST/.ssh/config ; SSHHOST=t610-backup ; KEEP=14
# tar собирается НА t610, пути — ОДНОЙ СТРОКОЙ (питфолл 11)
ssh -F "$SSHCFG" -o BatchMode=yes -o ConnectTimeout=15 "$SSHHOST" \
'tar czf - -C / config/configuration.yaml config/automations.yaml ... ' > "$OUT" 2> "$DEST/.err"
# проверка размера <1024 → .BAD + exit 2 ; ssh-ошибка → exit 3 ; ротация до KEEP
```
Скрипт на Mac (рабочие копии): `~/tmp-t610/backup-t610-v3.sh`, `~/tmp-t610/backup-t610.sh`.
Бэкап-ключ на Mac: `~/tmp-t610/backup-key/t610_backup_ed25519`. Скрипты: `mk_backup_key.sh`, `add_backup_key_t610.sh`, `push_backup_key_truenas.sh`, `move_key_to_backup.sh`, `cleanup_backup.sh`, `phase1_diag.sh`, `phase2_key.sh`, `wait_archive.sh`.
## Связанный синк в git (сделан в этой же сессии) ## Связанный синк в git (сделан в этой же сессии)
+1 -1
View File
@@ -2026,7 +2026,7 @@ curl -s -X POST -H "$HDR" -H "Content-Type: application/json" \
| ~~**B2**~~ | ~~**Node-RED наружу** — выставить порт аддона и поправить Caddy~~ | — | **✅ СНЯТО (2026-09-14 вечер-7):** решение Alex — «оставляем так». Node-RED доступен через **ingress** HA (`http://192.168.2.176/api/hassio_ingress/<token>/`), наружу не выпускается. Домен `nodered.*` не используется. См. §5-кватер-Г и `[[family/how-to/nodered-ventilation]]` | | ~~**B2**~~ | ~~**Node-RED наружу** — выставить порт аддона и поправить Caddy~~ | — | **✅ СНЯТО (2026-09-14 вечер-7):** решение Alex — «оставляем так». Node-RED доступен через **ingress** HA (`http://192.168.2.176/api/hassio_ingress/<token>/`), наружу не выпускается. Домен `nodered.*` не используется. См. §5-кватер-Г и `[[family/how-to/nodered-ventilation]]` |
| ~~**B3**~~ | ~~**Этап 4, остаток:** GPON-редирект → t610, ZONT MQTT → t610~~ | — | **✅ ВЫПОЛНЕНО (факт-проверка 2026-09-14):** роутер `192.168.2.2``firewall.@redirect[0]` (name=MQTT, src_dport=1883) `dest_ip=192.168.2.176`, `firewall.@rule[3]` (allow-1883) `dest_ip=192.168.2.176`. **Отдельного «GPON-роутера» нет**`192.168.0.10` это `wan`-интерфейс самого роутера `192.168.2.2` (§5-кватер). Остаётся `redirect[1]` HomeAssistant `8123``.197` (проверить, нужен ли) | | ~~**B3**~~ | ~~**Этап 4, остаток:** GPON-редирект → t610, ZONT MQTT → t610~~ | — | **✅ ВЫПОЛНЕНО (факт-проверка 2026-09-14):** роутер `192.168.2.2``firewall.@redirect[0]` (name=MQTT, src_dport=1883) `dest_ip=192.168.2.176`, `firewall.@rule[3]` (allow-1883) `dest_ip=192.168.2.176`. **Отдельного «GPON-роутера» нет**`192.168.0.10` это `wan`-интерфейс самого роутера `192.168.2.2` (§5-кватер). Остаётся `redirect[1]` HomeAssistant `8123``.197` (проверить, нужен ли) |
| ~~A2~~ | ~~**№7**: Static IP для t610~~ | — | **✅ ВЫПОЛНЕНО 2026-09-14 (вечер-8, §5-кватер-И-1):** на роутере `192.168.2.2` создана static-привязка `dhcp.@host[1]` = `t610` / MAC `9c:8e:99:ef:3f:c5` / `192.168.2.176``uci commit dhcp` + `dnsmasq reload`. Проверено: `ping` OK, HA → HTTP 200. Бэкап `/root/dhcp.bak-20260914-104152` | | ~~A2~~ | ~~**№7**: Static IP для t610~~ | — | **✅ ВЫПОЛНЕНО 2026-09-14 (вечер-8, §5-кватер-И-1):** на роутере `192.168.2.2` создана static-привязка `dhcp.@host[1]` = `t610` / MAC `9c:8e:99:ef:3f:c5` / `192.168.2.176``uci commit dhcp` + `dnsmasq reload`. Проверено: `ping` OK, HA → HTTP 200. Бэкап `/root/dhcp.bak-20260914-104152` |
| A3 | **№8**: Бэкап конфигов t610 | 🔶 почти готов | ① **✅ git-синк СДЕЛАН 2026-09-14:** коммит `9d31118` запушен в Gitea (SHA local == remote) — `configuration.yaml`, `automations.yaml`, **новый** `homeassistant/go2rtc.yaml`, `config.yml`. ② **🔄 автобэкап на TrueNAS (выбран вариант B — pull с TrueNAS):** датасет `/mnt/RED_2TB/backup/t610` (`nas:nas` 770), SMB-шара `t610` (id=3), ssh-ключ pull разложен ✅ (t610 `authorized_keys` + `~nas/.ssh/`); **осталось: скрипт + крон под `nas` + живой прогон.** Полный план, команды и 8 питфоллов — **[[family/plans/t610-backup-to-truenas]]**. Прошлый `tar`-бэкап `~/tmp-t610/backups/config-t610-20260914-115034.tar.gz` (88 КБ) **устарел** (до камеры/реле/rotate) | | ~~A3~~ | ~~**№8**: Бэкап конфигов t610~~ | — | **✅✅ ВЫПОЛНЕНО 2026-09-14 (вечер-15).** ① **git-синк:** коммит `9d31118` в Gitea (SHA local == remote) — `configuration.yaml`, `automations.yaml`, **новый** `homeassistant/go2rtc.yaml`, `config.yml`. ② **автобэкап на TrueNAS (вариант B — pull с TrueNAS):** датасет `/mnt/RED_2TB/backup/t610` (`nas:nas` 770), SMB-шара `t610` (id=3), ssh-ключ в `/mnt/RED_2TB/backup/t610/.ssh/` (ограничен `from="192.168.2.197"`), скрипт `backup-t610.sh` (v3), **крон id=3 юзер `nas` 03:30 ежедневно**, ротация 14. **Живой прогон:** 2 архива `t610-config-*.tar.gz` по ~605 КБ, **111 файлов**. В Mail.ru уезжает автоматически (`backup` ⊂ rclone `backup.sh`). **Полностью — `[[family/plans/t610-backup-to-truenas]]`.** ⚠️ Не входит (кандидаты): опции аддонов, `network_key` Zigbee, `flows_cred.json`, `home-assistant_v2.db` | ✅ закрыто |гон.** Полный план, команды и 8 питфоллов — **[[family/plans/t610-backup-to-truenas]]**. Прошлый `tar`-бэкап `~/tmp-t610/backups/config-t610-20260914-115034.tar.gz` (88 КБ) **устарел** (до камеры/реле/rotate) |
| ~~A4~~ | ~~**Ночной свет душевой**: триггер на падение освещённости~~ | — | **✅ ВЫПОЛНЕНО 2026-09-14 (вечер-8, §5-кватер-И-2):** в automation `1771997851260` добавлен триггер `illuminance below:8` + условие `is_occupied`. Проверено через API: `triggers`=2, `conditions`=2 | | ~~A4~~ | ~~**Ночной свет душевой**: триггер на падение освещённости~~ | — | **✅ ВЫПОЛНЕНО 2026-09-14 (вечер-8, §5-кватер-И-2):** в automation `1771997851260` добавлен триггер `illuminance below:8` + условие `is_occupied`. Проверено через API: `triggers`=2, `conditions`=2 |
| ~~**A5**~~ | ~~**Камера**: USB-вебка Logitech `046d:0825` на t610 → завести в HA~~ | — | **⚠️ ПЕРЕДЕЛАНО 2026-09-14 (вечер-11).** Сначала (вечер-9) завели через `camera: platform: ffmpeg`**отвергнуто** (`Resource busy`, нет `unique_id`). **Итог вечер-11:** аддон `local_ustreamer` + Generic Camera → `camera.192_168_2_176`, зона `kotelnaia`, `unique_id` ✅. Детали — §5-кватер-И-5 | | ~~**A5**~~ | ~~**Камера**: USB-вебка Logitech `046d:0825` на t610 → завести в HA~~ | — | **⚠️ ПЕРЕДЕЛАНО 2026-09-14 (вечер-11).** Сначала (вечер-9) завели через `camera: platform: ffmpeg`**отвергнуто** (`Resource busy`, нет `unique_id`). **Итог вечер-11:** аддон `local_ustreamer` + Generic Camera → `camera.192_168_2_176`, зона `kotelnaia`, `unique_id` ✅. Детали — §5-кватер-И-5 |
| ~~**A6**~~ | ~~**Камера — вернуть схему «как на TrueNAS»** (решение Alex, вечер-10)~~ | — | **✅✅ ВЫПОЛНЕНО 2026-09-14 (вечер-11, §5-кватер-И-3/И-5).** Историч. upstream был `cam.mallexxx.duckdns.org → 192.168.2.197:8090` (контейнер утрачен при пересоздании пула, след — `Caddyfile.bak`). Реализовано **аддоном на t610** (вебка физически там, Docker в HA OS закрыт → аддон). Поднят `local_ustreamer` (`/addons/ustreamer/`, MJPEG :8090) → Generic Camera по URL → **`unique_id` + зона `kotelnaia` + имя «Камера котельной»**. Блок `camera: platform: ffmpeg` из `configuration.yaml` **снесён** (бэкап `.bak-rmcam-20260914-185240`). Осталось: удалить лишний `/config/go2rtc.yaml` | | ~~**A6**~~ | ~~**Камера — вернуть схему «как на TrueNAS»** (решение Alex, вечер-10)~~ | — | **✅✅ ВЫПОЛНЕНО 2026-09-14 (вечер-11, §5-кватер-И-3/И-5).** Историч. upstream был `cam.mallexxx.duckdns.org → 192.168.2.197:8090` (контейнер утрачен при пересоздании пула, след — `Caddyfile.bak`). Реализовано **аддоном на t610** (вебка физически там, Docker в HA OS закрыт → аддон). Поднят `local_ustreamer` (`/addons/ustreamer/`, MJPEG :8090) → Generic Camera по URL → **`unique_id` + зона `kotelnaia` + имя «Камера котельной»**. Блок `camera: platform: ffmpeg` из `configuration.yaml` **снесён** (бэкап `.bak-rmcam-20260914-185240`). Осталось: удалить лишний `/config/go2rtc.yaml` |