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