Skip to content

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

01

Install Official Caddy APT Repository

Installation

Install Caddy through its official signed Cloudsmith repository so the package can be updated through your system package manager:

Terminal window
# 1. Install prerequisites and import official Caddy GPG signing key
sudo apt update && sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -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 daemon
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo 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

02

Define Modular Security Headers & Upstream Routing

Configuration

Edit /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

03

Dry-Run Validate Configuration File

Validation

Validate 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.

Terminal window
# Validate Caddyfile formatting and syntax
sudo 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

04

Gracefully Reload and Verify the Site

Deployment

Reload 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.

Terminal window
# 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.

Caddy terminal validation, active service status, and automatic TLS certificate logs

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

Comments