feat: drive domain from DOMAIN env var -- no manual find-and-replace

Previously every example.com had to be found and replaced manually.
Now a single DOMAIN=yourdomain.com in .env propagates everywhere:

- .env.example: add DOMAIN=example.com with explanation
- docker-compose.yml: pass DOMAIN into authelia container environment
- authelia/configuration.yml: use {{ env "DOMAIN" }} in totp.issuer,
  access_control.rules, and all four session.cookies[] fields
  (Authelia 4.38+ Go template substitution)
- caddy/Caddyfile: use {env.DOMAIN} in all site block addresses
  (Caddy native env substitution); update header comment explaining
  how to set DOMAIN for system vs dockerized Caddy
- README.md: update step 3 to explain DOMAIN is the only change needed;
  update step 4 to say just uncomment the right rule; update Caddy
  wiring section with DOMAIN env var instructions for both Caddy modes

https://claude.ai/code/session_012eTokAaGiZo7aGt1T2W9BC
This commit is contained in:
Claude
2026-04-26 14:39:56 +00:00
parent 711f892ada
commit cd78a3560d
5 changed files with 97 additions and 65 deletions
+46 -39
View File
@@ -2,7 +2,7 @@
# 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:
# your existing Caddyfile), then reload:
#
# # System Caddy:
# sudo caddy validate --config /etc/caddy/Caddyfile
@@ -11,9 +11,16 @@
# # 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
# Domain is read from the DOMAIN environment variable -- no hardcoded
# domains in this file. Set it in your Caddy environment before reloading:
#
# # System Caddy (add to /etc/caddy/caddy.env or your systemd override):
# export DOMAIN=yourdomain.com
#
# # Dockerized Caddy (add to its .env or compose environment:):
# DOMAIN=yourdomain.com
#
# Only the upstream IPs need editing: replace 192.168.x.x with real LAN IPs.
#
# Requirements:
# - Caddy v2.5.1+ (for `forward_auth` directive; tested on v2.11.2)
@@ -90,38 +97,11 @@
# access_control.rules handles the portal itself. Adding forward_auth here
# would cause a redirect loop.
# =============================================================================
auth.example.com { # CHANGE
auth.{env.DOMAIN} {
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.
#
@@ -147,11 +127,11 @@ auth.example.com { # CHANGE
# # 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)
# Then uncomment the cam 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
cam.{env.DOMAIN} {
import accesslog
import authelia
@@ -165,6 +145,33 @@ cam.example.com { # CHANGE
}
}
# =============================================================================
# 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 uncomment the doorbell rule in authelia/configuration.yml.
# =============================================================================
# doorbell.{env.DOMAIN} {
# 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 { # CHANGE IP
# transport http {
# read_timeout 60s
# write_timeout 60s
# }
# }
# }
#
# handle {
# reverse_proxy 192.168.x.x:5555 # CHANGE IP
# }
# }
# =============================================================================
# CASE 3: App keeps its own login; Authelia adds a 2FA gate in front.
#
@@ -173,10 +180,10 @@ cam.example.com { # CHANGE
# form appears. Two separate logins -- the app's auth is untouched.
#
# Also add a rule in authelia/configuration.yml:
# - domain: 'nas.example.com'
# - domain: 'nas.{{ env "DOMAIN" }}'
# policy: 'two_factor'
# =============================================================================
# nas.example.com { # CHANGE/REMOVE example
# nas.{env.DOMAIN} { # CHANGE/REMOVE example
# import accesslog
# import authelia
#
@@ -193,7 +200,7 @@ cam.example.com { # CHANGE
# 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
# router.{env.DOMAIN} { # CHANGE/REMOVE example
# import accesslog
# reverse_proxy 192.168.x.x:PORT { # CHANGE
# transport http {