Caddy Web Server Installation and Configuration
Caddy is a modern, easy-to-use web server written in Go that automatically provisions and renews HTTPS certificates from Let's Encrypt. Unlike traditional web servers that require complex SSL configuration, Caddy handles certificate management transparently, making it ideal for sysadmins managing multiple domains. This guide covers installation, configuration through Caddyfiles, and advanced reverse proxy scenarios.
Table of Contents
- Introduction
- System Requirements
- Installation Methods
- Binary Installation
- Package Manager Installation
- Caddyfile Basics
- Reverse Proxy Configuration
- Static File Server
- PHP Support
- API Gateway Configuration
- Automatic HTTPS
- Troubleshooting and Monitoring
Introduction
Caddy is a powerful web server designed with security and ease of use as primary goals. Its most distinctive feature is automatic HTTPS—Caddy automatically obtains and renews SSL/TLS certificates from Let's Encrypt without any additional configuration. This guide helps you harness Caddy's capabilities for production environments.
System Requirements
Ensure your VPS or bare metal server meets these requirements:
- Linux kernel 3.10 or newer
- 256 MB RAM minimum (1 GB recommended)
- 50 MB disk space
- Port 80 and 443 accessible for HTTPS
- Internet connectivity for certificate validation
- Sudo or root access
Caddy supports multiple architectures: x86_64, ARM, ARM64, and MIPS.
Installation Methods
Caddy can be installed through several methods depending on your preference for updates and maintainability.
Binary Installation
Download the latest Caddy release:
cd /tmp
wget https://github.com/caddyserver/caddy/releases/download/v2.7.4/caddy_2.7.4_linux_amd64.tar.gz
tar xzf caddy_2.7.4_linux_amd64.tar.gz
Create the necessary system directories and user account:
sudo useradd -r -s /bin/false -d /var/lib/caddy -m caddy
sudo mkdir -p /etc/caddy
sudo mkdir -p /var/www
sudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/lib/caddy /var/log/caddy /etc/caddy
Install the binary and set permissions:
sudo mv /tmp/caddy /usr/local/bin/caddy
sudo chmod +x /usr/local/bin/caddy
sudo setcap cap_net_bind_service=+ep /usr/local/bin/caddy
The setcap command allows Caddy to bind to ports 80 and 443 without requiring root privileges.
Create a systemd service file:
sudo tee /etc/systemd/system/caddy.service > /dev/null <<EOF
[Unit]
Description=Caddy Web Server
Documentation=https://caddyserver.com/docs/
After=network-online.target
Wants=network-online.target
[Service]
User=caddy
Group=caddy
ExecStart=/usr/local/bin/caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile
Type=notify
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=caddy
[Install]
WantedBy=multi-user.target
EOF
Enable and start Caddy:
sudo systemctl daemon-reload
sudo systemctl enable caddy
sudo systemctl start caddy
Package Manager Installation
For Debian/Ubuntu systems, use the official repository:
sudo apt update
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl https://dl.filippo.io/caddy/key.gpg | sudo tee /etc/apt/trusted.gpg.d/caddy-filippo.asc > /dev/null
echo "deb [signed-by=/etc/apt/trusted.gpg.d/caddy-filippo.asc] https://dl.filippo.io/caddy/deb stable main" | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
For RHEL/CentOS systems:
sudo dnf copr enable @caddy/caddy
sudo dnf install caddy
sudo systemctl start caddy
sudo systemctl enable caddy
Caddyfile Basics
Create a Caddyfile at /etc/caddy/Caddyfile to define how Caddy serves your content:
example.com www.example.com {
root * /var/www/html
file_server
encode gzip
}
This basic configuration serves static files from /var/www/html with automatic HTTPS.
Handle multiple sites in a single Caddyfile:
example.com {
root * /var/www/example
file_server
encode gzip
}
api.example.com {
reverse_proxy localhost:8080
}
blog.example.com {
reverse_proxy localhost:3000
}
Reload the configuration without restarting:
sudo caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile
Reverse Proxy Configuration
Caddy excels at reverse proxying to backend applications:
app.example.com {
reverse_proxy localhost:8080 {
header_uri -Authorization
health_uri /health
health_interval 10s
health_timeout 5s
policy least_conn
}
}
Configure multiple backend servers with load balancing:
api.example.com {
reverse_proxy localhost:8001 localhost:8002 localhost:8003 {
health_uri /api/health
health_interval 5s
header_up Host {http.request.host}
header_up X-Forwarded-For {http.request.remote.host}
header_up X-Forwarded-Proto {http.request.scheme}
}
}
Handle path-based routing:
example.com {
handle /api/* {
reverse_proxy localhost:8080
}
handle /static/* {
root * /var/www/static
file_server
}
handle {
reverse_proxy localhost:3000
}
}
Static File Server
Configure Caddy as a high-performance static file server:
cdn.example.com {
root * /var/www/cdn
file_server {
precompressed br gzip
index index.html
}
encode gzip
header Cache-Control "public, max-age=31536000"
@immutable {
path /assets/*
}
header @immutable Cache-Control "public, immutable, max-age=31536000"
}
Caddy automatically precompresses files and serves optimized versions to clients supporting brotli or gzip.
PHP Support
Enable PHP support by integrating with PHP-FPM:
example.com {
root * /var/www/html
php_fastcgi localhost:9000 {
dial timeout 3s
read timeout 30s
write timeout 30s
}
file_server
encode gzip
}
Ensure PHP-FPM is running:
sudo systemctl status php8.2-fpm
sudo systemctl enable php8.2-fpm
Configure PHP-FPM listener (edit /etc/php/8.2/fpm/pool.d/www.conf):
[www]
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
Reload PHP-FPM:
sudo systemctl reload php8.2-fpm
API Gateway Configuration
Configure Caddy as an API gateway with multiple routes:
api.example.com {
encode gzip
@v1 {
path_regexp ^/v1/.*
}
handle @v1 {
reverse_proxy localhost:8001 {
uri /
}
}
@v2 {
path_regexp ^/v2/.*
}
handle @v2 {
reverse_proxy localhost:8002 {
uri /
}
}
handle {
respond "API not found" 404
}
}
Add authentication middleware:
api.example.com {
@protected {
not header Authorization Bearer*
}
respond @protected 401
reverse_proxy localhost:8080
}
Automatic HTTPS
Caddy automatically provisions HTTPS certificates:
example.com www.example.com {
root * /var/www/html
file_server
encode gzip
}
Specify custom certificate providers or storage:
{
storage file_system {
root /var/lib/caddy/certificates
}
acme_ca https://acme.letsencrypt.org/directory
acme_email [email protected]
}
example.com {
root * /var/www/html
file_server
}
Monitor certificate expiration:
sudo caddy list-certs
Renew certificates manually:
sudo caddy renew
Troubleshooting and Monitoring
Check Caddy service status:
sudo systemctl status caddy
sudo journalctl -u caddy -n 50 -f
Validate Caddyfile syntax:
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
Check certificate status:
sudo caddy list-certs
Monitor Caddy metrics with the admin API:
curl http://localhost:2019/config/
curl http://localhost:2019/metrics?namespace=caddy
Enable metrics in Caddyfile:
{
admin localhost:2019
metrics
}
example.com {
root * /var/www/html
file_server
}
Test HTTPS configuration:
curl -i https://example.com
openssl s_client -connect example.com:443 -servername example.com
Debug configuration issues:
sudo caddy run --config /etc/caddy/Caddyfile --adapter caddyfile --debug
Check port binding:
sudo netstat -tlnp | grep caddy
Verify DNS resolution:
nslookup example.com
dig example.com
Conclusion
Caddy provides a modern, user-friendly web server that eliminates SSL/TLS configuration complexity. Its automatic HTTPS, straightforward Caddyfile syntax, and built-in reverse proxy capabilities make it ideal for cloud VPS and bare metal deployments. Whether serving static files, proxying to backend services, or implementing API gateways, Caddy delivers reliable performance with minimal configuration overhead.


