Some checks failed
CI / Unit & Component Tests (pull_request) Successful in 3m21s
CI / OCR Service Tests (pull_request) Successful in 23s
CI / fail2ban Regex (pull_request) Has been cancelled
CI / Semgrep Security Scan (pull_request) Has been cancelled
CI / Compose Bucket Idempotency (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / Unit & Component Tests (push) Successful in 3m18s
CI / OCR Service Tests (push) Successful in 21s
CI / Backend Unit Tests (push) Successful in 3m45s
CI / fail2ban Regex (push) Successful in 44s
CI / Semgrep Security Scan (push) Successful in 21s
CI / Compose Bucket Idempotency (push) Successful in 1m3s
nightly / deploy-staging (push) Successful in 2m14s
Promote the future-CSP constraint from an inline Caddyfile comment to a durable ADR-028: serve the pdf.js wasm decoders same-origin (never a CDN), any future CSP must allow 'wasm-unsafe-eval' + worker-src 'self' blob:, and the build-time guard keeps the wasm shipping. Caddyfile now points at the ADR. Addresses re-review: Markus (constraint should be an ADR, not a comment). Refs #708 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
106 lines
3.1 KiB
Caddyfile
106 lines
3.1 KiB
Caddyfile
# Caddyfile for the Familienarchiv host.
|
|
#
|
|
# Caddy runs on the host (not in a container) and reverse-proxies into
|
|
# the docker compose stacks bound to 127.0.0.1.
|
|
#
|
|
# Naming convention for ports (also documented in docker-compose.prod.yml):
|
|
# production: backend 8080, frontend 3000
|
|
# staging: backend 8081, frontend 3001
|
|
# gitea: 3005
|
|
#
|
|
# Security headers and the /actuator block apply to both archive vhosts.
|
|
# X-Frame-Options is deliberately NOT set here: Spring Security configures
|
|
# frame-options SAMEORIGIN (for the in-app PDF preview iframe). Setting
|
|
# DENY in Caddy would conflict.
|
|
|
|
(security_headers) {
|
|
header {
|
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
|
X-Content-Type-Options "nosniff"
|
|
Referrer-Policy "strict-origin-when-cross-origin"
|
|
# Deny browser APIs the app does not use. Reduces blast radius of an
|
|
# XSS landing in a privileged origin: a payload cannot silently turn
|
|
# on the microphone or read geolocation.
|
|
Permissions-Policy "camera=(), microphone=(), geolocation=()"
|
|
# No Content-Security-Policy is set yet. When one is added, it MUST
|
|
# include `script-src 'wasm-unsafe-eval'` and `worker-src 'self' blob:`
|
|
# or the pdf.js WebAssembly image decoders (JBIG2/CCITTFax/JPEG2000)
|
|
# and worker will be blocked and scanned PDFs render blank.
|
|
# See #708 and docs/adr/028-pdfjs-wasm-decoders-and-csp-constraint.md.
|
|
-Server
|
|
}
|
|
}
|
|
|
|
(block_actuator) {
|
|
# Defense in depth: even if management.endpoints.web.exposure.include grows
|
|
# in application.yaml, /actuator/* is unreachable externally. The internal
|
|
# Prometheus scrape (future) talks to the backend directly on the docker
|
|
# network, not via Caddy.
|
|
#
|
|
# Why a `handle` block and not a top-level `respond @matcher`: each archive
|
|
# vhost has a catch-all `handle { reverse_proxy ... }` that matches every
|
|
# path including /actuator/*, and Caddy's `handle` blocks are mutually
|
|
# exclusive. Without our own `handle /actuator/*` the catch-all wins, the
|
|
# request is proxied to the backend, and Spring Security 302s to /login
|
|
# instead of Caddy returning 404. See #512.
|
|
handle /actuator/* {
|
|
respond 404
|
|
}
|
|
}
|
|
|
|
(access_log) {
|
|
# JSON access log for fail2ban. The jail at infra/fail2ban/familienarchiv.conf
|
|
# watches this file for 401 responses on /api/auth/login.
|
|
# Caddy auto-creates /var/log/caddy/ when running as the `caddy` system user.
|
|
log {
|
|
output file /var/log/caddy/access.log {
|
|
roll_size 10mb
|
|
roll_keep 14
|
|
}
|
|
format json
|
|
}
|
|
}
|
|
|
|
archiv.raddatz.cloud {
|
|
import security_headers
|
|
import block_actuator
|
|
import access_log
|
|
|
|
handle /api/* {
|
|
reverse_proxy 127.0.0.1:8080
|
|
}
|
|
|
|
handle {
|
|
reverse_proxy 127.0.0.1:3000
|
|
}
|
|
}
|
|
|
|
staging.raddatz.cloud {
|
|
import security_headers
|
|
import block_actuator
|
|
import access_log
|
|
|
|
handle /api/* {
|
|
reverse_proxy 127.0.0.1:8081
|
|
}
|
|
|
|
handle {
|
|
reverse_proxy 127.0.0.1:3001
|
|
}
|
|
}
|
|
|
|
git.raddatz.cloud {
|
|
import security_headers
|
|
reverse_proxy 127.0.0.1:3005
|
|
}
|
|
|
|
grafana.archiv.raddatz.cloud {
|
|
import security_headers
|
|
reverse_proxy 127.0.0.1:3003
|
|
}
|
|
|
|
glitchtip.archiv.raddatz.cloud {
|
|
import security_headers
|
|
reverse_proxy 127.0.0.1:3002
|
|
}
|