Simplifying Web Services with Caddy
Running multiple web services doesn't have to be complicated. Here's how Caddy makes it simple by handling reverse proxying and HTTPS certificates automatically, plus a script I use to set up new services with a single command.
After my recent posts about We2.ee, Lone.Earth, Earth.Law and that pump calculator project, several folks asked about managing multiple websites without it becoming a huge time sink. The secret isn't complicated—it's a neat tool called Caddy that handles most of the tedious parts automatically.
Understanding Reverse Proxies
Traditionally, web servers were designed with a simple model: one server running a single service on ports 80 (HTTP) and—more recently as infosec awareness increased—443 (HTTPS). This made sense when most organizations ran just one website or application per server. The web server would directly handle incoming requests and serve the content.
But this model doesn't work well for self-hosting. Most of us want to run multiple services on a single machine - maybe a blog like this, a chat service like We2.ee, and a few microservices like that pump calculator. We can't dedicate an entire server to each service—that would be wasteful and expensive—and we can't run them all on ports 80/443 (only one service can use a port at a time).
This is where reverse proxies come in. They act as a traffic director for your web server. Instead of services competing for ports 80 and 443, each service runs on its own port, and the reverse proxy directs traffic for
- A blog to port 2368
- A Mastodon instance to port 3000
- An uptime tracking service to port 3001
- A code hub to port 3003
- An encrypted chat service to port 8448
- DNS-over-HTTPS filter and resolver on 8502
- A Peertube instance to port 9000
- An LLM API to port 11434
- ... etc.
When someone visits any of your websites, the reverse proxy looks at which domain they're trying to reach and routes them to the right service. That's really all there is to it—it's just routing traffic based on the requested domain.
Why Caddy Makes Life Easier
Caddy is a reverse proxy that manages this well and also happens to take care of one of the biggest headaches in web hosting: HTTPS certificates. Here's what my actual Caddy config looks like for this blog:
sij.law {
reverse_proxy localhost:2368
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}
This simple config tells Caddy to:
- Send all traffic for sij.law to the blog running on port 2368
- Automatically get HTTPS certificates from Let's Encrypt
- Renew those certificates before they expire
- Handle all the TLS/SSL security settings
If you've ever dealt with manual certificate management or complex web server configurations, you'll appreciate how much work these few lines are saving.
Making Domain Setup Even Easier
To streamline things further, I wrote a script that automates the whole domain setup process. When I was ready to launch that pump calculator I mentioned in my last post on the open web, I just ran:
cf pumpcalc.sij.ai --port 8901 --ip 100.64.64.11
One command and done—cf creates the DNS record on Cloudflare and points it to the IP of the server running Caddy, creates a Caddy configuration that reverse proxies pumpcalc.sij.ai to port 8901 on my testbench server (which has the Tailscale IP address 100.64.64.11
), and handles the HTTPS certification.
If you want to try this script out yourself, see the more detailed documentation at sij.ai/sij/cf, and by all means have a look at the Python code and see how it works under the hood.
Getting Started
- Start by installing Caddy on your server
- Create a config for just one website
- Let Caddy handle your HTTPS certificates
- Add more sites when you're ready
Start small, get comfortable with how it works, and expand when you need to. Ready to dig deeper? The Caddy documentation is excellent, or feel free to reach out with questions.