Files
ForbiddenStarsApp/deploy/pi
NotBigGhostandClaude Opus 5 8b400b76c6 Бэкап: убрать старые backup.sh/restore.sh, документация
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
2026-09-14 01:29:08 +03:00
..

Raspberry Pi — ПРОД (forbiddenstars.ru)

На Pi нужны только ДВА файла: docker-compose.yml и .env. Репозиторий, сборка и файл ключа туннеля не нужны:

  • образы (app + tunnel) тянутся из Gitea-реестра (pull_policy: always);
  • приватный ключ туннеля лежит в .env как TUNNEL_KEY_B64 (base64).

docker compose up поднимает два контейнера: app (FastAPI+SPA, портов на хост нет) и tunnel (ssh -R 9000:app:8000 к VPS). Публичная точка — VPS, домен forbiddenstars.ru (Pi за CGNAT — туннель стучится наружу сам).


0. Предпосылки (один раз, не на Pi)

  1. VPS настроен: Caddy forbiddenstars.ru → 127.0.0.1:9000, пользователь tunnel, сертификаты, страница-заглушка — см. deploy/vps/README.md.
  2. Образы собраны и запушены в реестр (на ПК с Docker Desktop):
    docker login gitea.arseniev.info
    .\scripts\build-push.ps1
    
    Без этого docker compose up на Pi не найдёт образы в реестре.

1. Система и Docker на Pi

ssh pi@<ip-пая>
sudo apt update && sudo apt -y full-upgrade
sudo apt -y install curl openssh-client       # base64/ssh-keygen уже есть в системе

curl -fsSL https://get.docker.com | sudo sh   # Docker Engine + compose-плагин (arm64)
sudo usermod -aG docker $USER
sudo systemctl enable --now docker            # автозапуск после ребута
newgrp docker                                 # применить группу (или перезайти по SSH)
docker version && docker compose version      # проверка

2. SSH-ключ для туннеля

Что это. Отдельная пара ключей только для туннеля — ею контейнер tunnel логинится на tunnel@VPS, чтобы открыть ssh -R. Это не системный ключ Pi, ты создаёшь его сам. Распределение:

  • приватный ключ → в .env как TUNNEL_KEY_B64 (base64, одной строкой);
  • публичный (.pub) → в authorized_keys пользователя tunnel на VPS.

Сгенерировать прямо на Pi:

ssh-keygen -t ed25519 -f ~/fs_tunnel -N ""    # создаст ~/fs_tunnel (приватный) и ~/fs_tunnel.pub

Добавить публичный ключ на VPS (Pi ходит наружу — это работает даже за CGNAT):

ssh-copy-id -i ~/fs_tunnel.pub tunnel@186.246.51.17
# Если у tunnel нет пароля (только ключ) — добавь вручную через свой админ-доступ к VPS:
#   cat ~/fs_tunnel.pub                # скопируй строку
#   на VPS:  echo '<строка>' >> /home/tunnel/.ssh/authorized_keys

Закодировать приватный ключ в base64 одной строкой — это значение для TUNNEL_KEY_B64:

base64 -w0 ~/fs_tunnel; echo          # выведет длинную строку без переносов — скопируй её целиком

Альтернатива: если ключ уже есть на ПК (deploy/tunnel/id_tunnel) и его pubkey уже на VPS — не плоди новый, закодируй тот: [Convert]::ToBase64String([IO.File]::ReadAllBytes((Resolve-Path "deploy\tunnel\id_tunnel")))

После того как base64 вставлен в .env, файлы ключа на Pi можно удалить — ключ теперь в .env, а pubkey уже на VPS:

shred -u ~/fs_tunnel ~/fs_tunnel.pub   # или просто rm

3. Два файла: docker-compose.yml + .env

mkdir -p ~/forbidden-stars && cd ~/forbidden-stars
# branch — main (или dev, если ещё не смёржено в main):
curl -fsSLO https://gitea.arseniev.info/NotBigGhost/ForbiddenStarsApp/raw/branch/main/docker-compose.yml
curl -fsSL  https://gitea.arseniev.info/NotBigGhost/ForbiddenStarsApp/raw/branch/main/.env.example -o .env
nano .env

Заполнить в .env:

SECRET_KEY=...                 # python3 -c "import secrets;print(secrets.token_urlsafe(48))"
ADMIN_USERNAME=...             # логин/пароль секретной админки
ADMIN_PASSWORD=...
TELEGRAM_BOT_TOKEN=...         # бот @BotFather; затем /setdomain → forbiddenstars.ru
TELEGRAM_BOT_USERNAME=...
VPS_TUNNEL_HOST=186.246.51.17
TUNNEL_KEY_B64=...             # длинная строка base64 из шага 2 (целиком, одной строкой)
IMAGE_REGISTRY=gitea.arseniev.info/notbigghost   # уже значение по умолчанию
IMAGE_TAG=latest

APP_ENV (форсится в production) и VPS_TUNNEL_PORT (прод → 9000) не трогать.

4. Запуск

docker login gitea.arseniev.info     # один раз, доступ к реестру
docker compose up -d                 # pull_policy: always → тянет образы из реестра, без сборки
docker compose ps                    # app healthy → поднимется tunnel
docker compose logs -f tunnel        # ждём строку: [tunnel] -R 9000:app:8000 -> tunnel@...

На старте контейнер сам применит миграции, засидит справочники и создаст админа из .env.

5. Проверка

  • Открой https://forbiddenstars.ru — должно отдать приложение (не заглушку).
  • У @BotFather /setdomain → добавь forbiddenstars.ru (иначе Telegram-вход не заработает).
  • Админка: удержать «Меню» 10 с → /admin/login, войти логином/паролём из .env.

Обновление

# ПК:  .\scripts\build-push.ps1
# Pi:  docker compose up -d          # always-pull подтянет свежий образ

Автозапуск после перезагрузки

Уже обеспечен: systemctl enable docker + restart: unless-stopped. После sudo reboot контейнеры поднимутся сами (используют локальный образ, без повторного pull).

Бэкапы

Отдельный контейнер backup в том же docker-compose.yml: каждую ночь делает зашифрованный снимок БД, uploads и achievements на Pi и на VPS. Дополнительных файлов на Pi не нужно, всё настраивается блоком BACKUP_* в .env. Пока BACKUP_PASSWORD пуст, бэкапы выключены.

Пошаговая настройка, восстановление и действия при гибели Pi — deploy/backup/README.md.

docker compose exec backup fs-backup status   # состояние
docker compose exec backup fs-backup list     # хронология снимков

Не выполняйте docker compose down -v: флаг -v удаляет тома с данными и локальными бэкапами.

Если что-то не так

  • https://forbiddenstars.ru отдаёт заглушку/502 → туннель не поднят: docker compose logs tunnel (чаще: pubkey не в authorized_keys на VPS, пустой/битый TUNNEL_KEY_B64, либо на VPS занят слот 9000 → на VPS sudo fuser -k 9000/tcp, затем docker compose restart tunnel).
  • pull не проходит → проверь docker login gitea.arseniev.info и что реестр по HTTPS с валидным сертификатом (иначе хост в /etc/docker/daemon.json → insecure-registries, systemctl restart docker).