deploy-production-readiness.md 6.4 KB

Deploy: Production Readiness Checklist

Контекст: В deploy/ есть docker-compose.prod.yml, deploy.sh, env.prod. Локально — docker-compose.yml + Makefile. Обновлено 2026-06 — добавлен Caddy reverse proxy, но есть ещё проблемы.

Суть

Проект разворачивается, Caddy настроен как reverse proxy с health headers и безопасными заголовками. Однако есть риски безопасности, надёжности и операционности.

Критические проблемы (P0)

Проблема Файл Риск
Secrets в plain text env.prod, docker-compose.yml Утечка БД, JWT, S3 при коммите / доступе к серверу
Миграции не гарантированно накатываются docker-compose.prod.yml:52 migrate/migrate sidecar без retry логики
Single instance БД/Redis/MinIO docker-compose.prod.yml SPOF, нет HA, нет бэкапов
Hardcoded IP в env.prod env.prod Не переносимо, не работает за доменом
CSP с unsafe-inline и unsafe-eval Caddyfile:40 XSS-защита ослаблена (см. [[atomic-csp-hardening]])
Redis — SPOF для rate limiter fail-closed в production (503 при падении) [[atomic-redis-rate-limiter-failopen-failclosed]]

Текущая конфигурация Caddy

# deploy/Caddyfile — уже работает как reverse proxy
http://api.{$DOMAIN} {
    reverse_proxy backend:8080
    header { ... }
}

http://{$DOMAIN} {
    reverse_proxy frontend:3000
    header {
        Content-Security-Policy "..."
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
    }
    encode zstd gzip
}

Что уже хорошо:

  • ✅ Reverse Proxy для frontend + backend
  • ✅ X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy
  • ✅ Content-Security-Policy (хотя и с unsafe-inline)
  • ✅ Cache-Control для статики
  • ✅ zstd + gzip encoding

Что нужно исправить:

  • ❌ Используется http://, а не HTTPS (Caddy умеет авто-HTTPS через Let's Encrypt)
  • ❌ CSP с unsafe-inline и unsafe-eval (см. [[atomic-csp-hardening]])
  • ❌ Нет HSTS заголовка

Рекомендуемые изменения

1. Secrets Management

# Не хранить секреты в репозитории!
# Использовать:
# - Docker secrets (swarm mode)
# - HashiCorp Vault / AWS Secrets Manager / 1Password CLI
# - .env файл только на сервере (chmod 600), в .gitignore

2. HTTPS (убрать http:// из Caddyfile)

# Caddyfile — авто-HTTPS через Let's Encrypt
photoplaces.ru {
    reverse_proxy frontend:3000
}

api.photoplaces.ru {
    reverse_proxy backend:8080
}

Caddy автоматически получит сертификаты для перечисленных доменов.

3. Healthchecks для всех сервисов

backend:
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/api/v1/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

4. Database Backups

postgres-backup:
    image: prodrigestivill/postgres-backup-local
    environment:
      SCHEDULE: "@daily"
      BACKUP_KEEP_DAYS: 30

5. Логирование и мониторинг

  • Loki + Promtail для логов
  • Prometheus + Grafana для метрик
  • Настроить алерты: падение Redis >5min, error rate >1%, p99 latency >500ms

6. Healthcheck зависимость (fix)

В текущем docker-compose.yml есть проблема: backend healthcheck использует curl к самому себе на /api/v1/health, но этот эндпоинт доступен только после старта Go приложения. Это может создать циклическое ожидание с depends_on из frontend. Рекомендуется:

  • Добавить простой healthcheck для backend (TCP check на порт 8080)
  • Или сделать /health на уровне Caddy/Router перед Go-обработчиками

Чек-лист перед продакшеном

  • Все секреты вынесены из репозитория
  • Настроен HTTPS (Let's Encrypt / Caddy авто-HTTPS)
  • Убрать http:// из Caddyfile — перейти на домены
  • Healthchecks на всех сервисах (working!)
  • Redis Sentinel/Cluster для HA (чтобы не было SPOF)
  • Автоматические бэкапы БД (проверено restore)
  • Логи агрегируются (Loki/ELK)
  • Метрики собираются (Prometheus + Grafana)
  • Настроены алерты (down, high error rate, high latency)
  • CSP hardening: nonce вместо unsafe-inline, strict-dynamic ([[atomic-csp-hardening]])
  • Rate limiting: fail-open/closed стратегия ([[atomic-redis-rate-limiter-failopen-failclosed]])
  • CORS настроен только для продакшен доменов
  • Security headers (CSP, HSTS, X-Frame-Options)
  • Нагрузочное тестирование пройдено
  • Graceful shutdown проверен (освобождение портов, закрытие соединений)
  • Падение Redis: что происходит с rate limiter (должен быть alarm + fallback)

Связанные заметки

  • [[backend-rate-limiting]] — rate limiter с fail-closed в production
  • [[atomic-csp-hardening]] — CSP hardening
  • [[atomic-redis-rate-limiter-failopen-failclosed]] — Fail-open/closed стратегия
  • [[architecture-overview]] — общий обзор и таблица P0-P2
  • [[MOC-security-patterns]] — карта безопасности
  • [[decision-validation-error-production]] — скрытие ошибок

Источник

Code review PhotoPlaces 2026-06. Проверка production readiness + обновление после внедрения Caddy.

Теги

#deploy #docker #production #security #monitoring #best-practice