# 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 # Schema files (YAML/JSON) should never be cached by browsers # This ensures frontend always fetches fresh schema content after updates @schemas { path /schemas/* } handle @schemas { header Cache-Control "no-cache, must-revalidate" header Pragma "no-cache" file_server { precompressed gzip br } } # 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 } }