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
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 updatesudo apt install caddyOn Arch Linux:
sudo pacman -S caddyBasic Caddyfile
Edit:
sudo vim /etc/caddy/CaddyfileExample:
newapi.example.com:8445 { reverse_proxy 127.0.0.1:3000}
ds2api.example.com:8446 { reverse_proxy 127.0.0.1:6011}
pt.example.com:8443 { reverse_proxy 127.0.0.1:18080}
bot.example.com:8444 { reverse_proxy 127.0.0.1:6185}Validate before reload:
sudo caddy validate --config /etc/caddy/Caddyfilesudo systemctl reload caddyIf reload is not enough:
sudo systemctl restart caddysudo journalctl -u caddy -e --no-pagerPorts 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:
tcp dport { 80, 443, 8443, 8444, 8445, 8446 } acceptBind Apps To Localhost
The app should usually listen on localhost:
127.0.0.1:3000127.0.0.1:6011127.0.0.1:18080127.0.0.1:6185This 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.