In this tutorial, we'll learn how to set up Caddy Server on Ubuntu 24.04.
What is Caddy?
Caddy is a modern, open-source web server written in Go. It’s designed to be simple, secure, and fully automated. What makes Caddy special is that it automatically manages HTTPS certificates using Let’s Encrypt — no manual setup or renewal needed. It can serve static websites, act as a reverse proxy for backend apps, and handle load balancing with clean, human-readable configuration. In short, Caddy turns complex server management into a one-file setup that just works.
Prerequisites
Before we begin, ensure we have the following:
- An Ubuntu 24.04 dedicate server or KVM VPS.
- Basic Linux Command Line Knowledge.
- A domain name, pointing A record to server IP.
Set up Caddy Server on Ubuntu 24.04
Step 1: Update the system
sudo apt update && sudo apt upgrade -y
Keep our system fresh so packages work properly.
Step 2: Install Caddy
Caddy provides an official repository. Run these commands to add it and install:
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 -y caddy
Caddy starts automatically after installation. Check its status:
sudo systemctl status caddy
Press q to exit the status screen.
Step 3: Add our website files
Let’s create a simple site directory.
sudo mkdir -p /var/www/example
sudo nano /var/www/example/index.html
Add a small test page:
<h1>Welcome to Our Website</h1>
<p>This site is powered by Caddy Server with HTTPS.</p>
Save and exit (Ctrl + O, Enter, Ctrl + X).
Step 4: Configure Caddy
Open the main configuration file:
sudo nano /etc/caddy/Caddyfile
Replace its content with this simple setup:
example.com {
root * /var/www/example
file_server
}
Important: Replace example.com with our real domain that points to the server’s public IP address.
Step 5: Allow HTTP and HTTPS traffic
If we’re using ufw (Ubuntu firewall):
sudo ufw allow 80,443/tcp
sudo ufw reload
Step 6: Reload Caddy
sudo systemctl reload caddy
- Caddy will automatically fetch an SSL certificate from Let’s Encrypt and enable HTTPS.
- We can check it by visiting our domain in a browser:
https://example.com
If the domain points correctly, we’ll see our test page with a lock icon — meaning SSL is working.
Step 7: Check Logs (if needed)
If the site doesn’t load:
sudo journalctl -u caddy -f
This shows what’s going on in real-time.
List active certificates and expiry:
sudo caddy list-certs
Manually trigger a reload without downtime:
sudo systemctl reload caddy
# or
sudo caddy reload --config /etc/caddy/Caddyfile
Certificate renewals are automatic; list-certs shows expiry dates for verification.
Simple proxy with header forwarding and websockets
example.com {
reverse_proxy {
to localhost:3000
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote}
header_up Host {host}
}
}
This preserves original host/protocol and supports WebSocket upgrades automatically.
Reverse proxy with path match (proxy only /api)
example.com {
handle_path /api/* {
reverse_proxy localhost:8080
}
handle {
root * /var/www/html
file_server
}
}
Simple load balancing
api.example.com {
reverse_proxy lb1.internal:8080 lb2.internal:8080 {
health_path /healthz
health_interval 10s
}
}
These patterns are standard and cover most proxy needs: path routing, static file fallback, websockets, and backend pools.
Using DNS provider for wildcard certs (short practical note)
If we need *.example.com, do the DNS challenge. Two options:
- Download a Caddy binary with the DNS provider module from the Caddy download page.
- Build a custom Caddy with xcaddy including caddy-dns/<provider>.
Then configure provider credentials (example Cloudflare) in env or config and use tls directive:
example.com, *.example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
reverse_proxy ...
}
Consult the provider docs for exact environment variables and plugin names.
Security & production tips
- Run Caddy as the packaged caddy user (default) — do not run as root. Package takes care of that.
- Use a short health_path for backends so Caddy can detect failed backends and avoid routing to them.
- Keep backups of /etc/caddy/Caddyfile and any TLS-related environment variables for DNS plugins.
- For strict compliance environments, pin ACME issuer or use a private CA via tls directive.
Conclusion
We set up Caddy from the official repo, created a Caddyfile for reverse proxying apps and static content, confirmed automatic HTTPS behavior, covered wildcard/DNS challenge considerations, and included checks and production tips. Caddy removes a lot of the friction around TLS and reverse proxies; for most web apps it’s a lighter, simpler alternative to manual cert management and complex Nginx configs. Use the examples above as copy-paste templates and adapt headers/backends to our stack.

