92 lines
2.8 KiB
Caddyfile
92 lines
2.8 KiB
Caddyfile
# ----------------------------------------------------------------------------
|
||
# Caddyfile – fronts the Astro app, terminates TLS, and runs the Coraza WAF
|
||
# with the OWASP Core Rule Set loaded.
|
||
# ----------------------------------------------------------------------------
|
||
{
|
||
# Make sure the WAF runs before the reverse-proxy handler.
|
||
order coraza_waf first
|
||
order file_server before reverse_proxy
|
||
|
||
# Email used for Let's Encrypt account registration.
|
||
email {$ACME_EMAIL:admin@example.com}
|
||
}
|
||
|
||
# ----------------------------------------------------------------------------
|
||
# Public site
|
||
# ----------------------------------------------------------------------------
|
||
{$SITE_ADDRESS:http://:80} {
|
||
encode zstd gzip
|
||
|
||
# ------------------------------------------------------------------
|
||
# WAF – Coraza + OWASP Core Rule Set (Top 10 protections)
|
||
# ------------------------------------------------------------------
|
||
coraza_waf {
|
||
load_owasp_crs
|
||
|
||
directives `
|
||
Include @coraza.conf-recommended
|
||
Include @crs-setup.conf.example
|
||
Include @owasp_crs/*.conf
|
||
SecRuleEngine On
|
||
SecRequestBodyAccess On
|
||
SecResponseBodyAccess Off
|
||
SecDefaultAction "phase:1,log,auditlog,deny,status:403"
|
||
SecDefaultAction "phase:2,log,auditlog,deny,status:403"
|
||
`
|
||
}
|
||
|
||
# ------------------------------------------------------------------
|
||
# TLS via ACME DNS-01 with the Google Cloud DNS provider.
|
||
# Falls back to no-TLS automatically when SITE_ADDRESS is http://...
|
||
# ------------------------------------------------------------------
|
||
tls {
|
||
dns googleclouddns {
|
||
gcp_project {$GCP_PROJECT}
|
||
}
|
||
resolvers 8.8.8.8 1.1.1.1
|
||
}
|
||
|
||
# ------------------------------------------------------------------
|
||
# Maintenance Page Handling
|
||
# ------------------------------------------------------------------
|
||
handle_errors {
|
||
@502_503 {
|
||
expression {err.status} in [502, 503]
|
||
}
|
||
handle @502_503 {
|
||
root * /etc/caddy/maintenance
|
||
rewrite * /maintenance.html
|
||
file_server
|
||
}
|
||
}
|
||
|
||
# ------------------------------------------------------------------
|
||
# Reverse-proxy to the Astro container. Caddy is on the host network
|
||
# namespace, so we connect over loopback to the port the app container
|
||
# publishes on 127.0.0.1 / [::1]:4321.
|
||
# ------------------------------------------------------------------
|
||
reverse_proxy 127.0.0.1:4321 {
|
||
header_up X-Real-IP {remote_host}
|
||
header_up X-Forwarded-Proto {scheme}
|
||
}
|
||
|
||
# Standard hardening headers
|
||
header {
|
||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||
X-Content-Type-Options "nosniff"
|
||
X-Frame-Options "SAMEORIGIN"
|
||
Referrer-Policy "strict-origin-when-cross-origin"
|
||
-Server
|
||
}
|
||
|
||
log {
|
||
output file /var/log/caddy/access.log {
|
||
roll_size 10MiB
|
||
roll_keep 5
|
||
roll_keep_for 168h
|
||
}
|
||
format json
|
||
}
|
||
}
|