88 lines
2.8 KiB
Caddyfile
88 lines
2.8 KiB
Caddyfile
# Caddy config for the Vaultwarden reverse proxy.
|
|
#
|
|
# Two non-obvious things:
|
|
#
|
|
# 1. Coraza runs DetectionOnly by design (see plan). The WAF observes
|
|
# and audit-logs; it does not block. Flipping to On would silently
|
|
# false-positive on attachment uploads and Sends — encrypted payloads
|
|
# look exactly like the things CRS is trained to flag.
|
|
#
|
|
# 2. /admin is matched into a 404 outside the WG subnet. Returning 404
|
|
# (not 401/403) hides the route's existence from public scanners.
|
|
# Vaultwarden's ADMIN_TOKEN is unset by default anyway, but this keeps
|
|
# the panel inaccessible even if a future change re-enables it.
|
|
{
|
|
# Required for Coraza to plug into the request pipeline before
|
|
# reverse_proxy. See coraza-caddy README.
|
|
order coraza_waf first
|
|
}
|
|
|
|
{$VAULT_FQDN} {
|
|
tls {
|
|
# Credentials come from the SA JSON at GOOGLE_APPLICATION_CREDENTIALS,
|
|
# but the project does not: the module refuses to load without
|
|
# gcp_project ("missing Google Cloud project ID"). The zone lookup
|
|
# lists the project's zones, so the SA needs project-level
|
|
# dns.managedZones.list on top of its zone-scoped dns.admin.
|
|
dns googleclouddns {
|
|
gcp_project {$GCP_PROJECT}
|
|
}
|
|
}
|
|
|
|
encode zstd gzip
|
|
|
|
coraza_waf {
|
|
# Mounts the embedded CRS filesystem; without it the @-prefixed
|
|
# Includes below fail with "no such file or directory".
|
|
load_owasp_crs
|
|
directives `
|
|
Include @coraza.conf-recommended
|
|
Include @crs-setup.conf.example
|
|
Include @owasp_crs/*.conf
|
|
SecRuleEngine DetectionOnly
|
|
SecAuditEngine RelevantOnly
|
|
SecAuditLog /var/log/caddy/coraza-audit.log
|
|
SecAuditLogParts ABIJDEFHZ
|
|
SecAuditLogFormat JSON
|
|
`
|
|
}
|
|
|
|
# /admin from a WG-subnet client → reverse proxy normally.
|
|
@admin_from_wg {
|
|
path /admin*
|
|
remote_ip {$WG_SUBNET}
|
|
}
|
|
handle @admin_from_wg {
|
|
reverse_proxy http://vaultwarden:8080 {
|
|
header_up X-Real-IP {remote_host}
|
|
header_up X-Forwarded-For {remote_host}
|
|
header_up X-Forwarded-Proto https
|
|
}
|
|
}
|
|
|
|
# /admin from anywhere else → 404 (hide route existence).
|
|
@admin_elsewhere path /admin*
|
|
handle @admin_elsewhere {
|
|
respond 404
|
|
}
|
|
|
|
# Everything else (sync API, web vault, /notifications/hub websocket).
|
|
handle {
|
|
reverse_proxy http://vaultwarden:8080 {
|
|
header_up X-Real-IP {remote_host}
|
|
header_up X-Forwarded-For {remote_host}
|
|
header_up X-Forwarded-Proto https
|
|
}
|
|
}
|
|
|
|
log {
|
|
output file /var/log/caddy/access.log {
|
|
roll_size 50MiB
|
|
roll_keep 5
|
|
roll_keep_for 720h
|
|
}
|
|
format json
|
|
}
|
|
}
|