Caddy Automatic HTTPS vs Traefik Labels: Which Reverse Proxy Survives a Compose Rewrite

Nadia Okoye

Nadia Okoye

August 25, 2026

Caddy Automatic HTTPS vs Traefik Labels: Which Reverse Proxy Survives a Compose Rewrite

I have rewritten the same Compose stack four times in two years: monolith folder to per-app files, then to a root compose.yaml plus overrides, then to a folder per VLAN. The applications survived. The reverse proxy comments did not. Traefik labels went stale on services I renamed. The Caddyfile pointed at a container DNS name that Compose no longer created. Automatic HTTPS kept working in both cases, which is how you do not notice the routing is wrong until a phone on LTE hits the old hostname.

This is not “which proxy has nicer TLS.” Both will talk to Let’s Encrypt. The question is where the truth lives when you move a service from apps/wiki to core/wiki and change the network from proxy to proxy_internal.

Caddy’s truth is a file you can read

A Caddyfile is a list of sites. Host, reverse_proxy to a name and port, maybe a handle for a path. Automatic HTTPS is the default, not a middleware you remember to attach. When I open the file I can see every public name the house answers for. That matters on the night you wonder whether grafana.example.com still exists.

The failure mode is obvious: the file is not the Compose graph. If you rename a service, Caddy still proxies to the old Docker DNS name until you edit the file. The container is healthy. The proxy is polite and wrong. That is the same class of lie as a Compose stack that looks up but is not ready. I keep the Caddyfile in the same git repo as Compose so the rewrite is one PR. I still miss the edit when the PR is “just moving files.”

caddy-docker-proxy exists if you want labels on Caddy too. Then you have Caddy with Traefik’s scatter problem. I do not use it. The whole reason I pick Caddy at home is one file, one brain.

A notepad with a handwritten list next to a mini PC

Traefik’s truth is labels on whatever you last touched

Traefik watches Docker. A service becomes routable because someone pasted eight labels on it. Routers, services, middlewares, certresolver, entrypoints. Automatic HTTPS is a resolver you named in static config and then remembered to reference. When it works, adding a new box is a label block and a restart of that service, not a trip to a central file.

When you rewrite Compose, labels are the thing that does not move correctly. YAML anchors help until they do not. An override file drops a label. A new network means the Traefik container cannot see the backend. Traefik 2 to 3 syntax has bitten people mid-rewrite. The dashboard will show a router. The router will 404 because the service points at a port you changed from 8080 to 3000 in the image and not in the label.

I like Traefik when the stack is a dozen microservices owned by one compose project that rarely changes shape. I dislike it when the homelab is a junk drawer of compose files written in different years. Labels become folklore. The Caddyfile is still folklore, but it is one page of folklore.

The rewrite that actually breaks HTTPS

Automatic HTTPS fails in boring ways that look like routing.

You change the published hostname in labels or in the Caddyfile and forget the DNS record. ACME waits. The old cert still serves the old name if that name still points at the box. You think TLS is fine.

You move Traefik onto a new compose project and lose the acme.json volume. Let’s Encrypt rate-limits you after a weekend of experiments. Caddy’s storage is also a volume you can drop. I name the volume caddy_data and I treat it like a password file. Same for Traefik’s acme.json. A Compose rewrite that “starts clean” is how you burn the weekly cert budget.

You put both proxies on 80/443 during a migration. One wins the bind. The other logs a mysterious ACME failure. I migrate by changing the LAN DNS or a temporary port, never by running two ACME clients on the same names at once.

A network switch and ethernet cables on a wooden board

Networks, not labels, are the usual outage

A rewrite almost always changes Docker networks. Traefik must share a network with every backend it routes to, or you use host networking and give up. Caddy in Docker has the same constraint: reverse_proxy wiki:3000 only works if Caddy and wiki share a network. People blame the proxy product. The product is Compose.

I now keep a dedicated edge network that is boring and long-lived. Services may move folders. They stay on edge if they are public. Internal-only services never join edge. The proxy rewrite then cannot accidentally expose Immich because someone copied a label block. Caddy does this by omission: if it is not in the file, it is not public. Traefik does this only if you are disciplined about not pasting Host( labels onto internal stacks.

That last sentence is why I have been moving household public sites to Caddy. The junk drawer of compose files will acquire Traefik labels. It will not acquire a Caddyfile site block without someone opening the file on purpose.

Middlewares and the feature you will not use

Traefik middlewares are excellent: auth forward, rate limit, headers, strip prefix. Caddy has handlers that cover most of the homelab cases, plus a plugin ecosystem. If you need an OIDC forward auth dance in front of ten apps, Traefik’s middleware chain is a reason to stay. If you need basic auth on one admin UI and gzip on the rest, Caddy is enough.

I ran Authentik in front of both. Traefik’s forwardAuth middleware was copy-paste from a wiki. Caddy’s forward_auth was a slightly shorter copy-paste. Neither rewrite was the hard part. The hard part was remembering which apps were supposed to skip auth for a webhook path. That list belongs in one file. Caddyfile again.

Who should keep Traefik

Keep Traefik if you already think in labels and your compose project is generated or consistent. Keep it if you want a dashboard of routers when you are drunk-debugging at midnight. Keep it if you are practicing for a job that uses Traefik. Homelab as career fanfic is allowed if you admit it.

Do not keep Traefik because “automatic HTTPS” is the feature. Caddy’s automatic HTTPS is the default story. Traefik’s is a configured story. Both work. The configured story has more ways to be half-right after a rewrite.

A rewrite checklist that is not a proxy war

  • Preserve the ACME volume. Name it. Back it up once.
  • Keep a long-lived edge network. Do not recreate it for neatness.
  • Change one public hostname at a time. Watch cert issue. Then the next.
  • If you use Traefik, grep the repo for traefik. after every rename.
  • If you use Caddy, grep the Caddyfile for the old container name after every rename.
  • Do not run two ACME clients on the same names.

I printed that list after the third rewrite. The fourth rewrite was boring. Boring is the win. If a step feels optional, it is the step that cost me a Saturday the last time. I do not skip the ACME volume anymore, even when the new folder structure looks cleaner without “legacy” mounts.

Logs, dashboards, and proving who answered

After a rewrite, the first argument is “which process served this 404.” Traefik’s dashboard and access log can answer if you turned them on and you can still log into the dashboard after the network change. I have locked myself out of Traefik’s dashboard by moving it behind the proxy it is. Caddy’s access logs are a file. grep Host is enough. I like that on a bad night.

Health of backends is the second argument. Traefik can take a container out of rotation. Caddy’s reverse_proxy will try the upstream and fail loudly. For a homelab with one replica, failover is a fantasy. You want a fast fail and a log line. Both can do that. Neither will save you if Compose still starts the old wiki container on a leftover profile.

I also keep a tiny curl -I script in the repo that hits every public hostname from a machine that uses public DNS, not the LAN rewrite. Rewrites break when you test from inside the house. The script has caught a Caddyfile that still pointed at wiki_1 after I dropped Compose’s old project name prefix.

What I run

Public hostnames go through Caddy. The Caddyfile is 80 lines. Compose can be ugly. The edge is not. I still have one Traefik leftover on a project that already had thirty labels and a consultant’s fingerprints. I will not rewrite it for sport. When that project dies, it dies with Traefik.

If you are starting a household proxy today and you rewrite Compose the way everyone rewrites Compose — in a hurry, on a Sunday — put the routes in a file. Labels survive a tidy stack. They do not survive a junk drawer. Automatic HTTPS will happily serve the wrong backend with a perfect certificate. That is not a compliment. The certificate only proves you still control the name. It does not prove the name still maps to the container you think you launched.

More articles for you