glam/infrastructure/caddy/Caddyfile
2025-12-30 03:43:31 +01:00

574 lines
11 KiB
Caddyfile

# Global options
{
email admin@bronhouder.nl
servers {
timeouts {
read_body 30s
read_header 10s
write 900s
idle 120s
}
max_header_size 16KB
}
# Structured JSON logging for all requests
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 5
roll_keep_for 168h
}
format json
level INFO
}
}
(sparql_protection) {
request_body {
max_size 1MB
}
header X-Query-Timeout "60s"
}
(static_files) {
root * /var/www/glam-frontend
# CRITICAL FIX: Handle /assets/* separately - return 404 if not found
# This prevents SPA fallback from serving index.html for missing JS chunks
# which would cause "error loading dynamically imported module" errors
@assets {
path /assets/*
}
handle @assets {
# Check if file exists
@assets_exist file {path}
# Existing assets get long cache (they have content hashes in filenames)
route @assets_exist {
header Cache-Control "public, max-age=31536000, immutable"
file_server {
precompressed gzip br
}
}
# Missing assets return 404 with no-cache (browser should retry on refresh)
@assets_missing not file {path}
route @assets_missing {
header Cache-Control "no-cache, no-store, must-revalidate"
respond "Not Found" 404
}
}
# For all other paths: SPA behavior with try_files
handle {
# index.html should never be cached
@index {
path /
}
header @index Cache-Control "no-cache, no-store, must-revalidate"
# All HTML responses (including SPA fallback) should not be cached
header Content-Type text/html* Cache-Control "no-cache, no-store, must-revalidate"
try_files {path} /index.html
file_server {
precompressed gzip br
}
}
}
(archief_static_files) {
root * /var/www/archief-assistent
# Handle /assets/* - serve local if exists, fallback to bronhouder.nl for proxied SPA assets
@assets {
path /assets/*
}
handle @assets {
@assets_exist file {path}
route @assets_exist {
header Cache-Control "public, max-age=31536000, immutable"
file_server {
precompressed gzip br
}
}
# Fallback to bronhouder.nl for assets not found locally
# This handles assets loaded by proxied SPA routes (/datamap, /linkml, /browse, etc.)
@assets_missing not file {path}
route @assets_missing {
reverse_proxy https://bronhouder.nl {
header_up Host bronhouder.nl
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
transport http {
tls
read_timeout 30s
write_timeout 30s
}
}
}
}
# For all other paths: SPA behavior with try_files
handle {
@index {
path /
}
header @index Cache-Control "no-cache, no-store, must-revalidate"
header Content-Type text/html* Cache-Control "no-cache, no-store, must-revalidate"
try_files {path} /index.html
file_server {
precompressed gzip br
}
}
}
:80 {
handle /health {
respond "OK" 200
}
handle /ducklake/* {
uri strip_prefix /ducklake
reverse_proxy 127.0.0.1:8765 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/postgres/* {
uri strip_prefix /api/postgres
reverse_proxy 127.0.0.1:8001 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/geo/* {
uri strip_prefix /api/geo
reverse_proxy 127.0.0.1:8002 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/cache/* {
uri strip_prefix /api
reverse_proxy 127.0.0.1:8090 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /api/typedb/* {
uri strip_prefix /api/typedb
reverse_proxy 127.0.0.1:8003 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/sync/* {
reverse_proxy 127.0.0.1:8766 {
transport http {
read_timeout 900s
write_timeout 900s
}
}
}
handle /api/* {
reverse_proxy 127.0.0.1:8000 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
@sparqlQuery {
path /query
}
handle @sparqlQuery {
import sparql_protection
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /sparql/* {
import sparql_protection
uri strip_prefix /sparql
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /store* {
import sparql_protection
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /update* {
import sparql_protection
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /qdrant/* {
uri strip_prefix /qdrant
reverse_proxy 127.0.0.1:6333 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle {
import static_files
}
}
bronhouder.nl, www.bronhouder.nl {
# Site-specific logging for chunk load monitoring
log {
output file /var/log/caddy/bronhouder.log {
roll_size 50mb
roll_keep 3
roll_keep_for 72h
}
format json
level INFO
}
handle /health {
respond "OK" 200
}
handle /ducklake/* {
uri strip_prefix /ducklake
reverse_proxy 127.0.0.1:8765 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/postgres/* {
uri strip_prefix /api/postgres
reverse_proxy 127.0.0.1:8001 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/geo/* {
uri strip_prefix /api/geo
reverse_proxy 127.0.0.1:8002 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/cache/* {
uri strip_prefix /api
reverse_proxy 127.0.0.1:8090 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /api/typedb/* {
uri strip_prefix /api/typedb
reverse_proxy 127.0.0.1:8003 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle /api/sync/* {
reverse_proxy 127.0.0.1:8766 {
transport http {
read_timeout 900s
write_timeout 900s
}
}
}
handle /api/* {
reverse_proxy 127.0.0.1:8000 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
@sparqlQuery {
path /query
}
handle @sparqlQuery {
import sparql_protection
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /sparql/* {
import sparql_protection
uri strip_prefix /sparql
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /store* {
import sparql_protection
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /update* {
import sparql_protection
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle /qdrant/* {
uri strip_prefix /qdrant
reverse_proxy 127.0.0.1:6333 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
handle {
import static_files
}
}
sparql.bronhouder.nl {
import sparql_protection
reverse_proxy 127.0.0.1:7878 {
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
# ============================================================================
# ARCHIEF.SUPPORT - ArchiefAssistent (National Archives Services)
# ============================================================================
archief.support, www.archief.support {
# Site-specific logging
log {
output file /var/log/caddy/archief.log {
roll_size 50mb
roll_keep 3
roll_keep_for 72h
}
format json
level INFO
}
# Health check endpoint
handle /health {
respond "OK" 200
}
# ========================================================================
# Ontology routes - reverse proxy to bronhouder.nl SPA
# These routes serve the same content as bronhouder.nl but on archief.support
# Assets are handled by the fallback in archief_static_files snippet
# ========================================================================
# /linkml - LinkML schema viewer
handle /linkml* {
reverse_proxy https://bronhouder.nl {
header_up Host bronhouder.nl
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
transport http {
tls
read_timeout 30s
write_timeout 30s
}
}
}
# /datamap - Data mapping documentation
handle /datamap* {
reverse_proxy https://bronhouder.nl {
header_up Host bronhouder.nl
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
transport http {
tls
read_timeout 30s
write_timeout 30s
}
}
}
# /ontology-viewer - Ontology viewer (proxied from bronhouder.nl/ontology)
# Uses /ontology-viewer path to avoid conflict with SPA /ontology route
handle /ontology-viewer* {
# Rewrite /ontology-viewer to /ontology before proxying
uri replace /ontology-viewer /ontology
reverse_proxy https://bronhouder.nl {
header_up Host bronhouder.nl
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
transport http {
tls
read_timeout 30s
write_timeout 30s
}
}
}
# /browse - Institution browser (proxied from bronhouder.nl)
handle /browse* {
reverse_proxy https://bronhouder.nl {
header_up Host bronhouder.nl
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
transport http {
tls
read_timeout 30s
write_timeout 30s
}
}
}
# Authentication API - proxied to de Aa auth backend (port 8080)
handle /auth/* {
reverse_proxy 127.0.0.1:8080 {
transport http {
read_timeout 30s
write_timeout 30s
}
}
}
# DSPy RAG API - proxied to RAG backend (port 8010)
handle /api/dspy/* {
uri strip_prefix /api/dspy
reverse_proxy 127.0.0.1:8010 {
transport http {
read_timeout 180s
write_timeout 180s
}
}
}
# RAG API endpoints - direct access to RAG backend
handle /api/rag/* {
reverse_proxy 127.0.0.1:8010 {
transport http {
read_timeout 180s
write_timeout 180s
}
}
}
# Geo API - institution data and stats
handle /api/geo/* {
uri strip_prefix /api/geo
reverse_proxy 127.0.0.1:8002 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
# Cache API - Qdrant-backed semantic cache (same backend as RAG)
handle /api/cache/* {
reverse_proxy 127.0.0.1:8010 {
transport http {
read_timeout 30s
write_timeout 30s
}
}
}
# Fallback API proxy - shared backend with bronhouder.nl
handle /api/* {
reverse_proxy 127.0.0.1:8000 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
# DuckLake analytics API
handle /ducklake/* {
uri strip_prefix /ducklake
reverse_proxy 127.0.0.1:8765 {
transport http {
read_timeout 120s
write_timeout 120s
}
}
}
# Static files from archief-assistent build
handle {
import archief_static_files
}
}