deploy/backup/README.md — подробная пошаговая инструкция по всему, что делается вручную: пароль шифрования, SSH-ключ, VPS (пользователь fsbackup только для SFTP, проверки sshd), сборка образов, включение на Pi (с разбором каждой переменной и контрольными проверками), доступ с ПК и выгрузка, учебное восстановление на тест-клоне, восстановление прода и из архива, катастрофа «Pi умер», повседневные действия, таблица неполадок, справочник, чек-лист. Команды разделов VPS и Pi прогнаны на локальном стенде. deploy/pi, deploy/vps §8, deploy/README — ссылки на новую схему. Удалены scripts/backup.sh и scripts/restore.sh (restore.sh ещё и оставлял БД root-овой: docker cp пишет файлы с uid 0); их архивы fs_*.tar.gz восстанавливаются через fs-backup import. #64 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jBxs9nBCk5nBdTLzcGz91
5.8 KiB
Публикация: домены, VPS, туннели
Приложение крутится дома (Pi — прод) и на твоём ПК (dev/test). Дома белого IP нет (CGNAT), поэтому наружу выставляем через VPS-привратник: на нём Caddy терминирует HTTPS твоими сертификатами и проксирует трафик в SSH reverse-туннели, которые приложение само открывает к VPS.
┌──────────── VPS 186.246.51.17 (Caddy) ───────────┐
forbiddenstars.ru ───►│ :443 (cert твой) → 127.0.0.1:9000 │
│ ▲ туннель-КОНТЕЙНЕР │
│ └── Pi : app:8000 PROD │
forbidden-stars.ru ──►│ :443 (cert твой) → 127.0.0.1:9001 │
│ ▲ контейнер (test) ИЛИ │
│ ▲ ssh с ПК (dev) │
│ ├── ПК test : app:8000 │
│ └── ПК dev : vite:5173 │
└───────────────────────────────────────────────────┘
- PROD — Pi.
docker compose up -dподнимает два сервиса:app+tunnel. Уappпортов на хост нет — наружу его выставляет только туннель-контейнер (ssh -R 9000:app:8000к VPS). Постоянно, Docker сам переподключает. См.pi/. - TEST — ПК. То же самое:
docker compose -f docker-compose.test.yml upподнимаетapp+tunnel(ssh -R 9001:app:8000). Портов на хост нет — тест виден только наforbidden-stars.ru. Обычно запускается лаунчером приAPP_ENV=test. - DEV — ПК, нативно (
uvicorn+vite). По умолчанию только на localhost; приLOCAL_PUBLIC=vpsлаунчер (run.ps1) дополнительно поднимает SSH-туннель с ПК (ssh -R 9001:localhost:5173) → дев виден наforbidden-stars.ru. - DEV и TEST делят слот 9001 (
forbidden-stars.ru) → поднимай что-то одно за раз. PROD на отдельном слоте 9000 (forbiddenstars.ru) — работает независимо.
Ключ туннеля — deploy/tunnel/id_tunnel (приватный, в git не идёт). Его публичную
часть добавь в authorized_keys пользователя tunnel на VPS. Один и тот же ключ годится
для контейнерного туннеля (Pi/ПК) и для dev-туннеля run.ps1.
Настройка по шагам:
- VPS —
vps/README.md: Caddy, файрвол, пользовательtunnel, сертификаты,Caddyfile. - Pi (прод) —
pi/README.md: ключ вdeploy/tunnel/id_tunnel,.env,docker compose up -d. - ПК (dev/test) — тот же ключ в
deploy/tunnel/id_tunnel(для test-контейнера) и/или ключ по умолчанию для dev (run.ps1); pubkey — вauthorized_keysуtunnel@VPS. - Бэкапы —
backup/README.md: контейнерbackup(restic) делает снимки на Pi и на VPS (fsbackup@VPS, только SFTP), скрипты ПК скачивают их и проверяют восстановление на тест-клоне.
Секреты не в git: сертификаты/ключи (*.pem, *.key, id_tunnel*) живут на VPS/Pi/ПК,
в репозитории только Caddyfile, deploy/tunnel/ (образ туннеля) и шаблоны.
Telegram-вход требует HTTPS-домен: у BotFather
/setdomainукажи оба домена (forbiddenstars.ruиforbidden-stars.ru).
Реал-тайм (SSE)
Приложение шлёт события «данные изменились» через SSE: GET /api/events
(text/event-stream). Это обычный HTTP — проходит через Caddy и SSH-туннель без доп.
настроек, КРОМЕ одного: для пути /api/events в Caddyfile выделен отдельный handle
без encode и с flush_interval -1 (иначе сжатие/буферизация задержат поток).
После правки Caddyfile на VPS: sudo systemctl reload caddy (или restart).
Шина событий — in-memory, рассчитана на один процесс (uvicorn --workers 1, как в
контейнере). Если когда-нибудь поднимешь несколько воркеров/реплик — шину нужно вынести во
внешний брокер (Redis pub/sub), иначе события увидит только тот воркер, что принял мутацию.
SSE-поток сам не закрывается, поэтому uvicorn запускается с --timeout-graceful-shutdown
(entrypoint.sh, run.*). Без него остановка ждёт закрытия всех соединений: в dev
--reload при открытой вкладке висит вечно, в контейнере остановку обрывает только SIGKILL
по stop_grace_period.