Why Take Care of Your Reverse Proxy on a VPS
On a VPS, the front-end web server is the piece that orchestrates everything: it terminates TLS, distributes traffic to your containers (app, forge, media server, LLM), serves static files, and applies security headers. Well chosen, it radically simplifies enabling HTTPS on all your subdomains. Caddy obtains and renews Let's Encrypt certificates automatically, with no configuration, using a readable Caddyfile of a few lines. Nginx, the industry reference, offers extremely fine control (cache, rewrite rules, load balancing, rate limiting) but requires manual certificate management or management via Certbot. The choice pits modern automation against proven, total control.
What a Good Front End Brings to Your VPS
- Centralized TLS termination for all your subdomains
- A single reverse proxy to multiple Docker containers
- Fast static file serving and compression (gzip/brotli)
- Security headers (HSTS, CSP) applied in the same place
- With Caddy: Let's Encrypt certificates obtained and renewed all on their own
- With Nginx: cache, rate limiting, and load balancing finely tuned
Prerequisites: A Frugal Front End
A reverse proxy is very lightweight: both Caddy and Nginx run comfortably on 1 vCPU and 512 MB to 1 GB of RAM, even in front of several services. The resource to watch is rather the bandwidth and the number of simultaneous connections. You'll need a domain and its subdomains pointing to the VPS IP (A/AAAA records), ports 80 and 443 open on the firewall (port 80 is required for certificate validation), and Docker if you containerize the proxy. No GPU or large storage: here, it's the configuration that makes the difference, not raw power.
Set Up Caddy (or Nginx) as a Reverse Proxy
Point the DNS
Create the A records (and AAAA if IPv6) for each subdomain (app, git, media) pointing to the VPS IP. Let's Encrypt validation will fail as long as DNS resolution isn't effective, so verify it first.
Open Ports 80 and 443
Allow only 80 and 443 on the firewall. Port 80 remains essential for the Let's Encrypt HTTP challenge and to automatically redirect traffic to HTTPS.
Write the Configuration
With Caddy, one block is enough: app.yourdomain.com { reverse_proxy 127.0.0.1:3000 } and HTTPS is automatic. With Nginx, write one server block per subdomain with proxy_pass and the X-Forwarded-* headers, then obtain the certificate via Certbot.
Launch and Reload Without Downtime
Start the service (docker compose up -d or systemd). After each change, validate the config (nginx -t or caddy validate), then hot-reload (nginx -s reload / caddy reload) to never interrupt traffic.
Harden Security
Enable HSTS, hide the server version, enforce TLS 1.2+, and add basic rate limiting. Centralize these headers at the proxy level so that they apply to all downstream services.
Set Up Logs and Monitoring
Enable access and error logs, and watch for 502/504 codes that reveal an unreachable downstream container. A healthy front end with 502 errors always points to the proxied service, not to the proxy.
| Criterion | Caddy | Nginx |
|---|---|---|
| HTTPS / certificates | Automatic, zero config | Manual or via Certbot |
| Configuration syntax | Caddyfile, very concise | More verbose, very expressive |
| Learning curve | Low | Moderate to high |
| Fine-grained control (cache, rewrite, LB) | Good, sometimes via plugins | Very complete and proven |
| Static performance | Excellent | Excellent, the reference |
| HTTP/3 / QUIC | Enabled by default | Supported depending on version |
| Ecosystem / documentation | Recent, growing | Vast, very mature |
| Ideal for | Quick HTTPS setup, multi-subdomain | Advanced tuning, high traffic |
If you're hesitating, know that they're not mutually exclusive: a common pattern places Caddy as the very first front end to automatically manage TLS for all your subdomains, then leaves Nginx downstream for fine caching and rewrite rules of a specific service. This way you combine automatic certificates with tuning control, without picking a side for good.