Caddy as web server and reverse proxy: installation, configuration and use
Caddy as a web server and reverse proxy: installation, configuration, and use
This article explains what Caddy is, how to install and configure it for static files and reverse proxy, including integration with Authelia. It is intended for developers and system administrators who want to set up a modern web server with automatic HTTPS.
Requirements
- A Linux server (Debian, Ubuntu, Fedora, or CentOS) with root access or sudo privileges - A domain name pointing to the server's IP address (for HTTPS via Let's Encrypt) - Basic knowledge of the command line - Caddy version 2.7 or newer (version 2.8 includes improved HTTP/3 support)
What is Caddy?
Caddy is an open-source web server written in Go. It stands out with automatic HTTPS: Caddy requests and renews TLS certificates itself via Let's Encrypt, without manual configuration. This works out-of-the-box for both simple file servers and complex reverse proxy setups.
Caddy supports HTTP/2 and HTTP/3. HTTP/3 runs on the QUIC protocol and performs better on unstable network connections. These protocols are enabled by default and require no additional configuration.
Steps
1. Install Caddy via the system package manager
Caddy offers official packages for the major Linux distributions. For Debian/Ubuntu:
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
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddyFor Fedora/RHEL:
sudo dnf install 'dnf-command(copr)'
sudo dnf copr enable @caddy/caddy
sudo dnf install caddy2. Start Caddy as a system service
Caddy runs as a service and starts automatically when the system boots:
sudo systemctl enable --now caddy
Check that the service is running:
sudo systemctl status caddy
3. Configure a simple file server with the Caddyfile
The Caddyfile is Caddy's configuration file. It uses a readable syntax for routes, proxy settings, and certificates. Create a basic configuration for a static file server:
sudo nano /etc/caddy/Caddyfile
Replace the contents with:
example.com {
root * /var/www/html
file_server browse
}Replace `example.com` with your own domain name. The `file_server browse` directive creates a browsable interface that shows the contents of the directory. This is useful for temporary file sharing or development environments.
4. Configure Caddy as a reverse proxy
Caddy can forward traffic to other services based on URL paths or hostnames. This is useful when multiple applications run on one server. Add a reverse proxy rule to the Caddyfile:
app.example.com {
reverse_proxy localhost:8080
}This forwards all traffic for `app.example.com` to the service on port 8080. For path-based routing:
example.com {
handle /api/* {
reverse_proxy localhost:3000
}
handle {
root * /var/www/html
file_server
}
}5. Build Caddy with plugins via xcaddy
For extensions such as specific DNS providers for certificate renewal, use xcaddy. This tool compiles Caddy from source with a chosen set of modules:
sudo apt install golang-go
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latestBuild Caddy with a DNS plugin, for example for Cloudflare:
xcaddy build --with github.com/caddy-dns/cloudflare
This produces a binary file `caddy` in the current directory. You can also choose a specific Caddy version:
xcaddy build v2.7.6 --with github.com/caddy-dns/cloudflare
6. Integrate Authelia for authentication
Authelia is an open-source authentication server that provides two-factor authentication and single sign-on (SSO). Place Authelia behind Caddy to secure web applications. Add to the Caddyfile:
secure.example.com {
forward_auth localhost:9091 {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}
reverse_proxy localhost:8080
}Caddy first sends traffic to Authelia on port 9091. Only authenticated users get access to the application on port 8080.
7. Restart Caddy after configuration changes
After every change to the Caddyfile, you must restart Caddy:
sudo systemctl reload caddy
Caddy validates the configuration and applies it without interrupting the service.
Verification
Check that Caddy runs correctly and HTTPS is active:
curl -I https://example.com
The output should show `HTTP/2 200` or `HTTP/3 200`. For a reverse proxy check:
curl -I https://app.example.com
Check the logs for certificate and proxy issues:
sudo journalctl -u caddy --since "5 minutes ago"
Common problems
1. Caddy cannot request a certificate from Let's Encrypt. Check that your domain name points to the correct IP address and that ports 80 and 443 are open in the firewall. Run `sudo ufw allow 80,443/tcp` if you are using UFW.
2. HTTP/3 does not work. HTTP/3 requires port 443 UDP to be open. Check this with `sudo ufw allow 443/udp`. Some networks block QUIC traffic; test with a different connection then.
3. The reverse proxy returns a 502 Bad Gateway. The backend service is not running or is listening on a different address or port. Check with `sudo ss -tlnp | grep 8080` whether the service is actually running on port 8080.
Caddy combines simple configuration with advanced functionality such as automatic certificate renewal and HTTP/3. The choice between the Caddyfile and JSON configuration determines how far you want to go in control — and that trade-off continues to differ per implementation.