Draft, not yet published
Caddy vs Nginx for a side project you're about to make real
7 July 2026· 4 min read · by Stackbastion
Your side project is about to have real users, and every deployment guide tells you to put a “reverse proxy” in front of it. Two names keep coming up: Caddy and Nginx. You just want to know which one to pick and why, without a religious war about it. Here’s a straight answer with the config for both.
What a reverse proxy even does
Before the comparison, the job. A reverse proxy sits between the internet and your app. It handles HTTPS (the padlock), routes requests to the right service, and can add things like compression and rate limits. Your app speaks plain HTTP on a private port; the proxy is the public, encrypted front door.
Both Caddy and Nginx do this well. The difference is almost entirely about HTTPS certificates and how much config you write.
Why the choice matters more than it looks
The single biggest chore in running a real app is HTTPS certificates. A certificate proves your site is who it says it is, and it expires every 90 days. Someone or something has to renew it, forever. This is where the two tools split hard.
Caddy gets and renews certificates automatically, out of the box, with no extra tools. Nginx does not; you bolt on a separate program (certbot) and a renewal timer, and you’re responsible for keeping that working. That’s the whole story in one sentence, but the config makes it concrete.
How to fix it: the same site, both ways
Say you want app.yourdomain.com to serve a Next.js app running on port 3000, over HTTPS.
Caddy
The entire config, HTTPS included:
app.yourdomain.com {
reverse_proxy localhost:3000
}
That’s it. Point your DNS at the server, start Caddy, and it fetches a Let’s Encrypt certificate and renews it for the life of the server. Adding gzip and a security header is two more lines:
app.yourdomain.com {
encode gzip
header Strict-Transport-Security "max-age=31536000"
reverse_proxy localhost:3000
}
Nginx
The same result takes more moving parts. First the server block:
# /etc/nginx/sites-available/app
server {
listen 80;
server_name app.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Then, separately, you install certbot and let it rewrite the config to add HTTPS:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d app.yourdomain.com
Certbot installs a renewal timer, which you should then verify actually works:
sudo certbot renew --dry-run
Note the extra proxy_set_header lines. Miss them and your app sees every visitor as coming from localhost, which breaks rate limiting, logging, and anything that cares about the real client IP. Caddy sets these for you.
The honest tradeoffs
Caddy wins on simplicity for small apps. Automatic HTTPS, sane defaults, and a config file you can read in one glance. For a solo founder taking a prototype live, this is the right default.
Nginx wins on ubiquity and fine control. It’s been the standard for 20 years, so every possible problem has a Stack Overflow answer, and at very high traffic or with unusual routing needs its performance tuning knobs go deeper. If you already know Nginx cold, there’s no reason to switch.
Where people get burned with Nginx on small projects is the certificate side: a renewal timer silently breaks, the certbot config drifts, and one morning the site is throwing certificate errors. That failure mode barely exists with Caddy.
Our take: for a side project going to production, use Caddy. It removes the exact chore most likely to take your site down, and the config is short enough that you’ll actually understand it. We use Caddy in our Hetzner and Docker Compose setups for this reason.
Or, we do it for you
Certificate renewal is the kind of thing that works until it doesn’t, usually while you’re asleep. We run the proxy layer for customers with monitoring on the certificate expiry itself. Book a free audit and we’ll check your HTTPS setup.
FAQ
Is Caddy slower than Nginx?
For a normal app, no difference you’ll ever notice. Nginx has an edge in synthetic benchmarks at extreme request rates, but a side project isn’t serving a million requests a second. Real traffic on either tool is bottlenecked by your app and database, not the proxy.
Can I switch from Nginx to Caddy later?
Yes, and it’s usually a downgrade in line count. The main thing to redo is any custom routing or header logic, since the syntax differs. For a simple reverse proxy, the Caddy version is a fraction of the Nginx config.
Do I still need certbot with Caddy?
No. That’s the point. Caddy has its own certificate management built in and talks to Let’s Encrypt directly. Installing certbot alongside Caddy just creates two things fighting over the same job.
What about apps that aren’t on the same server as the proxy?
Both handle it. In Caddy you change reverse_proxy localhost:3000 to the target’s address; in Nginx you change proxy_pass. Inside Docker Compose you use the service name, like reverse_proxy web:3000, which is exactly what our Compose example does.