Vendor NAS boxes ship a GUI-driven reverse proxy. Synology, QNAP, the rest. It is fine for a couple of domains and gets awkward fast. Here is how to move everything to a dedicated Caddy instance, and the gotchas that come with it.
Pull the full existing rule set before you migrate. You will find more running behind a reverse proxy than
you expect. Services pointed at localhost that have quietly run on the NAS itself for years with
no other documentation. Stale rules pointing at backends that moved or retired long ago. The occasional rule
with no live backend at all. Confirm what is still in use before you decide what to migrate and what to
retire.
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 will not
need to hand-replicate custom header rules from the old reverse proxy config.
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 straight from the Cloudflare dashboard with no HTTP challenge, valid for up to 15 years, and trusted specifically by Cloudflare. That is all that matters here. In Full and Full-Strict mode, Cloudflare validates your origin's certificate, not the visitor's browser.
example.com {
tls /config/origin-cert.pem /config/origin-key.pem
reverse_proxy 192.168.1.100:8080
}
openssl x509 -modulus against
openssl rsa -modulus. Then delete the local copy securely.
If your domains are proxied through a CDN to a single stable home IP, the traffic path is your router's port-forward rule, WAN 80 and 443 to a LAN target. Not DNS. Cutover is flipping that port-forward from the old backend's IP to the new reverse proxy's IP. Do it through your router's own admin UI, not automation tooling. It is a live cutover for public services, high-stakes enough to want a human 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 and backend chain, with the real certificate served.