The problem
I had six independent tools (three static single page apps, two small Node/Express services, and a Next.js application) that needed to share one domain, one TLS certificate, and one deploy process, without turning every new tool into a fresh round of manual server setup.
The approach
A single Caddy instance terminates TLS for timfas.com with automatic Let's Encrypt certificate issuance and renewal, then routes by path: static tools are served directly by Caddy's file server, the two Node services are reached through reverse_proxy to a local port with a matching systemd unit (Restart=on-failure) keeping the process alive, and the Next.js app is reverse proxied on its own port with a matching basePath so it can live at /cv-builder/ on the shared domain instead of a separate subdomain. A cron job runs a small bash uptime checker every 5 minutes against all 6 public URLs and writes a public status.json, which the portfolio page itself fetches client side to color a live status dot on every project card.
Architecture decisions
I chose Caddy over nginx specifically for automatic certificate issuance and renewal with no separate certbot process to babysit, which matters more here than nginx's larger ecosystem since I run this alone. I serve static tools directly through Caddy rather than giving each one its own Node process, so the only services that actually need to stay alive are the two that genuinely need a backend (DNS lookups and TLS socket inspection are blocked by browser CORS and cannot run client side). I built the uptime checker as a plain bash script on a 5 minute cron instead of reaching for a hosted monitoring product, trading a slightly less polished dashboard for zero external dependency and full visibility into exactly what it checks and how.
Lesson learned
The dns-inspector outage I write about in its own case study, a process killed by a clean SIGTERM that systemd's Restart=on-failure does not catch, is the direct reason I built the uptime checker and the status dots you see on every card. A restart policy alone is not monitoring. I would rather find out a tool is down from a dot on my own homepage than from someone else telling me.