diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..f3aaeb1 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,46 @@ +# Caddyfile for the blog behind Cloudflare. +# +# Topology: Cloudflare (terminates TLS) -> Caddy (HTTP :80) -> SWS (blog:80) +# +# Cloudflare handles the public HTTPS cert, so Caddy serves plain HTTP on :80 +# and does NOT need the Cloudflare DNS-01 / automatic-HTTPS setup. Set the +# Cloudflare SSL/TLS mode to "Full" so CF->origin is encrypted at the network +# layer (e.g. over your tunnel/Netbird), even though this listener is HTTP. +# +# Copy this file to /etc/caddy/Caddyfile on the caddy_cf host and reload: +# docker exec caddy_cf caddy reload --config /etc/caddy/Caddyfile +# or restart the container. +{ + # Trust Cloudflare so real visitor IPs (Cf-Connecting-Ip / X-Forwarded-For) + # are used for logging and remote_ip matchers instead of the CF edge IP. + servers { + trusted_proxies static private_ranges + client_ip_headers Cf-Connecting-Ip X-Forwarded-For + } +} + +# Bind to the hostname on the HTTP port only. Because the address has an +# explicit ":80" scheme/port, Caddy will NOT try to provision a TLS cert. +http://blog.ahmza.com { + # THE responder: proxy every request to the blog (SWS) container. + # This is what was missing before (requests fell through to a NOP -> blank page). + reverse_proxy blog:80 + + # Compression happens here (SWS has it disabled on purpose). + encode zstd gzip + + # Security headers (single source of truth; SWS has security-headers off). + header { + Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" + X-Content-Type-Options "nosniff" + X-Frame-Options "SAMEORIGIN" + Referrer-Policy "strict-origin-when-cross-origin" + # Drop Caddy's default Server header. + -Server + } + + log { + output stdout + format console + } +}