Caddyfile.example
Rama main · réplica de lectura del repositorio original.
# Filtre dels registres: IP escapçada, sense query i sense els noms de
# professor o assignatura de la URI. Comproveu-lo en desplegar amb una petició
# de prova (DESPLEGAMENT.md): una configuració vàlida no vol dir que filtri.
(format-registres) {
format filter {
request>remote_ip ip_mask 24 48
request>client_ip ip_mask 24 48
request>headers>X-Forwarded-For delete
request>uri multi_regexp {
regexp "[?].*$" ""
# Substitucions: absències, hores-professor i assignació manual;
# Estadístiques: detall del professor.
regexp "^(/api/(?:substitucions/[^/]+/[^/]+|estadistiques/professor)/).+$" "${1}{professor}"
regexp "^(/api/config/assignatures/[^/]+/).+$" "${1}{nom}"
regexp "^(/api/prioritats/no-substituir/).+$" "${1}{assignatura}"
}
wrap json
}
}
{
# El filtre també s'aplica als errors interns de Caddy amb una petició.
log default {
import format-registres
}
}
el-teu-domini.exemple.com {
encode zstd gzip
# Access log persistent.
#
# Sense aquest bloc, l'únic registre de peticions són els logs del
# contenidor (`docker compose logs`), que es perden cada cop que es
# reconstrueix la imatge — és a dir, a cada desplegament. Escriure'l a un
# volum del host permet revisar a posteriori l'activitat del servidor.
# El `docker-compose.yml.example` ja hi munta `./logs/caddy`.
#
# Les adreces IP es desen escapçades (vegeu `format filter`), de manera que
# el registre no identifica ningú. Els fitxers rotats es conserven com a màxim 30 dies (720 h),
# també limitats a 10 còpies. El filtre treu la query i els noms de la URI.
log {
output file /var/log/caddy/access.log {
roll_size 10MiB
roll_keep 10
roll_keep_for 720h
}
# Sense l'adreça IP sencera: només la xarxa (83.45.127.19 → 83.45.127.0),
# que no identifica ningú i permet comptar visites aproximades.
import format-registres
}
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
# Filtre XSS antic dels navegadors, desactivat: la CSP en fa la feina
X-XSS-Protection "0"
Referrer-Policy "strict-origin-when-cross-origin"
# Sempre per https durant un any (només aquest domini, no els subdominis)
Strict-Transport-Security "max-age=31536000"
# Només es pot carregar codi, estils i dades del mateix domini. Si
# afegiu recursos externs (fonts, analítiques...), cal afegir-los aquí.
Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
# No anunciar quin programari hi ha al darrere
-Server
-Via
}
# Memòria cau: les dades de l'API no es guarden mai al navegador (ordinadors
# compartits); els fitxers amb hash al nom no canvien mai; l'HTML es revalida
# sempre, perquè després d'un desplegament apunti als fitxers nous.
@api path /api/*
@assets path /assets/*
@html not path /api/* /assets/*
header @api >Cache-Control "no-store"
header @assets >Cache-Control "public, max-age=31536000, immutable"
header @html >Cache-Control "no-cache"
# Les pujades (XML d'horari, logo, CSV) són petites
request_body {
max_size 10MB
}
handle /api/* {
reverse_proxy backend:8000 {
header_down -Server
}
}
handle {
reverse_proxy frontend:80 {
header_down -Server
}
}
}