From 696bc49290f8143ddeeab61ebb42863534307a71 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Wed, 1 Apr 2026 21:28:28 -0700 Subject: [PATCH] Add SPA cache policy for authentik in Caddy Authentik's frontend uses content-hashed JS chunks, but the HTML pages that reference them had no Cache-Control headers. When the server restarts with new chunk hashes, browsers serve stale cached HTML that 404s on old chunk names, showing a throbber instead of the login form. Set Cache-Control: no-cache on /if/* (HTML flow pages) so browsers always revalidate, and Cache-Control: immutable on /static/dist/* (hashed assets) for efficient caching. Adds a reusable `cache_policy: spa` option to caddy_services. Co-Authored-By: Claude Opus 4.6 (1M context) --- ansible/roles/caddy/defaults/main.yml | 1 + ansible/roles/caddy/templates/Caddyfile.j2 | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/ansible/roles/caddy/defaults/main.yml b/ansible/roles/caddy/defaults/main.yml index 784738f..f8f9156 100644 --- a/ansible/roles/caddy/defaults/main.yml +++ b/ansible/roles/caddy/defaults/main.yml @@ -82,6 +82,7 @@ caddy_services: - name: authentik host: "authentik.{{ caddy_domain }}" backend: "https://authentik.tail8d86e.ts.net" + cache_policy: spa - name: ntfy host: "ntfy.{{ caddy_domain }}" backend: "https://ntfy.tail8d86e.ts.net" diff --git a/ansible/roles/caddy/templates/Caddyfile.j2 b/ansible/roles/caddy/templates/Caddyfile.j2 index dc3c7ff..4f103f1 100644 --- a/ansible/roles/caddy/templates/Caddyfile.j2 +++ b/ansible/roles/caddy/templates/Caddyfile.j2 @@ -31,6 +31,14 @@ {% for service in caddy_services %} @{{ service.name }} host {{ service.host }} handle @{{ service.name }} { +{% if service.cache_policy | default('') == 'spa' %} + # SPA cache policy: hashed static assets are immutable, HTML must revalidate. + # Prevents stale HTML from referencing chunk hashes that no longer exist. + @{{ service.name }}_static path /static/dist/* + header @{{ service.name }}_static Cache-Control "public, max-age=31536000, immutable" + @{{ service.name }}_html path /if/* + header @{{ service.name }}_html Cache-Control "no-cache" +{% endif %} {% if service.backend.startswith('https://') %} reverse_proxy {{ service.backend }} { # Caddy v2.11+ rewrites Host to upstream for HTTPS backends.