littleshop/docker-compose.prod.yml
SysAdmin 68c5d2dfdf Production optimization: Docker configuration and monitoring stack
🚀 Docker Production Optimizations:
- Chiseled Ubuntu base image for minimal attack surface
- Non-root user execution with security hardening
- Read-only filesystem with targeted writable volumes
- Resource limits (1GB RAM, 1 CPU) with health checks
- Multi-stage builds optimized for caching
- Zero-downtime deployment automation

🔍 Comprehensive Monitoring Stack:
- Prometheus metrics collection with custom rules
- Grafana dashboards for application visualization
- AlertManager with email notifications for critical events
- Fluentd centralized logging with retention policies
- Node Exporter + cAdvisor for system/container metrics
- Health check endpoint (/health) for container orchestration

📋 Production Deployment Ready:
- Complete deployment scripts with backup strategy
- Environment templates for secure configuration
- Performance monitoring and alerting rules
- Enterprise-grade security and observability

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 12:35:41 +01:00

151 lines
5.0 KiB
YAML

version: '3.8'
services:
littleshop:
build:
context: .
dockerfile: Dockerfile
target: final
image: littleshop:production
container_name: littleshop_prod
restart: unless-stopped
# Resource limits for production
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
cpus: '0.5'
# Security configuration
security_opt:
- no-new-privileges:true
read_only: true
# Temporary file systems for read-only container
tmpfs:
- /tmp:noexec,nosuid,size=100m
- /var/tmp:noexec,nosuid,size=50m
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:8080
- DOTNET_ENVIRONMENT=Production
- DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
- DOTNET_RUNNING_IN_CONTAINER=true
- DOTNET_USE_POLLING_FILE_WATCHER=true
- ASPNETCORE_FORWARDEDHEADERS_ENABLED=true
# Application secrets (from environment or .env file)
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
- BTCPAY_SERVER_URL=${BTCPAY_SERVER_URL}
- BTCPAY_STORE_ID=${BTCPAY_STORE_ID}
- BTCPAY_API_KEY=${BTCPAY_API_KEY}
- BTCPAY_WEBHOOK_SECRET=${BTCPAY_WEBHOOK_SECRET}
volumes:
# Persistent data volumes (writable)
- littleshop_data:/app/data:rw
- littleshop_uploads:/app/wwwroot/uploads:rw
- littleshop_logs:/app/logs:rw
networks:
- traefik
- littleshop_internal
# Health check
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# Traefik configuration for production
- "traefik.enable=true"
- "traefik.docker.network=traefik"
# HTTP to HTTPS redirect
- "traefik.http.routers.littleshop-http.rule=Host(`littleshop.silverlabs.uk`)"
- "traefik.http.routers.littleshop-http.entrypoints=web"
- "traefik.http.routers.littleshop-http.middlewares=littleshop-redirect"
- "traefik.http.middlewares.littleshop-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.littleshop-redirect.redirectscheme.permanent=true"
# HTTPS Router with security headers
- "traefik.http.routers.littleshop.rule=Host(`littleshop.silverlabs.uk`)"
- "traefik.http.routers.littleshop.entrypoints=websecure"
- "traefik.http.routers.littleshop.tls=true"
- "traefik.http.routers.littleshop.tls.certresolver=letsencrypt"
- "traefik.http.routers.littleshop.middlewares=littleshop-security,littleshop-headers"
# Service configuration
- "traefik.http.services.littleshop.loadbalancer.server.port=8080"
- "traefik.http.services.littleshop.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.littleshop.loadbalancer.healthcheck.interval=30s"
# Security headers middleware
- "traefik.http.middlewares.littleshop-security.headers.frameDeny=true"
- "traefik.http.middlewares.littleshop-security.headers.sslRedirect=true"
- "traefik.http.middlewares.littleshop-security.headers.browserXssFilter=true"
- "traefik.http.middlewares.littleshop-security.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.littleshop-security.headers.forceSTSHeader=true"
- "traefik.http.middlewares.littleshop-security.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.littleshop-security.headers.stsPreload=true"
- "traefik.http.middlewares.littleshop-security.headers.stsSeconds=31536000"
- "traefik.http.middlewares.littleshop-security.headers.referrerPolicy=strict-origin-when-cross-origin"
- "traefik.http.middlewares.littleshop-security.headers.permissionsPolicy=camera=(), microphone=(), geolocation=()"
# Custom headers for forwarded requests
- "traefik.http.middlewares.littleshop-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.littleshop-headers.headers.customrequestheaders.X-Forwarded-Host=littleshop.silverlabs.uk"
- "traefik.http.middlewares.littleshop-headers.headers.customrequestheaders.X-Real-IP="
# Log aggregation service (optional)
fluentd:
image: fluent/fluentd:v1.16-1
container_name: littleshop_logs
restart: unless-stopped
volumes:
- littleshop_logs:/fluentd/log:ro
- ./docker/fluentd.conf:/fluentd/etc/fluent.conf:ro
networks:
- littleshop_internal
depends_on:
- littleshop
# Optimized volume configuration
volumes:
littleshop_data:
driver: local
driver_opts:
type: none
o: bind
device: /opt/littleshop/data
littleshop_uploads:
driver: local
driver_opts:
type: none
o: bind
device: /opt/littleshop/uploads
littleshop_logs:
driver: local
driver_opts:
type: none
o: bind
device: /opt/littleshop/logs
# Network isolation
networks:
traefik:
external: true
littleshop_internal:
driver: bridge
internal: true
ipam:
config:
- subnet: 172.20.0.0/24