v1.1 - Пересмотр деплоя прода
This commit is contained in:
@@ -27,6 +27,14 @@ VPS_TUNNEL_USER=tunnel
|
|||||||
# Раскомментируй и переопредели, только если нужен нестандартный слот.
|
# Раскомментируй и переопредели, только если нужен нестандартный слот.
|
||||||
#VPS_TUNNEL_PORT=9001
|
#VPS_TUNNEL_PORT=9001
|
||||||
|
|
||||||
|
# Приватный ключ туннеля в base64 — чтобы на Pi хватило только docker-compose.yml + .env
|
||||||
|
# (без файла deploy/tunnel/id_tunnel). Нужен ТОЛЬКО для прод-контейнера на Pi; для dev/test
|
||||||
|
# на ПК ключ берётся из файла. Сгенерируй ключ на ПК и закодируй БЕЗ переносов строк:
|
||||||
|
# Git Bash / Linux: base64 -w0 deploy/tunnel/id_tunnel
|
||||||
|
# PowerShell: [Convert]::ToBase64String([IO.File]::ReadAllBytes((Resolve-Path "deploy/tunnel/id_tunnel")))
|
||||||
|
# Pubkey (deploy/tunnel/id_tunnel.pub) добавь в authorized_keys у tunnel@VPS.
|
||||||
|
TUNNEL_KEY_B64=
|
||||||
|
|
||||||
# ─── АДМИНИСТРАТОР (вход по логину/паролю, отдельно от Telegram) ──────────────
|
# ─── АДМИНИСТРАТОР (вход по логину/паролю, отдельно от Telegram) ──────────────
|
||||||
ADMIN_USERNAME=admin
|
ADMIN_USERNAME=admin
|
||||||
ADMIN_PASSWORD=change-me-admin-password
|
ADMIN_PASSWORD=change-me-admin-password
|
||||||
|
|||||||
+99
-64
@@ -1,89 +1,124 @@
|
|||||||
# Raspberry Pi — ПРОД (`forbiddenstars.ru`)
|
# Raspberry Pi — ПРОД (`forbiddenstars.ru`)
|
||||||
|
|
||||||
Pi запускает приложение **и туннель** в Docker: `docker compose up` поднимает два сервиса —
|
На Pi нужны только **ДВА файла**: `docker-compose.yml` и `.env`. Репозиторий, сборка и файл
|
||||||
`app` (FastAPI + SPA) и `tunnel` (ssh-контейнер). У `app` **портов на хост нет**, наружу он
|
ключа туннеля не нужны:
|
||||||
доступен только через туннель-контейнер (`ssh -R 9000:app:8000` к VPS). Публичная точка —
|
- образы (`app` + `tunnel`) тянутся из Gitea-реестра (`pull_policy: always`);
|
||||||
VPS, домен `forbiddenstars.ru`. Снаружи Pi недоступен (CGNAT) — туннель сам стучится наружу.
|
- приватный ключ туннеля лежит в `.env` как `TUNNEL_KEY_B64` (base64).
|
||||||
|
|
||||||
## 1. Ключ для туннеля
|
`docker compose up` поднимает два контейнера: `app` (FastAPI+SPA, портов на хост нет) и
|
||||||
Туннель-контейнер ходит на `tunnel@VPS` по ключу из `deploy/tunnel/id_tunnel` (gitignored).
|
`tunnel` (`ssh -R 9000:app:8000` к VPS). Публичная точка — VPS, домен `forbiddenstars.ru`
|
||||||
Создай ключ и добавь его pubkey в `authorized_keys` пользователя `tunnel` на VPS:
|
(Pi за CGNAT — туннель стучится наружу сам).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Предпосылки (один раз, не на Pi)
|
||||||
|
1. **VPS настроен**: Caddy `forbiddenstars.ru` → `127.0.0.1:9000`, пользователь `tunnel`,
|
||||||
|
сертификаты, страница-заглушка — см. `deploy/vps/README.md`.
|
||||||
|
2. **Образы собраны и запушены в реестр** (на ПК с Docker Desktop):
|
||||||
|
```powershell
|
||||||
|
docker login gitea.arseniev.info
|
||||||
|
.\scripts\build-push.ps1
|
||||||
|
```
|
||||||
|
Без этого `docker compose up` на Pi не найдёт образы в реестре.
|
||||||
|
|
||||||
|
## 1. Система и Docker на Pi
|
||||||
```bash
|
```bash
|
||||||
ssh-keygen -t ed25519 -f deploy/tunnel/id_tunnel -N ""
|
ssh pi@<ip-пая>
|
||||||
ssh-copy-id -i deploy/tunnel/id_tunnel.pub tunnel@186.246.51.17
|
sudo apt update && sudo apt -y full-upgrade
|
||||||
# (или вручную: содержимое deploy/tunnel/id_tunnel.pub -> /home/tunnel/.ssh/authorized_keys на VPS)
|
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. .env
|
## 2. SSH-ключ для туннеля
|
||||||
Все настройки приложения и туннеля — в одном `.env` (контейнер форсит `APP_ENV=production`):
|
**Что это.** Отдельная пара ключей **только для туннеля** — ею контейнер `tunnel` логинится на
|
||||||
|
`tunnel@VPS`, чтобы открыть `ssh -R`. Это не системный ключ Pi, ты создаёшь его сам. Распределение:
|
||||||
|
- **приватный** ключ → в `.env` как `TUNNEL_KEY_B64` (base64, одной строкой);
|
||||||
|
- **публичный** (`.pub`) → в `authorized_keys` пользователя `tunnel` на VPS.
|
||||||
|
|
||||||
|
Сгенерировать прямо на Pi:
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
ssh-keygen -t ed25519 -f ~/fs_tunnel -N "" # создаст ~/fs_tunnel (приватный) и ~/fs_tunnel.pub
|
||||||
```
|
```
|
||||||
Минимально заполнить на Pi:
|
Добавить публичный ключ на VPS (Pi ходит наружу — это работает даже за CGNAT):
|
||||||
|
```bash
|
||||||
|
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
|
||||||
```
|
```
|
||||||
SECRET_KEY=... # python -c "import secrets;print(secrets.token_urlsafe(48))"
|
Закодировать приватный ключ в base64 **одной строкой** — это значение для `TUNNEL_KEY_B64`:
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
shred -u ~/fs_tunnel ~/fs_tunnel.pub # или просто rm
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Два файла: docker-compose.yml + .env
|
||||||
|
```bash
|
||||||
|
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_USERNAME=... # логин/пароль секретной админки
|
||||||
ADMIN_PASSWORD=...
|
ADMIN_PASSWORD=...
|
||||||
TELEGRAM_BOT_TOKEN=... # бот @BotFather; /setdomain → forbiddenstars.ru
|
TELEGRAM_BOT_TOKEN=... # бот @BotFather; затем /setdomain → forbiddenstars.ru
|
||||||
TELEGRAM_BOT_USERNAME=...
|
TELEGRAM_BOT_USERNAME=...
|
||||||
VPS_TUNNEL_HOST=186.246.51.17 # читает сервис tunnel
|
VPS_TUNNEL_HOST=186.246.51.17
|
||||||
VPS_TUNNEL_USER=tunnel
|
TUNNEL_KEY_B64=... # длинная строка base64 из шага 2 (целиком, одной строкой)
|
||||||
|
IMAGE_REGISTRY=gitea.arseniev.info/notbigghost # уже значение по умолчанию
|
||||||
|
IMAGE_TAG=latest
|
||||||
```
|
```
|
||||||
`VPS_TUNNEL_PORT` задавать не нужно — прод-контейнер по умолчанию берёт слот **9000**.
|
`APP_ENV` (форсится в `production`) и `VPS_TUNNEL_PORT` (прод → 9000) не трогать.
|
||||||
Ресурсы (`APP_MEM_LIMIT`/`APP_CPUS`) и оффсайт-бэкап (`BACKUP_*`) — по желанию.
|
|
||||||
|
|
||||||
## 3. Запуск (образ из реестра)
|
## 4. Запуск
|
||||||
Образы (`app` + `tunnel`) собираются под arm64 на ПК и пушатся в Gitea-реестр, Pi их тянет
|
|
||||||
(см. `IMAGE_REGISTRY`/`IMAGE_TAG` в `.env`). Pi 4/5 — мощный, но реестр держим как основной путь.
|
|
||||||
|
|
||||||
На ПК (Docker Desktop) — один раз `docker login gitea.arseniev.info`, далее при каждом релизе:
|
|
||||||
```powershell
|
|
||||||
.\scripts\build-push.ps1 # Windows (PowerShell); на *nix — bash scripts/build-push.sh
|
|
||||||
```
|
|
||||||
> `bash scripts/build-push.sh` в PowerShell уходит в WSL и падает, если нет дистрибутива —
|
|
||||||
> используй `.ps1`. Команды внутри — обычный `docker buildx`, работают и напрямую в PowerShell.
|
|
||||||
На Pi:
|
|
||||||
```bash
|
```bash
|
||||||
docker login gitea.arseniev.info # один раз (доступ к пакету)
|
docker login gitea.arseniev.info # один раз, доступ к реестру
|
||||||
git pull # нужны docker-compose.yml, .env, deploy/tunnel/id_tunnel
|
docker compose up -d # pull_policy: always → тянет образы из реестра, без сборки
|
||||||
docker compose pull # тянет свежие образы из реестра
|
|
||||||
docker compose up -d
|
|
||||||
docker compose ps # app healthy → поднимется tunnel
|
docker compose ps # app healthy → поднимется tunnel
|
||||||
docker compose logs -f tunnel # ждём: [tunnel] -R 9000:app:8000 -> tunnel@...
|
docker compose logs -f tunnel # ждём строку: [tunnel] -R 9000:app:8000 -> tunnel@...
|
||||||
```
|
```
|
||||||
Открой `https://forbiddenstars.ru` — должен отдать прод.
|
На старте контейнер сам применит миграции, засидит справочники и создаст админа из `.env`.
|
||||||
|
|
||||||
> Альтернатива без реестра (Pi 4/5 ≥4ГБ потянет сборку): `docker compose up -d --build` прямо на Pi.
|
## 5. Проверка
|
||||||
> Реестр Gitea должен быть по HTTPS с валидным сертификатом; иначе на Pi добавь его в
|
- Открой `https://forbiddenstars.ru` — должно отдать приложение (не заглушку).
|
||||||
> `/etc/docker/daemon.json` → `insecure-registries`.
|
- У @BotFather `/setdomain` → добавь `forbiddenstars.ru` (иначе Telegram-вход не заработает).
|
||||||
|
- Админка: удержать «Меню» 10 с → `/admin/login`, войти логином/паролём из `.env`.
|
||||||
|
|
||||||
## Обновление
|
## Обновление
|
||||||
```bash
|
```bash
|
||||||
# ПК: scripts/build-push.sh
|
# ПК: .\scripts\build-push.ps1
|
||||||
# Pi: git pull && docker compose pull && docker compose up -d
|
# Pi: docker compose up -d # always-pull подтянет свежий образ
|
||||||
```
|
```
|
||||||
|
|
||||||
## Бэкап (полный + оффсайт на VPS)
|
## Автозапуск после перезагрузки
|
||||||
`scripts/backup.sh` делает консистентный онлайн-снимок и собирает **полный** архив
|
Уже обеспечен: `systemctl enable docker` + `restart: unless-stopped`. После `sudo reboot`
|
||||||
`fs_<TS>.tar.gz` (БД + `uploads/` + `achievements/`) в `backups/` с ротацией. Если в `.env`
|
контейнеры поднимутся сами (используют локальный образ, без повторного pull).
|
||||||
задан `BACKUP_VPS_HOST` — копия дополнительно уходит на VPS (оффсайт; Pi → VPS push, т.к. CGNAT).
|
|
||||||
|
|
||||||
Настройка оффсайта (один раз):
|
## Бэкап (опционально)
|
||||||
```bash
|
Бэкап-скриптам нужен сам `docker-compose.yml` (он на Pi) + скрипты. Скопируй рядом
|
||||||
# 1) отдельный ключ бэкапа + его pubkey на VPS (юзер backup — см. deploy/vps/README.md):
|
`scripts/backup.sh` и `scripts/restore.sh`, настрой `BACKUP_*` в `.env` и cron. Подробно —
|
||||||
ssh-keygen -t ed25519 -f deploy/backup/id_backup -N ""
|
комментарии в `scripts/backup.sh` и `deploy/vps/README.md` §8.
|
||||||
ssh-copy-id -i deploy/backup/id_backup.pub backup@186.246.51.17
|
|
||||||
# 2) в .env заполнить BACKUP_VPS_HOST=186.246.51.17 (по желанию — BACKUP_VPS_USER/DIR/KEEP_*)
|
|
||||||
# 3) разовый прогон и проверка, что архив доехал на VPS:
|
|
||||||
scripts/backup.sh
|
|
||||||
# 4) cron (ежедневно в 04:00):
|
|
||||||
crontab -e
|
|
||||||
# 0 4 * * * /home/pi/ForbidenStarsApp/scripts/backup.sh >> /var/log/fs-backup.log 2>&1
|
|
||||||
```
|
|
||||||
|
|
||||||
Восстановление: `scripts/restore.sh backups/fs_<TS>.tar.gz` (ДЕСТРУКТИВНО — заменяет текущие
|
## Если что-то не так
|
||||||
данные; сначала проверь на тест-контуре). Тома — `db-data` / `uploads-data` / `achievements-data`.
|
- `https://forbiddenstars.ru` отдаёт заглушку/502 → туннель не поднят: `docker compose logs tunnel`
|
||||||
|
(чаще: pubkey не в `authorized_keys` на VPS, пустой/битый `TUNNEL_KEY_B64`, либо на VPS занят
|
||||||
Логи: `docker compose logs -f app` / `... tunnel`. Если `https://forbiddenstars.ru` отдаёт
|
слот 9000 → на VPS `sudo fuser -k 9000/tcp`, затем `docker compose restart tunnel`).
|
||||||
502 — значит туннель не поднят: смотри `docker compose logs tunnel` (чаще всего ключ не в
|
- `pull` не проходит → проверь `docker login gitea.arseniev.info` и что реестр по HTTPS с валидным
|
||||||
`authorized_keys` на VPS или не заданы `VPS_TUNNEL_*` в `.env`).
|
сертификатом (иначе хост в `/etc/docker/daemon.json` → `insecure-registries`, `systemctl restart docker`).
|
||||||
|
|||||||
+12
-10
@@ -9,18 +9,20 @@ VPS_TUNNEL_USER="${VPS_TUNNEL_USER:-tunnel}"
|
|||||||
: "${VPS_TUNNEL_PORT:?VPS_TUNNEL_PORT is required}"
|
: "${VPS_TUNNEL_PORT:?VPS_TUNNEL_PORT is required}"
|
||||||
UPSTREAM="${UPSTREAM:-app:8000}"
|
UPSTREAM="${UPSTREAM:-app:8000}"
|
||||||
|
|
||||||
# Ключ должен быть смонтирован файлом. Если тут пусто/папка — Docker создал каталог,
|
# Источник приватного ключа: либо TUNNEL_KEY_B64 (base64 в .env — прод: только compose+env),
|
||||||
# потому что файла deploy/tunnel/id_tunnel на хосте нет.
|
# либо смонтированный файл /key/id_tunnel (dev/test, где репозиторий есть на хосте).
|
||||||
if [ ! -f /key/id_tunnel ]; then
|
mkdir -p /root/.ssh
|
||||||
echo "[tunnel] ERROR: /key/id_tunnel is not a regular file."
|
KEY=/root/.ssh/id_tunnel
|
||||||
echo "[tunnel] Put your private key at deploy/tunnel/id_tunnel on the host (its pubkey must be in authorized_keys of tunnel@VPS)."
|
if [ -n "${TUNNEL_KEY_B64:-}" ]; then
|
||||||
|
echo "$TUNNEL_KEY_B64" | base64 -d > "$KEY"
|
||||||
|
elif [ -f /key/id_tunnel ]; then
|
||||||
|
cp /key/id_tunnel "$KEY"
|
||||||
|
else
|
||||||
|
echo "[tunnel] ERROR: нет ключа — задай TUNNEL_KEY_B64 в .env (base64) или примонтируй /key/id_tunnel."
|
||||||
|
echo "[tunnel] base64 ключа без переносов: base64 -w0 deploy/tunnel/id_tunnel"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
chmod 600 "$KEY"
|
||||||
# Копируем ключ и выставляем строгие права (с хоста права могут не годиться, особенно с Windows).
|
|
||||||
mkdir -p /root/.ssh
|
|
||||||
cp /key/id_tunnel /root/.ssh/id_tunnel
|
|
||||||
chmod 600 /root/.ssh/id_tunnel
|
|
||||||
|
|
||||||
echo "[tunnel] -R ${VPS_TUNNEL_PORT}:${UPSTREAM} -> ${VPS_TUNNEL_USER}@${VPS_TUNNEL_HOST}"
|
echo "[tunnel] -R ${VPS_TUNNEL_PORT}:${UPSTREAM} -> ${VPS_TUNNEL_USER}@${VPS_TUNNEL_HOST}"
|
||||||
exec ssh -N \
|
exec ssh -N \
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
# ВРЕМЕННЫЙ ПРОД НА ПК — заглушка вместо Pi, пока он не готов.
|
||||||
|
# Поднимает forbiddenstars.ru (слот VPS 9000) с твоего ПК: поведение production,
|
||||||
|
# прод-данные в ПОСТОЯННЫХ томах (потом перенесёшь на Pi через backup/restore).
|
||||||
|
#
|
||||||
|
# Отличия от docker-compose.yml (прод на Pi):
|
||||||
|
# • локальный образ (сборка x86 на ПК), НЕ из реестра и НЕ пушится;
|
||||||
|
# • отдельный проект (name) и свои тома — не конфликтует с dev/test на этом ПК.
|
||||||
|
# Всё остальное — как у прода (APP_ENV=production, туннель на 9000, лимиты, healthcheck).
|
||||||
|
#
|
||||||
|
# Запуск: docker compose -f docker-compose.temp.yml up -d --build
|
||||||
|
# Логи: docker compose -f docker-compose.temp.yml logs -f tunnel
|
||||||
|
# Остановка: docker compose -f docker-compose.temp.yml down (тома сохраняются)
|
||||||
|
#
|
||||||
|
# ВАЖНО: слот 9000 общий с будущим прод-туннелем Pi. Перед запуском прода на Pi
|
||||||
|
# ОСТАНОВИ этот контур (down), иначе оба будут драться за VPS:9000.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
name: forbidden-stars-temp
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
image: forbidden-stars:temp-prod # локальный образ x86 (на ПК); в реестр НЕ пушим
|
||||||
|
restart: unless-stopped
|
||||||
|
init: true
|
||||||
|
stop_grace_period: 30s
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
APP_ENV: production # ведём себя ровно как прод
|
||||||
|
volumes:
|
||||||
|
- db-data:/data
|
||||||
|
- uploads-data:/data/uploads
|
||||||
|
- achievements-data:/data/achievements
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
mem_limit: ${APP_MEM_LIMIT:-1g} # на ПК ресурсов больше, чем на Pi
|
||||||
|
cpus: ${APP_CPUS:-2}
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "5"
|
||||||
|
|
||||||
|
# Туннель на ПРОД-слот: VPS:${VPS_TUNNEL_PORT:-9000} → app:8000 (домен forbiddenstars.ru).
|
||||||
|
tunnel:
|
||||||
|
build: ./deploy/tunnel
|
||||||
|
image: forbidden-stars-tunnel:temp-prod
|
||||||
|
restart: unless-stopped
|
||||||
|
init: true
|
||||||
|
depends_on:
|
||||||
|
app:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
VPS_TUNNEL_HOST: ${VPS_TUNNEL_HOST:?VPS_TUNNEL_HOST is required in .env}
|
||||||
|
VPS_TUNNEL_USER: ${VPS_TUNNEL_USER:-tunnel}
|
||||||
|
VPS_TUNNEL_PORT: ${VPS_TUNNEL_PORT:-9000} # прод-слот forbiddenstars.ru
|
||||||
|
UPSTREAM: app:8000
|
||||||
|
volumes:
|
||||||
|
- ./deploy/tunnel/id_tunnel:/key/id_tunnel:ro
|
||||||
|
mem_limit: 64m
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db-data:
|
||||||
|
uploads-data:
|
||||||
|
achievements-data:
|
||||||
+10
-7
@@ -1,9 +1,11 @@
|
|||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
# ПРОД на Raspberry Pi (forbiddenstars.ru) — единый compose: приложение + туннель.
|
# ПРОД на Raspberry Pi (forbiddenstars.ru) — единый compose: приложение + туннель.
|
||||||
# Все настройки и секреты — в корневом .env (см. .env.example). Этот файл их только
|
# На Pi нужны только ДВА файла: этот docker-compose.yml и .env. Репозиторий, сборка и
|
||||||
# пробрасывает; ничего секретного тут нет.
|
# файл ключа не нужны: образы тянутся из реестра (pull_policy: always), а приватный ключ
|
||||||
|
# туннеля лежит в .env (TUNNEL_KEY_B64, base64). build: оставлен для сборки/пуша на ПК
|
||||||
|
# (scripts/build-push.*) — на Pi он не используется.
|
||||||
#
|
#
|
||||||
# Запуск/обновление: docker compose up -d --build
|
# Запуск/обновление: docker compose up -d (сам тянет свежие образы)
|
||||||
# Логи: docker compose logs -f app (или: ... tunnel)
|
# Логи: docker compose logs -f app (или: ... tunnel)
|
||||||
# Остановка: docker compose down (данные в томах сохраняются)
|
# Остановка: docker compose down (данные в томах сохраняются)
|
||||||
# Бэкап/restore: scripts/backup.sh / scripts/restore.sh
|
# Бэкап/restore: scripts/backup.sh / scripts/restore.sh
|
||||||
@@ -18,6 +20,7 @@ services:
|
|||||||
# Образ из реестра (Gitea): собирается под arm64 на ПК (scripts/build-push.sh) и тянется
|
# Образ из реестра (Gitea): собирается под arm64 на ПК (scripts/build-push.sh) и тянется
|
||||||
# на Pi через `docker compose pull`. build: оставлен как локальный фолбэк (сборка на Pi).
|
# на Pi через `docker compose pull`. build: оставлен как локальный фолбэк (сборка на Pi).
|
||||||
image: ${IMAGE_REGISTRY:-gitea.arseniev.info/notbigghost}/forbidden-stars:${IMAGE_TAG:-latest}
|
image: ${IMAGE_REGISTRY:-gitea.arseniev.info/notbigghost}/forbidden-stars:${IMAGE_TAG:-latest}
|
||||||
|
pull_policy: always # на Pi всегда тянем образ из реестра (без сборки)
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
init: true # PID 1 пробрасывает сигналы → корректный SIGTERM
|
init: true # PID 1 пробрасывает сигналы → корректный SIGTERM
|
||||||
stop_grace_period: 30s # время на чек-пойнт WAL SQLite перед остановкой
|
stop_grace_period: 30s # время на чек-пойнт WAL SQLite перед остановкой
|
||||||
@@ -46,22 +49,22 @@ services:
|
|||||||
max-file: "5"
|
max-file: "5"
|
||||||
|
|
||||||
# SSH reverse-туннель: VPS:${VPS_TUNNEL_PORT:-9000} → app:8000 (домен forbiddenstars.ru).
|
# SSH reverse-туннель: VPS:${VPS_TUNNEL_PORT:-9000} → app:8000 (домен forbiddenstars.ru).
|
||||||
# Ключ — ./deploy/tunnel/id_tunnel (в git не идёт); его pubkey в authorized_keys у tunnel@VPS.
|
# Приватный ключ — в .env как TUNNEL_KEY_B64 (base64); pubkey — в authorized_keys у tunnel@VPS.
|
||||||
tunnel:
|
tunnel:
|
||||||
build: ./deploy/tunnel
|
build: ./deploy/tunnel
|
||||||
image: ${IMAGE_REGISTRY:-gitea.arseniev.info/notbigghost}/forbidden-stars-tunnel:${IMAGE_TAG:-latest}
|
image: ${IMAGE_REGISTRY:-gitea.arseniev.info/notbigghost}/forbidden-stars-tunnel:${IMAGE_TAG:-latest}
|
||||||
|
pull_policy: always
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
init: true
|
init: true
|
||||||
depends_on:
|
depends_on:
|
||||||
app:
|
app:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
VPS_TUNNEL_HOST: ${VPS_TUNNEL_HOST:?VPS_TUNNEL_HOST is required in .env}
|
VPS_TUNNEL_HOST: ${VPS_TUNNEL_HOST} # обязателен; tunnel.sh упадёт с ошибкой, если пуст
|
||||||
VPS_TUNNEL_USER: ${VPS_TUNNEL_USER:-tunnel}
|
VPS_TUNNEL_USER: ${VPS_TUNNEL_USER:-tunnel}
|
||||||
VPS_TUNNEL_PORT: ${VPS_TUNNEL_PORT:-9000} # прод-слот (forbiddenstars.ru)
|
VPS_TUNNEL_PORT: ${VPS_TUNNEL_PORT:-9000} # прод-слот (forbiddenstars.ru)
|
||||||
UPSTREAM: app:8000
|
UPSTREAM: app:8000
|
||||||
volumes:
|
TUNNEL_KEY_B64: ${TUNNEL_KEY_B64:-} # приватный ключ туннеля (base64), из .env
|
||||||
- ./deploy/tunnel/id_tunnel:/key/id_tunnel:ro
|
|
||||||
mem_limit: 64m
|
mem_limit: 64m
|
||||||
security_opt:
|
security_opt:
|
||||||
- no-new-privileges:true
|
- no-new-privileges:true
|
||||||
|
|||||||
Reference in New Issue
Block a user