Update authelia stack: 4 auth cases, full Caddyfile, improved docs
Keeps this as a standalone authelia+fail2ban stack (no Frigate services). Changes: - docker-compose.yml: fail2ban depends_on authelia with service_healthy condition so authelia.log exists before fail2ban tries to bind-mount it; add inline note about pre-creating the log file - authelia/configuration.yml: expand access_control comment block to cover all 4 cases (added Case 3: app keeps own auth + Authelia as 2FA gate, and Case 4: app handles auth alone); clearer per-case commented rules - caddy/Caddyfile (replaces snippet.example.caddyfile): complete Caddyfile with all 4 auth-case examples; (accesslog) imported in every block so fail2ban caddy-4xx jail covers all subdomains, not just gated ones; full inline docs for enabling Frigate proxy auth - README.md: expand "Which sites" from 3 to 4 cases; add proxy-auth service compatibility table (Frigate, Grafana, Gitea, Nextcloud, HA, Portainer etc.); clarify fail2ban covers all sites via single caddy-4xx jail; add touch authelia/authelia.log to first-run; add troubleshooting entries for authelia.log bind-mount directory bug and fail2ban chain verification https://claude.ai/code/session_012eTokAaGiZo7aGt1T2W9BC
This commit is contained in:
+203
@@ -0,0 +1,203 @@
|
||||
# =============================================================================
|
||||
# Caddyfile -- Authelia + fail2ban integration
|
||||
#
|
||||
# Copy this file into your Caddy setup (or merge the relevant blocks into
|
||||
# your existing Caddyfile), edit all placeholders, then reload:
|
||||
#
|
||||
# # System Caddy:
|
||||
# sudo caddy validate --config /etc/caddy/Caddyfile
|
||||
# sudo systemctl reload caddy
|
||||
#
|
||||
# # Dockerized Caddy:
|
||||
# docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
|
||||
#
|
||||
# Placeholders to replace:
|
||||
# example.com -> your real root domain
|
||||
# 192.168.x.x -> real upstream LAN IPs
|
||||
#
|
||||
# Requirements:
|
||||
# - Caddy v2.5.1+ (for `forward_auth` directive)
|
||||
# - Caddy must be on the `caddy_net` Docker network so it can resolve
|
||||
# `authelia` by container name. In your Caddy compose:
|
||||
# networks: [caddy_net]
|
||||
# and at the bottom:
|
||||
# networks:
|
||||
# caddy_net:
|
||||
# external: true
|
||||
#
|
||||
# =============================================================================
|
||||
# DECISION TREE -- which sites go behind Authelia?
|
||||
#
|
||||
# CASE 1 -- App has NO built-in auth (e.g. Pi doorbell PTT page).
|
||||
# `import authelia` + rule in authelia/configuration.yml.
|
||||
# Authelia is the ONLY login. Use two_factor for hardware-control pages.
|
||||
#
|
||||
# CASE 2 -- App has built-in auth AND supports trusted-header proxy auth
|
||||
# (Frigate 0.14+, Grafana, Gitea, Nextcloud, Home Assistant, ...).
|
||||
# `import authelia` + rule in Authelia + disable the app's own login form.
|
||||
# Single Authelia login: Authelia authenticates, app reads Remote-User header.
|
||||
#
|
||||
# CASE 3 -- App has built-in auth and CANNOT switch to proxy auth, but you
|
||||
# want a 2FA gate in front anyway (router admin, legacy apps, etc.).
|
||||
# `import authelia` + rule in Authelia. App auth is untouched.
|
||||
# User logs into Authelia (2FA), then the app's own login form appears.
|
||||
#
|
||||
# CASE 4 -- App handles its own auth; Authelia not involved.
|
||||
# Plain `reverse_proxy`, no `import authelia`, no Authelia rule.
|
||||
# Traffic skips Authelia entirely.
|
||||
#
|
||||
# fail2ban coverage: import (accesslog) in EVERY site block -- gated or not.
|
||||
# The caddy-4xx jail watches /var/log/caddy/access.log and bans scanners
|
||||
# spraying all your subdomains, not just the Authelia-gated ones.
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# (authelia) -- forward_auth gate.
|
||||
# Import into any site block you want gated (cases 1, 2, 3).
|
||||
# On success Authelia sets Remote-User, Remote-Groups, Remote-Email,
|
||||
# Remote-Name headers that the upstream app can consume for role mapping.
|
||||
# -----------------------------------------------------------------------------
|
||||
(authelia) {
|
||||
forward_auth authelia:9091 {
|
||||
uri /api/authz/forward-auth
|
||||
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# (accesslog) -- structured JSON access log consumed by fail2ban's caddy-4xx
|
||||
# jail. Import into EVERY site block so fail2ban covers your whole stack.
|
||||
#
|
||||
# Pre-create the log directory before starting Caddy:
|
||||
# sudo mkdir -p /var/log/caddy
|
||||
# sudo chown caddy:caddy /var/log/caddy # system Caddy
|
||||
# # Dockerized Caddy: add volumes: ["/var/log/caddy:/var/log/caddy"] to compose
|
||||
# -----------------------------------------------------------------------------
|
||||
(accesslog) {
|
||||
log {
|
||||
output file /var/log/caddy/access.log {
|
||||
roll_size 10MiB
|
||||
roll_keep 5
|
||||
roll_keep_for 720h
|
||||
}
|
||||
format json
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Authelia login portal
|
||||
# Never add `import authelia` here -- the `bypass` rule in
|
||||
# access_control.rules handles the portal itself. Adding forward_auth here
|
||||
# would cause a redirect loop.
|
||||
# =============================================================================
|
||||
auth.example.com { # CHANGE
|
||||
import accesslog
|
||||
reverse_proxy authelia:9091
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# CASE 1: Pi doorbell PTT page -- Authelia is the ONLY auth.
|
||||
#
|
||||
# The Pi's Flask server has no built-in authentication. Authelia gates it.
|
||||
# two_factor is appropriate -- this URL controls a speaker in your house.
|
||||
# Comment out until the Pi is deployed.
|
||||
# Also add (or uncomment) the doorbell.example.com rule in configuration.yml.
|
||||
# =============================================================================
|
||||
# doorbell.example.com { # CHANGE
|
||||
# import accesslog
|
||||
# import authelia
|
||||
#
|
||||
# # Same-origin proxy to Frigate so WebRTC fetch works without CORS.
|
||||
# handle_path /frigate/* {
|
||||
# reverse_proxy 192.168.x.x:8971 {
|
||||
# transport http {
|
||||
# read_timeout 60s
|
||||
# write_timeout 60s
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# handle {
|
||||
# reverse_proxy 192.168.x.x:5555
|
||||
# }
|
||||
# }
|
||||
|
||||
# =============================================================================
|
||||
# CASE 2: Frigate UI -- Authelia replaces Frigate's own login form.
|
||||
#
|
||||
# Frigate 0.14+ supports trusted-header proxy auth. Authelia authenticates
|
||||
# the user (optionally with TOTP 2FA), then passes Remote-User and
|
||||
# Remote-Groups headers to Frigate which maps them to admin/viewer roles.
|
||||
#
|
||||
# To enable proxy auth in Frigate, edit frigate_config/config.yml:
|
||||
#
|
||||
# auth:
|
||||
# enabled: False
|
||||
# trusted_proxies:
|
||||
# - 172.18.0.0/16 # caddy_net subnet; find it with:
|
||||
# # docker network inspect caddy_net
|
||||
# proxy:
|
||||
# header_map:
|
||||
# user: remote-user # matches copy_headers in (authelia) snippet
|
||||
# role: remote-groups
|
||||
# default_role: viewer
|
||||
# separator: '|'
|
||||
# # Optional shared secret -- prevents LAN header spoofing.
|
||||
# # Generate: openssl rand -hex 32
|
||||
# # Set the same value as header_up X-Proxy-Secret below.
|
||||
# # auth_secret: 'your-32-byte-hex'
|
||||
#
|
||||
# Then uncomment the cam.example.com rule in authelia/configuration.yml
|
||||
# and restart: docker compose restart authelia (in the authelia stack)
|
||||
# docker compose restart frigate (in the camera stack)
|
||||
# =============================================================================
|
||||
cam.example.com { # CHANGE
|
||||
import accesslog
|
||||
import authelia
|
||||
|
||||
reverse_proxy 192.168.x.x:8971 { # CHANGE IP
|
||||
transport http {
|
||||
read_timeout 60s
|
||||
write_timeout 60s
|
||||
}
|
||||
# Uncomment if you set auth_secret: in Frigate's proxy: block.
|
||||
# header_up X-Proxy-Secret "your-32-byte-hex-here"
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# CASE 3: App keeps its own login; Authelia adds a 2FA gate in front.
|
||||
#
|
||||
# Use when an app can't do proxy auth but you still want 2FA before it.
|
||||
# The user authenticates with Authelia (2FA), then the app's own login
|
||||
# form appears. Two separate logins -- the app's auth is untouched.
|
||||
#
|
||||
# Also add a rule in authelia/configuration.yml:
|
||||
# - domain: 'nas.example.com'
|
||||
# policy: 'two_factor'
|
||||
# =============================================================================
|
||||
# nas.example.com { # CHANGE/REMOVE example
|
||||
# import accesslog
|
||||
# import authelia
|
||||
#
|
||||
# reverse_proxy 192.168.x.x:PORT { # CHANGE
|
||||
# transport http {
|
||||
# tls_insecure_skip_verify # only if self-signed TLS
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
|
||||
# =============================================================================
|
||||
# CASE 4: App handles its own auth; Authelia not involved.
|
||||
#
|
||||
# No `import authelia`. No access_control rule in Authelia.
|
||||
# Still import accesslog so fail2ban's caddy-4xx jail covers this site.
|
||||
# =============================================================================
|
||||
# router.example.com { # CHANGE/REMOVE example
|
||||
# import accesslog
|
||||
# reverse_proxy 192.168.x.x:PORT { # CHANGE
|
||||
# transport http {
|
||||
# tls_insecure_skip_verify
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
@@ -1,144 +0,0 @@
|
||||
# =============================================================================
|
||||
# Authelia + Caddy integration snippets
|
||||
#
|
||||
# Merge these blocks into your real Caddyfile (typically the one your
|
||||
# dockerized Caddy mounts from its own ~/docker/caddy/ folder). Reload Caddy
|
||||
# after editing:
|
||||
# docker compose -f ~/docker/caddy/docker-compose.yml exec caddy \
|
||||
# caddy reload --config /etc/caddy/Caddyfile
|
||||
#
|
||||
# Requires:
|
||||
# - Caddy v2.5.1 or newer
|
||||
# - Caddy joined to the external `caddy_net` docker network so it can
|
||||
# resolve `authelia` by container name
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
# DECISION TREE: which sites go behind Authelia?
|
||||
#
|
||||
# 1. App has NO built-in auth (e.g. the Pi doorbell PTT page).
|
||||
# -> `import authelia` here AND add a rule in
|
||||
# authelia/configuration.yml access_control.rules. Use
|
||||
# two_factor for anything that controls hardware.
|
||||
#
|
||||
# 2. App has built-in auth AND supports trusted-header proxy auth
|
||||
# (Frigate 0.14+, Grafana, Gitea, Jellyfin, Portainer, ...).
|
||||
# -> `import authelia` here, add a rule in Authelia, AND switch
|
||||
# the app's own config to consume Remote-User from upstream
|
||||
# (disable its built-in login form). One login, 2FA, app
|
||||
# still owns its user/role mapping. See the cam.* example
|
||||
# and the README for Frigate specifics.
|
||||
#
|
||||
# 3. App has built-in auth and CAN'T switch (router admin pages,
|
||||
# odd legacy things).
|
||||
# -> Plain `reverse_proxy` block. NO `import authelia`, NO
|
||||
# Authelia rule. The traffic skips Authelia entirely.
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Reusable forward_auth snippet for cases (1) and (2). Import into any site
|
||||
# block you want gated by Authelia.
|
||||
# -----------------------------------------------------------------------------
|
||||
(authelia) {
|
||||
forward_auth authelia:9091 {
|
||||
uri /api/authz/forward-auth
|
||||
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Caddy access logging -- fail2ban needs JSON access logs at a host path
|
||||
# both Caddy and fail2ban can see. Mount /var/log/caddy in BOTH compose
|
||||
# files (Caddy as rw, fail2ban as ro). The roll directives keep it bounded.
|
||||
# -----------------------------------------------------------------------------
|
||||
(accesslog) {
|
||||
log {
|
||||
output file /var/log/caddy/access.log {
|
||||
roll_size 10MiB
|
||||
roll_keep 5
|
||||
roll_keep_for 720h
|
||||
}
|
||||
format json
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Site blocks
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Authelia login portal -- always bypass in access_control.rules.
|
||||
# -----------------------------------------------------------------------------
|
||||
auth.example.com {
|
||||
import accesslog
|
||||
reverse_proxy authelia:9091
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CASE 1: app has NO built-in auth.
|
||||
# Pi doorbell PTT page -- Authelia is the only gate. two_factor in Authelia.
|
||||
# -----------------------------------------------------------------------------
|
||||
doorbell.example.com {
|
||||
import accesslog
|
||||
import authelia
|
||||
|
||||
handle_path /frigate/* {
|
||||
reverse_proxy 192.168.x.x:8971 {
|
||||
transport http {
|
||||
read_timeout 60s
|
||||
write_timeout 60s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle {
|
||||
reverse_proxy 192.168.x.x:5555
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CASE 2: app supports trusted-header proxy auth.
|
||||
# Frigate UI -- Authelia gates access AND Frigate consumes Remote-User from
|
||||
# upstream so its own role mapping (admin/viewer) still works. To use this,
|
||||
# also edit frigate_config/config.yml:
|
||||
#
|
||||
# auth:
|
||||
# enabled: False
|
||||
# trusted_proxies:
|
||||
# - 172.18.0.0/16 # your caddy_net subnet, see README
|
||||
# proxy:
|
||||
# header_map:
|
||||
# user: remote-user
|
||||
# role: remote-groups
|
||||
# default_role: viewer
|
||||
# separator: '|'
|
||||
# # Optional but recommended when Caddy and Frigate are on different
|
||||
# # hosts/VLANs. Generate with `openssl rand -hex 32` and add the
|
||||
# # matching `header_up X-Proxy-Secret <value>` below.
|
||||
# # auth_secret: 'paste-32-byte-hex-here'
|
||||
# -----------------------------------------------------------------------------
|
||||
cam.example.com {
|
||||
import accesslog
|
||||
import authelia
|
||||
reverse_proxy 192.168.x.x:8971 {
|
||||
transport http {
|
||||
read_timeout 60s
|
||||
write_timeout 60s
|
||||
}
|
||||
# Uncomment and match Frigate's auth_secret if you set one above.
|
||||
# header_up X-Proxy-Secret "paste-same-32-byte-hex-here"
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CASE 3: app keeps its own auth (no Authelia involvement).
|
||||
# Example: a router admin page or a service that can't do proxy auth.
|
||||
# Do NOT add `import authelia` and do NOT add an access_control rule for it.
|
||||
# -----------------------------------------------------------------------------
|
||||
# router.example.com {
|
||||
# import accesslog
|
||||
# reverse_proxy 192.168.1.1:443 {
|
||||
# transport http {
|
||||
# tls_insecure_skip_verify
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
Reference in New Issue
Block a user