Caddy Reverse Proxy with Automated TLS and Safe Headers
Caddy can obtain and renew HTTPS certificates automatically when the hostname resolves to the server and the required ports are reachable. This guide proxies a local service and adds a small set of response headers. Replace the example domain and upstream port with your values.
Step 1: Install Caddy on Debian / Ubuntu
Install Official Caddy APT Repository
InstallationInstall Caddy through its official signed Cloudsmith repository so the package can be updated through your system package manager:
# 1. Install prerequisites and import official Caddy GPG signing keysudo apt update && sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curlcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
# 2. Add Caddy repository source and install daemoncurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.listsudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpgsudo chmod o+r /etc/apt/sources.list.d/caddy-stable.listsudo apt update && sudo apt install -y caddy❯ View Expected Console Output
The Caddy package and systemd service are installed. Confirm the running state with systemctl status caddy after setup.
Step 2: Configure a Caddyfile with Conservative Security Headers
Define Modular Security Headers & Upstream Routing
ConfigurationEdit /etc/caddy/Caddyfile. The initial HSTS duration below is short while you verify the host and its subdomains work over HTTPS. Caddy preserves the incoming Host header and sets the standard forwarded headers by default, so the basic proxy does not need manual header_up overrides.
If a CDN or another trusted proxy sits in front of Caddy, configure the upstream proxy’s addresses in Caddy’s global trusted_proxies setting before relying on forwarded client IP details.
(security_headers) { header { X-Content-Type-Options nosniff X-Frame-Options SAMEORIGIN Referrer-Policy strict-origin-when-cross-origin Strict-Transport-Security "max-age=300" -Server }}
app.yourdomain.com { import security_headers encode zstd gzip reverse_proxy 127.0.0.1:8080}Step 3: Validate Caddyfile Syntax Before Reloading
Dry-Run Validate Configuration File
ValidationValidate that Caddy can parse and adapt the configuration before reloading. Validation catches syntax and adaptation errors, but it does not prove the upstream application is reachable or that DNS and firewall settings are correct.
# Validate Caddyfile formatting and syntaxsudo caddy validate --config /etc/caddy/Caddyfile❯ View Expected Console Output
Caddy reports that the configuration is valid. Exact output varies by installed release.
Step 4: Gracefully Reload Caddy and Verify the Site
Gracefully Reload and Verify the Site
DeploymentReload the service gracefully, then make a request through the public hostname and check the service logs. A successful reload does not verify certificate issuance, upstream health, or client access by itself.
# Apply the validated Caddyfile through the systemd service.sudo systemctl reload caddy❯ View Expected Console Output
Caddy reloads the service configuration. Confirm the HTTPS site and upstream application respond as expected.

Figure 1: Caddy validates its configuration, runs as a service, and obtains a TLS certificate for the configured hostname.