← Back to Wiki
Networking / Caddy

Migrate Off Your NAS's Built-in Reverse Proxy

Vendor NAS boxes (Synology, QNAP, etc.) usually ship a GUI-driven reverse proxy that's fine for a couple of domains but gets awkward fast. Here's how to move everything to a dedicated Caddy instance instead, and the gotchas that come with it.

Audit before you touch anything

Before migrating, pull the full existing rule set. It's common to find more running behind a reverse proxy than you'd expect — services pointed at localhost that have been quietly running on the NAS itself for years with no other documentation, stale rules pointing at backends that moved or were retired long ago, and the occasional rule with no live backend behind it at all. Confirm what's actually still in use before deciding what to migrate versus retire.

Gotcha: bulk "delete these specific rules" GUI actions aren't always scoped the way you'd expect. Using a NAS's bulk cleanup action to remove a handful of retired sites can, in some cases, wipe the entire rule set instead of just the targeted ones — taking down every public domain, including anything security-sensitive like a password manager, until manually restored. Always verify the entire resulting rule set after any bulk GUI action, not just that the targeted items are gone. Keep a copy of the full rule list before making changes, precisely so you have something to restore from if this happens.

Standing up Caddy

A small dedicated VM or container running Caddy via Docker Compose is enough for dozens of domains. A basic site block:

example.com {
	reverse_proxy 192.168.1.100:8080
}

Caddy handles WebSocket upgrades and sets X-Forwarded-* headers automatically — you generally don't need to hand-replicate custom header rules from the old reverse proxy config.

The Cloudflare certificate gotcha

If your domains are proxied through Cloudflare with "Always Use HTTPS" enabled, Caddy's automatic HTTPS will try to get a real Let's Encrypt certificate and fail in two different ways:

Fix: use a Cloudflare Origin CA certificate instead of Let's Encrypt — issued directly from the Cloudflare dashboard with no HTTP challenge involved, valid for up to 15 years, and trusted specifically by Cloudflare (which is all that matters, since Cloudflare — not the visitor's browser — is what validates your origin's certificate in Full/Full-Strict mode).

example.com {
	tls /config/origin-cert.pem /config/origin-key.pem
	reverse_proxy 192.168.1.100:8080
}
Handling the private key safely: Cloudflare only ever shows an Origin CA private key once, in the dashboard, with no download button. Extract the certificate (public, non-sensitive) however's convenient, but get the private key by copying it directly from Cloudflare's own copy button straight into a file — never pass a raw private key through a chat tool or an automated script's output. Verify the key actually matches the certificate before deploying (compare the modulus of both with openssl x509 -modulus vs. openssl rsa -modulus), then delete the local copy securely once confirmed.

Cutover

If your domains are proxied through a CDN to a single stable home IP, the actual traffic path is your router's port-forward rule (WAN 80/443 → LAN target), not DNS. Cutover is as simple as flipping that port-forward from the old backend's IP to the new reverse proxy's IP. Do this through your router's own admin UI rather than any automation tooling — it's a live cutover for public services, high-stakes enough to want a human directly in the loop.

Verify afterward against the real public path (not a locally-forced DNS override) — confirm every domain returns the correct response through the actual CDN → port-forward → reverse-proxy → backend chain, with the real certificate being served.