############################################ # GLOBAL OPTIONS ############################################ { email YOUREMAIL@EMAIL.com auto_https disable_redirects # Trust ONLY Cloudflare's proxies, then read CF-Connecting-IP (NEEDED FOR JWT AUTH) servers { import /etc/caddy/snippets/trusted_proxies.caddy client_ip_headers CF-Connecting-IP } } ############################################ # Block-list generated every night by IPsum import /etc/caddy/snippets/deny_ips.caddy ############################################ ############################################ # SNIPPETS ############################################ (cf_headers) { header_up X-Real-IP {http.request.header.CF-Connecting-IP} header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} header_up CF-Connecting-IP {http.request.header.CF-Connecting-IP} } ############################################ # EXTRA MATCHER FOR CLOUDFLARE ############################################ import /etc/caddy/snippets/cf_only.caddy (auth_admin) { basic_auth { admin YOUR_HASHED_PASSWORD } basic_auth_totp { # JSON file with the secrets secrets_file_path /data/totp-secrets.json # 32-byte base-64 key for the JWT cookie sign_key YOUR_SIGN_KEY # Optional tweaks session_inactivity_timeout 2h # default 60m } } ############################################ # PUBLIC SITES #- CLOUDFLARE SSL FLEXIBLE ############################################ http://YOURWEBSITE.COM { reverse_proxy http://IP:PORT { import cf_headers } } ############################################ # PUBLIC SITES #- CLOUDFLARE SSL FLEXIBLE #- ONLY ACCESSIBLE FROM CLOUDFLARE IPS #- BLOCKS BAD IPS ############################################ http://YOURWEBSITE.COM { import block_ips import cf_only # defines @from_cf matcher # 1️⃣ traffic that *arrives from Cloudflare* → OK handle @from_cf { reverse_proxy http://IP:PORT { import cf_headers } } # 2️⃣ everything else → 403 handle { respond "Direct access forbidden (use DNS via Cloudflare)" 403 } } ############################################ # PUBLIC SITES (UBIQUITI UNIFI CONTROLLER EXAMPLE WITH CADDY AS A REVERSE PROXY) #- CLOUDFLARE SSL FLEXIBLE #- 2-FA-PROTECTED SITES #- GZIP COMPRESSION #- WEBSOCKET SUPPORT #- SKIP TLS INVALID CERTIFICATE (FROM UNIFI CONTAINER) ############################################ http://unifi.YOURWEBSITE.COM { encode gzip zstd import auth_admin reverse_proxy https://IP:8443 { import cf_headers header_up -Authorization header_up Upgrade {http.request.header.Upgrade} header_up Connection {http.request.header.Connection} transport http { tls_insecure_skip_verify } } } ############################################ # PUBLIC SITES # ANOTHER EXAMPLE OF WEBSOCKET SUPPORT, UI AND WEBSOCKET RUNNING ON DIFFERENT PORTS ############################################ http://YOURWEBSITE.COM { import auth_admin @websocket { header Connection *Upgrade* header Upgrade websocket } handle @websocket { reverse_proxy http://IP:8080 { import cf_headers header_up Host {host} header_up Upgrade {http.request.header.Upgrade} header_up Connection {http.request.header.Connection} header_up X-Forwarded-Proto {scheme} } } handle { reverse_proxy http://IP:8090 { import cf_headers header_up -Authorization header_up Host {host} header_up X-Forwarded-Proto {scheme} header_down Set-Cookie (.*) "$1; Path=/; Secure; SameSite=Lax" } } } ############################################ # PUBLIC SITES - (UBIQUITI UNIFI CONTROLLER EXAMPLE WITH CADDY AS A REVERSE PROXY) #- SSL HANDLED BY CADDY (CAN USE CLOUDFLARE STRICT MODE) #- GZIP COMPRESSION #- WEBSOCKET SUPPORT #- SKIP TLS INVALID CERTIFICATE ############################################ https://unifi.YOURWEBSITE.COM { encode gzip zstd import auth_admin tls { issuer acme { disable_http_challenge } } reverse_proxy https://IP:8443 { import cf_headers header_up -Authorization header_up Upgrade {http.request.header.Upgrade} header_up Connection {http.request.header.Connection} transport http { tls_insecure_skip_verify } } } ############################################ # CATCH-ALL ############################################ :80, :443 { respond "Connection Refused" 403 }