Reverse Proxy
Caddy
Dockerhub - caddy
Modules
The Dockerfile uses xcaddy to build Caddy with the necessary modules.
- caddy-dns/cloudflare
- This module uses a Cloudflare token to neogiate the ACME challenge with Let's Encrypt.
- mholt/caddy-dynamicdns
- This module uses a Cloudflare token to update the the DNS entry for the root domain. This is only necessary if Cloudflare is forwarding traffic directly to your network because your public IP might change every once in a while. Using a Cloudflare tunnel obviates the need for this because the connection is established to Cloudflare by the tunnel.
Dockerfile with modules
Config
- ACME DNS-01 Challenge
-
Uses the
acme-dnsandacme-caglobal optionsGlobal options block{ email {env.EMAIL} acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN} acme_ca https://acme-v02.api.letsencrypt.org/directory # acme_ca https://acme-staging-v02.api.letsencrypt.org/directory log { output stdout format json level DEBUG } }Use the staging endpoint for development to avoid the rate limit
- Security Headers
-
These additional headers increase security. Check if they're working with this security check.
Option block(security_headers) { header { # Enable HSTS with 1 year max-age and include subdomains Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" # Prevent MIME type sniffing X-Content-Type-Options "nosniff" # Prevent clickjacking attacks X-Frame-Options "SAMEORIGIN" # Disable server tokens -Server # Control which features and APIs can be used Permissions-Policy "geolocation=(), microphone=(), camera=()" # Relaxed CSP - allows inline scripts/styles and websockets for Proxmox compatibility Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline' data: https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' wss:; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests" } }If this endpoint is getting proxied by cloudflare, then these need to be applied with Response Header Transform Rules in the web dashboard.
- Insecure Reverse Proxy
-
Some endpoints, such as Proxmox's web UI, use their own, self-signed certs for HTTPS. This function disables the TLS verify check for a proxied connection, which is essentially equivalent to proceeding through the browser warning. However, this allows you to specify what server name you expect on the cert provided.
These endpoints should never be exposed to the internet
- Slow Cloudflare DNS
-
Cloudflare sometimes(?) takes forever to propagate the TXT records for the DNS-01 challenge, so it times out. This block can be used to slow down the checks Caddy does, which allows it to succeed sometimes if it's having trouble. Unfortunately, these settings don't seem to be exposed as global options, so this block has to be imported wherever it's needed.
Option block(slow_cloudflare_tls) { tls { dns cloudflare {env.CLOUDFLARE_API_TOKEN} propagation_timeout 1h propagation_delay 30m } }Example usageappdaemon.john-stream.com { import slow_cloudflare_tls reverse_proxy 192.168.1.242:5050 }The global
acme_dnsoption has to be commented out for this to work. - Tunnel Route
-
This blocks modularizes only allowing traffic to come from the
cloudflaredcontainer. - Split Horizon
-
The split horizon DNS is established by this block
Option block# Combined HTTPS and HTTP (tunnel) routes for a service. This is only used for services that are exposed both internally and externally. (split_horizon) { {args[0]}.john-stream.com, {args[0]}.john-stream.com:80 { @http protocol http handle @http { # Only traffic from the cloudflared tunnel can use HTTP import tunnel_route {args[1]} } @https protocol https handle @https { # Everything else must come from a local network and use HTTPS import local_route {args[1]} } } }
Reference
Deploying Web Applications Quicker and Easier with Caddy 2
How to use DNS provider modules in Caddy 2
NGINX
Nginx (pronounced "engine x", stylized as NGINX or nginx) is a web server that can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache.
Reverse Proxy
DockerHub - nginx
Default config location: /etc/nginx/nginx.conf
Serving Static Content
This feature is used to host the built document site for the final stage of its Dockerfile.
CoreDNS
This Corefile sets up the following behavior:
- Local
john-stream.comzone- Defined by the zone file
- Uses fallthrough to forward failed requests to Cloudflare
- Reverse DNS for certain IPs
- DNS-over-TLS (DoT) communication with Cloudflare
Example Corefile
# CoreDNS Configuration for Split Horizon DNS
# john-stream.com - Internal resolution with external fallback
# Internal zone for john-stream.com
john-stream.com {
# Load internal zone file for local resolution
file /etc/coredns/john-stream.com.zone john-stream.com {
fallthrough
}
# Forward to Cloudflare if record not found in zone file
forward . tls://1.1.1.1 tls://1.0.0.1 {
tls_servername cloudflare-dns.com
}
log
errors
}
# Handle reverse DNS for internal IPs if needed
# Adjust this range based on your internal network
168.192.in-addr.arpa {
file /etc/coredns/db.192.168
log
errors
}
# Default: All other queries go to Cloudflare DNS
. {
forward . tls://1.1.1.1 tls://1.0.0.1 {
tls_servername cloudflare-dns.com
}
log
errors
cache 30
}
Example zone file
$ORIGIN john-stream.com.
$TTL 3600
; CoreDNS Local Resolution Only - NOT an authoritative nameserver
; External queries should go to Cloudflare nameservers
; This file only provides internal IP overrides for split-horizon DNS
; SOA Record (required by CoreDNS, but not used as authoritative)
@ IN SOA localhost. admin.localhost. (
2025110402 ; Serial (YYYYMMDDNN)
7200 ; Refresh
3600 ; Retry
1209600 ; Expire
3600 ; Minimum TTL
)
; Main server/host
@ IN A 192.168.1.150
hermes 3600 IN A 192.168.1.150
panoptes 3600 IN A 192.168.1.107
asdf 3600 IN CNAME tunnel
appdaemon 3600 IN CNAME hermes
cron 3600 IN CNAME hermes
docs 3600 IN CNAME hermes
gitea 3600 IN CNAME hermes
grafana 3600 IN A 192.168.1.177
Reverse DNS Lookup
Example reverse lookup file
$TTL 86400
@ IN SOA john-stream.com. admin.john-stream.com. (
2025112301 ; Serial (YYYYMMDDnn)
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Minimum
IN NS john-stream.com.
; PTR Records for 192.168.0.0/16
; Format: <last_octet> IN PTR <hostname>.
; Example:
; 1.1 IN PTR host1.john-stream.com.
; 10.1 IN PTR host2.john-stream.com.
100.1 IN PTR nas.john-stream.com.
150.1 IN PTR hermes.john-stream.com.
177.1 IN PTR grafana.john-stream.com.
The period at the end of the entries is actually important.