# Развёртывание открытой альфы rf4spotter.ru Production-контур рассчитан на один Linux-сервер с Docker Compose. Наружу публикуются только Caddy `80/443`; PostgreSQL, FastAPI и MinIO не имеют host-портов. Административные страницы защищены Caddy Basic Auth, административный API — Bearer-токеном FastAPI. API-запросы не требуют Basic: обе схемы используют заголовок Authorization и не могут накладываться на один запрос. Текущее состояние публичных DNS/TLS и незакрытые инфраструктурные действия ведутся в [`docs/deployment-status.md`](../docs/deployment-status.md). ## 1. DNS и сервер Создайте A-записи `rf4spotter.ru` и `files.rf4spotter.ru` на публичный IPv4 сервера. При наличии рабочего IPv6 добавьте AAAA для обоих имён. До запуска убедитесь, что извне доступны TCP 80/443 и UDP 443; SSH ограничьте своим IP или VPN. Порты 4321, 8000, 9000, 9001 и 5432 открывать нельзя. Минимум для открытой альфы: 2 vCPU, 4 ГБ RAM и 40 ГБ SSD. Рекомендуется 4 vCPU, 8 ГБ RAM и отдельное внешнее место для резервных копий. ## 2. Секреты На сервере: ```bash cp .env.production.example .env.production chmod 600 .env.production openssl rand -base64 36 # отдельные значения для БД, ADMIN_TOKEN, RATE_LIMIT_SECRET, MinIO root и S3 app docker run --rm caddy:2.10.2-alpine caddy hash-password --plaintext 'ОТДЕЛЬНЫЙ ADMIN-ПАРОЛЬ' ``` Заполните `.env.production`. Хеш Caddy содержит символы `$`, поэтому значение `ADMIN_BASIC_PASSWORD_HASH` в env-файле заключите в одинарные кавычки. `MINIO_ROOT_*` и `S3_*` обязаны быть разными: init-контейнер root-доступом создаёт `S3_BUCKET`, назначает приложению только list/location этого bucket и get/put/delete его объектов, затем проверяет отсутствие глобального list. API получает только application credentials и не может создавать bucket. Если пароль PostgreSQL содержит специальные символы, в `DATABASE_URL` нужна URL-кодированная форма того же пароля. `.env.production` нельзя коммитить или пересылать вместе с логами. ## 3. Проверка и первый запуск Перед первым запуском проверьте секреты и итоговую Compose-конфигурацию, не выводя значения в лог: ```bash ./deploy/preflight.sh ``` Перед сборкой запишите текущий `git rev-parse --short HEAD` в `APP_REVISION` файла `.env.production`, чтобы `/ready` однозначно показывал развёрнутый commit. `PUBLIC_CACHE_SECONDS` задаёт короткий in-process кэш публичного агрегата активности (по умолчанию 20 секунд). Не увеличивайте его без повторной проверки свежести после публикации. ```bash docker compose --env-file .env.production -f compose.production.yaml config --quiet docker compose --env-file .env.production -f compose.production.yaml build docker compose --env-file .env.production -f compose.production.yaml run --rm migrate docker compose --env-file .env.production -f compose.production.yaml up -d --no-deps api web community-scheduler docker compose --env-file .env.production -f compose.production.yaml ps curl -fsS https://rf4spotter.ru/health curl -fsS https://rf4spotter.ru/ready ``` Безопасный диагностический снимок для администратора: ```bash curl -fsS -H "Authorization: Bearer $ADMIN_TOKEN" -o rf4spotter-diagnostics.json https://rf4spotter.ru/api/v1/admin/diagnostics ``` После обновления DNS и получения сертификатов выполните внешний этап той же проверки: ```bash ./deploy/preflight.sh --online ``` До запуска на сервере можно воспроизвести полный production bootstrap на пустых изолированных volumes. Скрипт собирает образы, применяет миграции, проверяет отсутствие демо-уловов, readiness и отправку заявки: ```bash ./deploy/test-production-bootstrap.sh ``` Отдельный upgrade-drill проверяет путь от предыдущей Alembic-ревизии к текущему head и сохранность контрольных данных: ```bash ./deploy/test-release-upgrade.sh ``` По умолчанию временно используются только loopback-порты `14321` и `18000`; PostgreSQL и MinIO наружу не публикуются. Контур и volumes удаляются после проверки. Drill успешно пройден 6 сентября 2026 года. Одноразовый `migrate` применяет Alembic до rollout API; при ошибке новый runtime не запускается. API при старте выполняет только идемпотентный seed: в production он добавляет минимальные справочники и точки, а демонстрационные уловы жёстко отключены `SEED_DEMO_DATA=false`. Проверка TLS и маршрутизации: ```bash curl -I https://rf4spotter.ru/ curl -I https://files.rf4spotter.ru/minio/health/live ``` MinIO health URL допустим для диагностики, но Console наружу не публикуется. Объекты доступны только по временным подписанным ссылкам. ## 4. Первичные данные Официальный импорт запускается вручную после успешного readiness: ```bash docker compose --env-file .env.production -f compose.production.yaml exec api python -m app.cli import-records ``` Автоматический scheduler не входит в production-файл. RF4MAP и RF4 Posts нельзя опрашивать чаще одного раза в 30 минут; до отдельной эксплуатационной задачи используйте только контролируемые ручные запуски и staging. Официальный импорт защищён PostgreSQL advisory lock на комбинацию source/region/category. Параллельный admin-запрос получает `409`, а scheduler записывает безопасный skip и не делает второй HTTP-запрос к источнику. ## 5. Обновление ```bash git pull --ff-only docker compose --env-file .env.production -f compose.production.yaml build ./deploy/backup.sh /srv/rf4-backups docker compose --env-file .env.production -f compose.production.yaml run --rm migrate docker compose --env-file .env.production -f compose.production.yaml up -d --no-deps api web community-scheduler docker compose --env-file .env.production -f compose.production.yaml ps curl -fsS https://rf4spotter.ru/ready ``` Перед обновлением со сменой схемы обязателен backup PostgreSQL. Если миграция не началась или схема обратно совместима, верните предыдущий Git commit/images и повторите rollout без downgrade Alembic. Если миграция изменила данные несовместимо, остановите API/web и восстановите сделанный перед release backup через `restore.sh`, затем запустите предыдущую ревизию. Не удаляйте volumes, не используйте `down -v` и не выполняйте `alembic downgrade` без отдельно проверенного плана конкретной миграции. ## 6. Резервное копирование и восстановление Храните копии вне диска приложения. Скрипт создаёт PostgreSQL dump, архив MinIO и контрольные суммы в новом каталоге с UTC-временем: ```bash ./deploy/backup.sh /srv/rf4-backups ``` Восстановление заменяет содержимое PostgreSQL и MinIO данными из выбранной копии, временно останавливая API и web. Это намеренно защищённая подтверждением операция: ```bash CONFIRM_RESTORE=rf4-spotter ./deploy/restore.sh /srv/rf4-backups/20260906T120000Z curl -fsS https://rf4spotter.ru/ready ``` Репозиторий содержит изолированный drill, который создаёт отдельные Compose volumes, портит тестовые данные, восстанавливает их и сравнивает PostgreSQL и MinIO: ```bash ./deploy/test-backup-restore.sh ``` Drill успешно пройден 6 сентября 2026 года. На целевом сервере всё равно проведите учебное восстановление с реальной зашифрованной копией перед приглашением пользователей. Затем настройте ежедневный запуск `backup.sh`, выгрузку копий во внешнее хранилище и уведомление при ошибке; храните минимум 7 ежедневных и 4 еженедельных копии. Полный production bootstrap дополнительно запускается отдельным CI workflow вручную и еженедельно. Он не удваивает быстрый Compose E2E на каждом push; полный лог сохраняется всегда, а при ошибке — также Compose status и браузерные diagnostics. ## 7. Ежедневное обслуживание После успешного backup сначала проверьте план очистки, затем примените его: ```bash docker compose --env-file .env.production -f compose.production.yaml exec -T api python -m app.cli cleanup-retention docker compose --env-file .env.production -f compose.production.yaml exec -T api python -m app.cli cleanup-retention --apply ``` Сроки и состав данных описаны в [`docs/data-retention.md`](../docs/data-retention.md). Автоматизацию включайте только после проверки dry-run на рабочем наборе. После ручной проверки установите ежедневный timer. `maintenance.sh` использует lock от параллельного запуска и применяет retention только после успешного backup: ```bash sudo cp deploy/systemd/rf4spotter-maintenance.service /etc/systemd/system/ sudo cp deploy/systemd/rf4spotter-maintenance.timer /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now rf4spotter-maintenance.timer systemctl list-timers rf4spotter-maintenance.timer ``` Шаблон рассчитан на пользователя `rf4spotter`, каталог `/opt/rf4-spotter` и наличие `flock` из `util-linux`. Пользователь должен иметь доступ к Docker socket и каталогу `BACKUP_ROOT`. Результат каждого запуска хранится в systemd journal. Docker JSON-логи production-сервисов ограничены пятью файлами по 10 МБ на контейнер. ## 8. Мониторинг После настройки DNS, TLS и первого backup выполните: ```bash ./deploy/monitor.sh ``` Проверка контролирует контейнеры, `/ready`, диск, объём PostgreSQL/MinIO, свежесть backup и срок TLS. Установка systemd timer, пороги и порядок реакции описаны в [`docs/production-monitoring.md`](../docs/production-monitoring.md). До подключения реального канала уведомлений одного журнала systemd недостаточно. ## 9. Что ещё блокирует публичное открытие альфы - подключение уведомлений о сбоях мониторинга; - проверка DNS/TLS и полного запуска на целевом сервере; - внешнее зашифрованное хранилище резервных копий. - действующие `privacy@rf4spotter.ru` и `abuse@rf4spotter.ru`, публичные правила и privacy notice; - проверка rate limit и очереди модерации под ожидаемой публичной нагрузкой. До закрытия этих пунктов контур можно поднять для технической проверки домена, но не следует открывать форму без ограничения доступа.