diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 00000000..d4eccaf3 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,29 @@ +services: + traefik: + # Use hardened Traefik config in production (no staging CA, no tracing/metrics) + volumes: + - ./services/traefik/traefik.prod.yml:/etc/traefik/traefik.yml:ro + - ./services/traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro + - ./services/traefik/acme.json:/acme.json + ports: + - "80:80" + - "443:443" + + # Remove public exposure of internal datastores in production + db: + ports: [] + + redis: + ports: [] + +## Usage (examples): +## - With explicit files (recommended): +## docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d traefik caddy php1 php2 php3 php4 php5 db redis +## +## - Or set COMPOSE_FILE for the shell session (PowerShell on Windows): +## $env:COMPOSE_FILE = "docker-compose.yml;docker-compose.prod.yml" +## docker compose up -d traefik caddy php1 php2 php3 php4 php5 db redis +## +## Notes: +## - Traefik uses Let’s Encrypt production. Ensure DNS A/AAAA records for api.truckwash.dk and traefik.truckwash.dk point to this host and ports 80/443 are reachable. +## - The dashboard is protected by basic auth and an IP allowlist (defined in dynamic.yml). Replace the bcrypt hash before enabling in production. \ No newline at end of file diff --git a/services/traefik/dynamic.yml b/services/traefik/dynamic.yml index 07ae2162..5348e3d4 100644 --- a/services/traefik/dynamic.yml +++ b/services/traefik/dynamic.yml @@ -33,9 +33,38 @@ http: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 + secure-headers: + headers: + sslRedirect: true + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: false + contentTypeNosniff: true + browserXssFilter: true + referrerPolicy: "strict-origin-when-cross-origin" + customFrameOptionsValue: "SAMEORIGIN" + permissionsPolicy: "geolocation=(), microphone=(), camera=(), payment=()" + addVaryHeader: true + api-ratelimit: + rateLimit: + average: 100 + burst: 200 services: cloud-svc: loadBalancer: servers: - url: "http://94.130.142.41:11000" + +tls: + options: + default: + minVersion: VersionTLS12 + sniStrict: true + cipherSuites: + - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 + - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 diff --git a/services/traefik/traefik.prod.yml b/services/traefik/traefik.prod.yml new file mode 100644 index 00000000..cbc674ca --- /dev/null +++ b/services/traefik/traefik.prod.yml @@ -0,0 +1,28 @@ +entryPoints: + web: + address: ":80" + websecure: + address: ":443" + +providers: + docker: + exposedByDefault: false + file: + filename: /etc/traefik/dynamic.yml + watch: true + +api: + dashboard: true + +log: + level: WARN + +accessLog: {} + +certificatesResolvers: + le: + acme: + email: jb@truckwash.dk + storage: /acme.json + httpChallenge: + entryPoint: web \ No newline at end of file