diff --git a/.env.example b/.env.example index a3d6987..7842b1f 100644 --- a/.env.example +++ b/.env.example @@ -22,11 +22,15 @@ LOCAL_PUBLIC=local # Ключ туннеля — в deploy/tunnel/id_tunnel (в git не идёт); pubkey → authorized_keys у tunnel@VPS. VPS_TUNNEL_HOST=186.246.51.17 VPS_TUNNEL_USER=tunnel -VPS_TUNNEL_PORT=9001 # слот VPS для dev-туннеля (forbidden-stars.ru); контейнеры: prod=9000, test=9001 +# VPS_TUNNEL_PORT обычно НЕ задают — каждый контур берёт свой слот по умолчанию: +# dev (run.ps1) → 9001, прод-контейнер → 9000, test-контейнер → 9001. +# Раскомментируй и переопредели, только если нужен нестандартный слот. +#VPS_TUNNEL_PORT=9001 # ─── АДМИНИСТРАТОР (вход по логину/паролю, отдельно от Telegram) ────────────── ADMIN_USERNAME=admin ADMIN_PASSWORD=change-me-admin-password +ADMIN_NICKNAME=Администратор ADMIN_BOOTSTRAP_ENABLED=true # ─── АУТЕНТИФИКАЦИЯ ИГРОКОВ ─────────────────────────────────────────────────── @@ -57,10 +61,20 @@ COOKIE_DOMAIN= DEV_DATABASE_URL=sqlite:///./data/dev/forbidden_stars.db PROD_DATABASE_URL=sqlite:////data/forbidden_stars.db -# Каталог загрузок (зарезервировано под фото/видео), тоже раздельно. +# Каталог загрузок (фото партий), раздельно для dev и prod. DEV_UPLOAD_DIR=./data/dev/uploads PROD_UPLOAD_DIR=/data/uploads +# Каталог определений титулов (файлы: meta.json, condition.py, icon.*), раздельно. +DEV_ACHIEVEMENTS_DIR=./data/dev/achievements +PROD_ACHIEVEMENTS_DIR=/data/achievements + +# ─── РЕСУРСЫ ПРОД-КОНТЕЙНЕРА (docker-compose.yml) ───────────────────────────── +# Лимиты под Raspberry Pi. Не заданы → дефолты compose (512m / 1.5 CPU). +# Подними, если у Pi больше RAM/ядер. +#APP_MEM_LIMIT=512m +#APP_CPUS=1.5 + # ─── БЭКАП (оффсайт-копия на VPS; читает scripts/backup.sh на хосте Pi) ─────── # Полный бэкап (БД + uploads + achievements) кладётся локально в backups/, и — если задан # BACKUP_VPS_HOST — копируется на VPS (Pi → VPS push, т.к. Pi за CGNAT). Пусто = только локально. diff --git a/deploy/pi/README.md b/deploy/pi/README.md index 970181a..a975d0a 100644 --- a/deploy/pi/README.md +++ b/deploy/pi/README.md @@ -15,14 +15,22 @@ ssh-copy-id -i deploy/tunnel/id_tunnel.pub tunnel@186.246.51.17 ``` ## 2. .env +Все настройки приложения и туннеля — в одном `.env` (контейнер форсит `APP_ENV=production`): ```bash -cp .env.example .env # заполни секреты; APP_ENV контейнер форсит в production +cp .env.example .env ``` -Проверь, что заданы параметры VPS (их читает сервис `tunnel`): +Минимально заполнить на Pi: ``` -VPS_TUNNEL_HOST=186.246.51.17 +SECRET_KEY=... # python -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 VPS_TUNNEL_USER=tunnel ``` +`VPS_TUNNEL_PORT` задавать не нужно — прод-контейнер по умолчанию берёт слот **9000**. +Ресурсы (`APP_MEM_LIMIT`/`APP_CPUS`) и оффсайт-бэкап (`BACKUP_*`) — по желанию. ## 3. Запуск ```bash diff --git a/docker-compose.yml b/docker-compose.yml index c16c27c..d41cc23 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,42 +1,50 @@ +# ───────────────────────────────────────────────────────────────────────────── +# ПРОД на Raspberry Pi (forbiddenstars.ru) — единый compose: приложение + туннель. +# Все настройки и секреты — в корневом .env (см. .env.example). Этот файл их только +# пробрасывает; ничего секретного тут нет. +# +# Запуск/обновление: docker compose up -d --build +# Логи: docker compose logs -f app (или: ... tunnel) +# Остановка: docker compose down (данные в томах сохраняются) +# Бэкап/restore: scripts/backup.sh / scripts/restore.sh +# +# Контейнер ВСЕГДА production: APP_ENV форсится здесь и игнорирует значение из .env. +# Порты на хост НЕ публикуются — наружу приложение выставляет только сервис tunnel +# (SSH reverse-туннель к VPS). Из LAN/localhost оно недоступно. +# ───────────────────────────────────────────────────────────────────────────── services: app: build: . image: forbidden-stars:latest restart: unless-stopped - init: true + init: true # PID 1 пробрасывает сигналы → корректный SIGTERM + stop_grace_period: 30s # время на чек-пойнт WAL SQLite перед остановкой env_file: - - .env # секреты/настройки (один общий формат для dev и prod) + - .env # единый источник настроек/секретов всего приложения environment: - # Прод обособлен: контейнер ВСЕГДА production и ИГНОРИРУЕТ APP_ENV из .env - # (хоть development, хоть test). БД=/data, STATIC_DIR=/app/static — из Dockerfile. - APP_ENV: production - # Портов на хост НЕТ: приложение доступно только изнутри сети compose. - # Наружу его выставляет сервис tunnel (ниже) через VPS. Из LAN/localhost — недоступно. + APP_ENV: production # прод обособлен: игнорируем APP_ENV из .env volumes: - - db-data:/data # БД SQLite + WAL-сайдкары - - uploads-data:/data/uploads # задел под фото/видео - - achievements-data:/data/achievements # определения ачивок (файлы) + - db-data:/data # БД SQLite + WAL-сайдкары + - uploads-data:/data/uploads # медиа партий + - achievements-data:/data/achievements # определения титулов (файлы) healthcheck: - test: - - CMD - - python - - -c - - "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')" + 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: 512m - cpus: 1.5 + mem_limit: ${APP_MEM_LIMIT:-512m} # лимиты под Pi; переопределяются в .env + cpus: ${APP_CPUS:-1.5} + security_opt: + - no-new-privileges:true logging: driver: json-file options: max-size: "10m" max-file: "5" - # SSH reverse-туннель к VPS: forbiddenstars.ru (VPS:9000) -> app:8000 (по сети compose). - # Ключ — в ./deploy/tunnel/id_tunnel (gitignore), его pubkey в authorized_keys у tunnel@VPS. - # VPS_TUNNEL_HOST/USER берутся из .env (на Pi заполни их там же). + # SSH reverse-туннель: VPS:${VPS_TUNNEL_PORT:-9000} → app:8000 (домен forbiddenstars.ru). + # Ключ — ./deploy/tunnel/id_tunnel (в git не идёт); его pubkey в authorized_keys у tunnel@VPS. tunnel: build: ./deploy/tunnel image: forbidden-stars-tunnel:latest @@ -46,13 +54,15 @@ services: app: condition: service_healthy environment: - VPS_TUNNEL_HOST: ${VPS_TUNNEL_HOST} + VPS_TUNNEL_HOST: ${VPS_TUNNEL_HOST:?VPS_TUNNEL_HOST is required in .env} VPS_TUNNEL_USER: ${VPS_TUNNEL_USER:-tunnel} - VPS_TUNNEL_PORT: "9000" # forbiddenstars.ru (прод); у test — 9001 + 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: