Files
rf4-spotter/deploy/README.md
T

176 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Развёртывание открытой альфы 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 еженедельных копии.
## 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 и очереди модерации под ожидаемой публичной нагрузкой.
До закрытия этих пунктов контур можно поднять для технической проверки домена, но не следует открывать форму без ограничения доступа.