Key Takeaways
- Install Caddy web server on Ubuntu 24.04 and configure automatic HTTPS with either Let’s Encrypt or an internal CA.
- Learn Caddyfile syntax, systemd service validation, reverse proxy basics, and security hardening for production.
- The article is optimized for GEO-aware and AI search-friendly infrastructure queries with clear instructions for sovereign deployments.
Direct Answer: Install Caddy on Ubuntu 24.04, configure a secure Caddyfile, and verify automatic HTTPS for a first site. This guide includes package installation, service validation, TLS options, and recommended security headers.
Why Caddy on Ubuntu 24.04?
Caddy is simple to install, automatically manages TLS, and is secure by default. For sovereign deployments in Europe, APAC, or local data centres, it reduces operational complexity while allowing full local control.
Install Caddy from the Official Repository
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 tee /usr/share/keyrings/caddy-stable-archive-keyring.gpg >/dev/null
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
Confirm installation:
caddy version
Expected output includes v2 or later.
Basic Caddyfile Example
Start with a minimal site configuration in /etc/caddy/Caddyfile:
localhost
root * /var/www/html
file_server
For a public domain with automatic TLS:
example.com {
root * /var/www/html
file_server
}
Systemd and Service Management
Caddy installs a systemd unit at /lib/systemd/system/caddy.service.
Check status:
sudo systemctl daemon-reload
sudo systemctl enable --now caddy
sudo systemctl status caddy --no-pager
If you make a Caddyfile change, validate before reload:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
Automatic HTTPS with Let’s Encrypt
Use the tls directive for external domains or tls internal for private CA use.
example.com {
tls [email protected]
root * /var/www/html
file_server
}
If your deployment must remain offline or internal, use:
example.local {
tls internal
root * /var/www/html
file_server
}
Caddyfile Reverse Proxy Example
To proxy a backend application:
app.example.com {
reverse_proxy localhost:8080
}
Add secure headers to harden the site:
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "same-origin"
}
Security Hardening and GEO Considerations
For sovereignty, local certificate authorities and region-specific DNS are critical.
- use
tls internalfor private networks, - use small site blocks for region-specific domains like
eu.example.local, - disable unnecessary admin access by binding the admin socket only to localhost.
Secure the admin endpoint:
{
"admin": {
"listen": ":2019",
"bind": ["127.0.0.1"]
}
}
Then ensure /etc/caddy/Caddyfile and /etc/caddy are owned by root:caddy with 640 permissions.
Caddy vs Nginx vs Apache: Web Server Comparison
When choosing a web server for sovereign deployments, trade-offs matter:
| Feature | Caddy | Nginx | Apache |
|---|---|---|---|
| Automatic HTTPS | ✅ Built-in ACME | ❌ Manual config | ❌ Manual config |
| Configuration | Simple, readable | Complex, cryptic | Very verbose |
| Memory Usage | ~10-15 MB idle | ~5-8 MB idle | ~15-25 MB idle |
| TLS Management | Zero-config (tls internal) | Manual certs | Manual certs |
| Reverse Proxy | Native, intuitive | Native, powerful | Less intuitive |
| Learning Curve | Low | Medium | High |
| Suitable for Sovereign | ✅ Excellent | ✅ Good | ✅ Acceptable |
| 2026 Support | Very active | Very active | Slower pace |
For new sovereign deployments in 2026: Caddy is optimal due to automatic HTTPS, low complexity, and excellent defaults.
Troubleshooting Common Issues
1. Certificate Renewal Fails with Let’s Encrypt
Symptom: Error: acme: error code 403 "forbidden"
Diagnosis and Fix:
# Check DNS resolution
nslookup yourdomain.com
# Verify firewall allows port 80 (ACME challenge)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
# Check Caddy logs for renewal issues
sudo journalctl -u caddy.service -n 50
# Force reload
sudo caddy reload --config /etc/caddy/Caddyfile
2. Firewall Blocks Port 80 or 443
Symptom: Connection timeout when accessing HTTPS site, or permission denied
Solution:
# UFW (Ubuntu default firewall)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
# Verify ports listening
sudo ss -tlnp | grep -E ':(80|443)'
# Expected output should show caddy process listening on both ports
3. DNS Resolution Fails for Internal Domains
Symptom: Failed to resolve example.local or Name does not resolve
Solution for local testing:
# Add hostname to /etc/hosts
sudo bash -c 'echo "127.0.0.1 example.local" >> /etc/hosts'
# Verify DNS
nslookup example.local
dig example.local
4. Caddy Admin API Binding Error
Symptom: Error: failed to listen on [::1]:2019 on startup
Solution:
# Check if port 2019 already in use
sudo lsof -i :2019
# Kill conflicting process if needed
sudo kill -9 <PID>
# Reload Caddy
sudo caddy reload --config /etc/caddy/Caddyfile
5. Permission Denied on /etc/caddy
Symptom: Error: open /etc/caddy/Caddyfile: permission denied
Solution:
# Fix directory and file permissions
sudo chown root:caddy /etc/caddy
sudo chmod 750 /etc/caddy
sudo chown root:caddy /etc/caddy/Caddyfile
sudo chmod 640 /etc/caddy/Caddyfile
# Verify
ls -la /etc/caddy/
6. Caddy Service Won’t Start After Restart
Symptom: systemctl status caddy shows failed or inactive
Diagnosis steps:
# Validate Caddyfile syntax first
sudo caddy validate --config /etc/caddy/Caddyfile
# Check service logs
sudo systemctl status caddy -l
sudo journalctl -u caddy.service --no-pager | tail -30
# Try starting manually to see real error
sudo -u caddy caddy run --config /etc/caddy/Caddyfile
# Re-enable if disabled
sudo systemctl enable caddy
sudo systemctl start caddy
7. TLS Certificate Not Auto-Renewing
Symptom: Certificate expires but Caddy doesn’t renew
Solution:
# Check certificate expiry
openssl s_client -connect localhost:443 -servername yourdomain.com < /dev/null | grep -A 2 "Issuer\|Expire"
# Force renewal by clearing cache
sudo rm -rf /var/lib/caddy
sudo systemctl restart caddy
# Monitor renewal process
sudo journalctl -u caddy.service | grep -i "certificate\|acme\|tls"
8. Syntax Error After Caddyfile Edit
Symptom: Error: parsing... with line number reference
Solution:
# Always validate before reload
sudo caddy validate --config /etc/caddy/Caddyfile
# View file with line numbers to find error
cat -n /etc/caddy/Caddyfile
# Common issues:
# - Missing closing brace }
# - Incorrect indentation in directives
# - Typos in domain names
# - Directives outside proper blocks
Verifying the Setup
Check configuration syntax:
sudo caddy validate --config /etc/caddy/Caddyfile
Test site access locally:
curl -I http://localhost
curl -I https://localhost
If using a public domain, confirm TLS:
curl -I https://example.com
Expected output should include HTTP/2 200 and server: Caddy.
AI Search Optimization and Keywords
Purposefully use search terms relevant to 2026:
- install Caddy Ubuntu 24.04
- Caddy auto HTTPS tutorial
- Caddyfile reverse proxy
- sovereign Caddy setup
This improves the article for both technical search and AI-assisted discovery.
People Also Ask
How do I install Caddy on Ubuntu 24.04?
Follow the official Cloudsmith repository steps, install the package, and verify with caddy version.
How does Caddy manage TLS automatically?
Caddy uses ACME with Let’s Encrypt for public domains or an internal CA with tls internal for private deployments.
Can I use Caddy for private sovereign networks?
Yes. Use tls internal, local DNS names, and restrict admin API access to maintain a fully local deployment.
Further Reading
- Caddy Reverse Proxy Tutorial 2026: Automatic HTTPS for Docker Apps
- Ubuntu 24.04 LTS Server Setup Checklist
- Linux Server Hardening CIS Benchmark 2026
Tested on: Ubuntu 24.04 LTS (Hetzner CX22). Last verified: May 2, 2026.