- Add Redis 7 for pub/sub (lobby + chat real-time), rate limiting, caching - Replace SSE DB polling with Redis pub/sub (lobby: instant approval, chat: instant delivery) - Add PgBouncer (transaction mode, 500 client → 25 pool connections) - Chat SSE stream via Redis pub/sub instead of 3s polling - Optimistic UI in ChatPanel (messages appear before server confirms) - Redis-based rate limiter (works across multiple app replicas) - Prisma query optimization (select only needed fields) - Chat message cache in Redis (10s TTL) - Docker Compose: add redis, pgbouncer services with healthchecks - Production: resource limits, 2 app replicas behind Traefik - Update CLAUDE.md, README.md, .env.example, setup.sh Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
76 lines
2.3 KiB
YAML
76 lines
2.3 KiB
YAML
# Продакшен — Traefik + Let's Encrypt
|
|
# Запуск: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
|
|
|
services:
|
|
traefik:
|
|
image: traefik:v3
|
|
command:
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.exposedbydefault=false"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.websecure.address=:443"
|
|
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
|
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
|
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
|
|
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- letsencrypt_data:/letsencrypt
|
|
restart: unless-stopped
|
|
|
|
app:
|
|
environment:
|
|
NEXT_PUBLIC_APP_URL: https://${DOMAIN}
|
|
BETTER_AUTH_URL: https://${DOMAIN}
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 1G
|
|
reservations:
|
|
memory: 512M
|
|
replicas: 2
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.app.rule=Host(`${DOMAIN}`)"
|
|
- "traefik.http.routers.app.entrypoints=websecure"
|
|
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.app.loadbalancer.server.port=3000"
|
|
|
|
minio:
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.minio-api.rule=Host(`s3.${DOMAIN}`)"
|
|
- "traefik.http.routers.minio-api.entrypoints=websecure"
|
|
- "traefik.http.routers.minio-api.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.minio-api.service=minio-api"
|
|
- "traefik.http.services.minio-api.loadbalancer.server.port=9000"
|
|
- "traefik.http.routers.minio-console.rule=Host(`minio.${DOMAIN}`)"
|
|
- "traefik.http.routers.minio-console.entrypoints=websecure"
|
|
- "traefik.http.routers.minio-console.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.minio-console.service=minio-console"
|
|
- "traefik.http.services.minio-console.loadbalancer.server.port=9001"
|
|
|
|
redis:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 256M
|
|
|
|
postgres:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 1G
|
|
|
|
ai-agent:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 2G
|
|
|
|
volumes:
|
|
letsencrypt_data:
|