# ============================================================================= # Authelia + fail2ban -- Caddy snippets # # These are SNIPPETS TO ADD to your existing Caddyfile, not a replacement # for it. Copy the (authelia) and (accesslog) snippet definitions once at # the top of your Caddyfile, then copy whichever site blocks apply. # # DOMAIN is read from the environment -- set it wherever your Caddy reads # env vars (Caddy's own .env, systemd EnvironmentFile, or compose env:). # Only the upstream IPs need manual editing. # # Caddy v2.5.1+ required; tested on v2.11.2. # ============================================================================= # ----------------------------------------------------------------------------- # Paste these two snippet definitions once, near the top of your Caddyfile. # ----------------------------------------------------------------------------- # Gate any site block with Authelia by adding `import authelia` inside it. (authelia) { forward_auth authelia:9091 { uri /api/authz/forward-auth copy_headers Remote-User Remote-Groups Remote-Email Remote-Name } } # JSON access log that fail2ban's caddy-4xx jail reads. # Add `import accesslog` to EVERY site block (gated or not) so fail2ban # catches scanners hitting all your subdomains, not just the protected ones. (accesslog) { log { output file /var/log/caddy/access.log { roll_size 10MiB roll_keep 5 roll_keep_for 720h } format json } } # ============================================================================= # Authelia portal -- always required; never put `import authelia` here. # ============================================================================= auth.{env.DOMAIN} { import accesslog reverse_proxy authelia:9091 } # ============================================================================= # CASE 1 -- App has NO built-in auth. Authelia is the only gate. # # Examples: Homer, Heimdall, Dozzle, phpIPAM, any internal tool with no # login page. Use two_factor in authelia/configuration.yml for these. # ============================================================================= # Homer / Heimdall dashboard (no auth whatsoever) homer.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:8080 # CHANGE IP:PORT } # Dozzle (Docker log viewer -- no auth by default) dozzle.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:8888 # CHANGE IP:PORT } # Pi doorbell PTT page (Flask server, no auth) # Uncomment when the Pi is deployed. # doorbell.{env.DOMAIN} { # import accesslog # import authelia # # handle_path /frigate/* { # reverse_proxy 192.168.x.x:8971 # CHANGE: Frigate IP # } # handle { # reverse_proxy 192.168.x.x:5555 # CHANGE: Pi IP # } # } # ============================================================================= # CASE 2 -- App supports trusted-header proxy auth. Authelia replaces its # own login form. Single login, app reads Remote-User for roles. # # Requires per-app config changes -- see notes in each block. # ============================================================================= # --- Frigate 0.14+ --- # In frigate_config/config.yml: # auth: # enabled: False # trusted_proxies: [172.18.0.0/16] # caddy_net subnet # proxy: # header_map: {user: remote-user, role: remote-groups} # default_role: viewer # separator: '|' cam.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:8971 { # CHANGE IP transport http { read_timeout 60s; write_timeout 60s } # header_up X-Proxy-Secret "32-byte-hex" # if auth_secret: set in Frigate } } # --- Grafana --- # In grafana.ini (or GF_* env vars): # [auth.proxy] # enabled = true # header_name = Remote-User # header_property = username # auto_sign_up = true grafana.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:3000 # CHANGE IP } # --- Gitea / Forgejo --- # In app.ini: # [service] # ENABLE_REVERSE_PROXY_AUTHENTICATION = true # REVERSE_PROXY_TRUSTED_PROXIES = * git.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:3000 # CHANGE IP } # --- Nextcloud --- # In config/config.php: # 'trusted_proxies' => ['172.18.0.0/16'], # 'overwriteprotocol' => 'https', # Plus user_external app + HTTP header auth set to Remote-User. cloud.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:80 { # CHANGE IP header_up Host {upstream_hostport} } } # --- Paperless-ngx --- # In compose env: # PAPERLESS_ENABLE_HTTP_REMOTE_USER=true # PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME=HTTP_REMOTE_USER paperless.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:8000 # CHANGE IP } # --- Miniflux --- # In compose env: # AUTH_PROXY_HEADER=Remote-User # AUTH_PROXY_USER_CREATION=true miniflux.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:8080 # CHANGE IP } # --- BookStack --- # See BookStack docs for HTTP header auth (requires the SAML2 or HTTP auth method). # bookstack.{env.DOMAIN} { # import accesslog # import authelia # reverse_proxy 192.168.x.x:80 # CHANGE IP # } # --- Immich --- # Proxy auth headers not supported; use Authelia as OIDC provider instead. # Configure Authelia's identity_providers.oidc block and point Immich at it. # photos.{env.DOMAIN} { # import accesslog # import authelia # reverse_proxy 192.168.x.x:2283 # CHANGE IP # } # ============================================================================= # CASE 3 -- App keeps its own login. Authelia adds a 2FA gate in front. # # The user passes Authelia 2FA, then the app's own login appears. # Use for apps that don't support proxy auth headers but you still want # 2FA before they're even reachable. This is the only way to get TOTP # in front of apps that don't natively support it. # ============================================================================= # --- Uptime Kuma --- # No proxy auth, no native TOTP -- Authelia is the only way to add 2FA. uptime.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:3001 # CHANGE IP } # --- Portainer --- # No proxy auth header support (use OIDC for full SSO instead). portainer.{env.DOMAIN} { import accesslog import authelia reverse_proxy 192.168.x.x:9000 # CHANGE IP } # --- Mealie --- # Has OIDC support -- can do full case 2 with Authelia as OIDC provider. # For simpler case-3 gate: # mealie.{env.DOMAIN} { # import accesslog # import authelia # reverse_proxy 192.168.x.x:9000 # CHANGE IP # } # --- Home Assistant --- # Can also do case 2 via the trusted_networks auth provider + header forwarding. # homeassistant.{env.DOMAIN} { # import accesslog # import authelia # reverse_proxy 192.168.x.x:8123 # CHANGE IP # } # --- Vaultwarden --- # Has its own strong auth + native TOTP. Many skip Authelia here entirely # and rely on Vaultwarden's own 2FA (totally valid). Or use case 3 as an # extra gate if you want 2FA even before the login page loads. # vault.{env.DOMAIN} { # import accesslog # import authelia # reverse_proxy 192.168.x.x:80 # CHANGE IP # } # ============================================================================= # CASE 4 -- App handles its own auth. Authelia not involved. # Still import accesslog so fail2ban covers this site. # ============================================================================= # --- Syncthing --- # sync.{env.DOMAIN} { # import accesslog # reverse_proxy 192.168.x.x:8384 # CHANGE IP # } # --- Router / NAS admin UI --- # router.{env.DOMAIN} { # import accesslog # reverse_proxy 192.168.x.x:443 { # transport http { tls_insecure_skip_verify } # } # }