Caddy is a modern, open-source web server written in Go that stands out for one defining feature: automatic HTTPS. Caddy obtains and renews TLS certificates from Let’s Encrypt or ZeroSSL automatically, with zero configuration required beyond specifying a domain name. It also supports HTTP/2 and HTTP/3 (QUIC) out of the box, and its declarative Caddyfile configuration format is dramatically simpler than Nginx or Apache for common use cases. On RHEL 9, Caddy is installed from its official repository and integrates with systemd. This guide covers installing Caddy on RHEL 9, configuring static file serving and reverse proxying with automatic HTTPS, and using the JSON API for programmatic configuration.
Prerequisites
- RHEL 9 server with root or sudo access
- Domain name with DNS pointing to your server (for automatic HTTPS)
- Ports 80 and 443 open in firewalld
Step 1 — Install Caddy
# Add the official Caddy repository
dnf install -y 'dnf-command(copr)'
dnf copr enable -y @caddy/caddy
# Install Caddy
dnf install -y caddy
# Verify
caddy version
Alternatively, install from the official RPM:
# Add Caddy repo manually
cat > /etc/yum.repos.d/caddy.repo << 'EOF'
[caddy]
name=Caddy
baseurl=https://dl.cloudsmith.io/public/caddy/stable/rpm/el/$releasever/$basearch/
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://dl.cloudsmith.io/public/caddy/stable/gpg.key
EOF
dnf install -y caddy
Step 2 — Open Firewall Ports
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
Step 3 — Configure Static File Serving
vi /etc/caddy/Caddyfile
example.com {
root * /var/www/example.com/html
file_server
encode gzip zstd
log {
output file /var/log/caddy/example.com.log
}
}
That is the entire configuration needed for a static site with automatic HTTPS, gzip compression, and access logging. Caddy automatically obtains a Let’s Encrypt certificate for example.com when the server starts.
Step 4 — Configure a Reverse Proxy
app.example.com {
reverse_proxy localhost:3000
}
api.example.com {
reverse_proxy localhost:4000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
Step 5 — Multiple Sites in One Caddyfile
site1.com {
root * /var/www/site1.com
file_server
}
site2.com {
reverse_proxy localhost:3000
}
site3.com {
php_fastcgi unix//run/php-fpm/www.sock
root * /var/www/site3.com
file_server
encode gzip
}
Step 6 — Enable and Start Caddy
# Set SELinux context for web root
semanage fcontext -a -t httpd_sys_content_t '/var/www(/.*)?'
restorecon -Rv /var/www/
# Allow Caddy to bind to privileged ports (80, 443) as non-root
# Caddy sets this up automatically via systemd service capabilities
# Start and enable
systemctl enable --now caddy
# Verify
systemctl status caddy
# Test certificate issuance
caddy validate --config /etc/caddy/Caddyfile
Step 7 — Useful Caddy Commands
# Validate config
caddy validate --config /etc/caddy/Caddyfile
# Reload config without restart (zero downtime)
caddy reload --config /etc/caddy/Caddyfile
# Format the Caddyfile
caddy fmt --overwrite /etc/caddy/Caddyfile
# List active certificates
caddy trust
# Run interactively (for testing)
caddy run --config /etc/caddy/Caddyfile
Verification Checklist
systemctl is-active caddy
curl -I https://example.com
curl -I http://example.com # Should redirect to HTTPS
journalctl -u caddy -n 20
Conclusion
Caddy on RHEL 9 provides automatic HTTPS, HTTP/2, gzip/zstd compression, and a clean reverse proxy configuration in a minimal Caddyfile. For teams that want zero certificate management overhead and a simpler configuration language than Nginx, Caddy is an excellent choice. Its automatic certificate renewal means you never deal with expired certificates.
Next steps: How to Configure Nginx Rate Limiting and Connection Throttling on RHEL 9, How to Configure Nginx FastCGI Caching on RHEL 9, and How to Set Up Varnish Cache as a Reverse Proxy on RHEL 9.