Caddy Reverse Proxy Notes
Caddy Reverse Proxy Notes
This note records the Caddy setup I keep reusing for small VPS services.
Caddy is good for this use case because the config is short and ACME
certificate management is automatic. Most app services can stay on
127.0.0.1, while Caddy is the only public HTTP/TLS
entry.
Example domains and ports:
newapi.example.com:8445->127.0.0.1:3000ds2api.example.com:8446->127.0.0.1:6011pt.example.com:8443->127.0.0.1:18080bot.example.com:8444->127.0.0.1:6185
Install On Debian
1 | sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl |
On Arch Linux:
1 | sudo pacman -S caddy |
Basic Caddyfile
Edit:
1 | sudo vim /etc/caddy/Caddyfile |
Example:
1 | newapi.example.com:8445 { |
Validate before reload:
1 | sudo caddy validate --config /etc/caddy/Caddyfile |
If reload is not enough:
1 | sudo systemctl restart caddy |
Ports And ACME
For normal automatic certificates, Caddy needs to complete ACME challenges. Keep these in mind:
80should be reachable for HTTP-01 challenges.443should be reachable for normal HTTPS sites.- If another service owns
443, Caddy can still serve HTTPS on another port, but certificate issuance may need80or DNS challenge.
Example firewall rules:
1 | tcp dport { 80, 443, 8443, 8444, 8445, 8446 } accept |
Bind Apps To Localhost
The app should usually listen on localhost:
1 | 127.0.0.1:3000 |
This prevents users from bypassing Caddy and hitting the raw app port directly.
Notes
- Put one service block per tool. Do not mix service-specific config into a generic Caddy note.
- Caddyfile changes should be validated before reload.
- If the app rejects proxied requests because of host header validation, fix that in the app config deliberately instead of exposing the app port.
- Do not publish real internal domains or private ports if they reveal your infrastructure layout.