Traefik or Caddy? Choose a Reverse Proxy by How You Deploy

# programming# productivity# tutorial# devops
Traefik or Caddy? Choose a Reverse Proxy by How You Deploydpm_bush

Adding a service behind a reverse proxy should be routine. But the workflow changes depending on...

Adding a service behind a reverse proxy should be routine. But the workflow changes depending on whether routes live in one proxy config or are discovered from your containers. That distinction is often more useful than trying to pick a universal winner between Traefik and Caddy.

A good starting point: Caddy is often simpler when you have a small, fairly stable list of sites. Traefik is often a better fit when Docker services change frequently and you want routing to follow container metadata.

The practical difference: where routes are defined

With Caddy, you typically write a site block that maps a hostname to an upstream. The routing configuration is explicit and centralized:

app.example.com {
    reverse_proxy app:3000
}
Enter fullscreen mode Exit fullscreen mode

Here, app:3000 is the service name and port reachable from Caddy on the shared Docker network. Caddy does not discover containers just because they are running; you provide or generate the upstream configuration.

Traefik can use a Docker provider to discover containers and build routes from labels on each Compose service. A minimal example of the routing labels looks like this:

services:
  app:
    image: example/app
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.services.app.loadbalancer.server.port=3000"
Enter fullscreen mode Exit fullscreen mode

This assumes Traefik is configured with the Docker provider and a matching websecure entry point, and that both services can communicate on the proxy network. The labels describe routing; they are not, by themselves, a complete HTTPS certificate setup.

The workflow difference is the point: with Caddy, you update the proxy configuration when the set of routes changes. With Traefik's Docker provider, route definitions can live alongside the application in Compose labels.

When Caddy is a sensible default

Choose Caddy when you want a readable, site-oriented configuration and do not expect routes to change constantly. This works well for a VM, home server, or small Compose stack where someone can easily review a short list of hostnames and upstreams.

Caddy can manage HTTPS automatically for eligible public hostnames. That still depends on the environment: DNS needs to point to the server, and the required validation traffic must be reachable for the method in use. In Docker, retain Caddy's data storage across container replacement so its certificate state persists.

A centralized config also gives you one obvious place to inspect when a hostname points to the wrong backend. If you want to compare Caddy with another common self-hosting option, this Caddy vs. Nginx Proxy Manager comparison covers differences in configuration and workflow.

When Traefik's discovery model helps

Choose Traefik when your Docker services are added, removed, or redeployed often, and you want routing to be driven by their metadata. Teams that treat each Compose file as the definition of an application may prefer keeping that application's proxy labels beside its service.

Traefik has more concepts to configure. Its static configuration covers items such as entry points and providers; dynamic configuration describes routers, services, and middleware. With Docker, the provider supplies dynamic configuration from container labels. This can reduce manual proxy edits, but it also means route behavior may be spread across multiple Compose files.

When a route fails, inspect what the provider discovered, the router rule and entry point, and the service's target port. Also check that the proxy and application share a network and that the backend is actually listening. A provider-driven setup is convenient, but it can make the final route less visible in one central file.

One security detail deserves attention: mounting the Docker socket gives the proxy access to the Docker API. A read-only mount is shown in many examples, but it should not be treated as a complete security boundary. Decide whether that access model is appropriate for your host, and avoid exposing the Docker API unnecessarily.

HTTPS is configuration plus reachable infrastructure

Both tools can obtain certificates automatically, but neither can bypass DNS or network requirements.

Caddy's common automatic HTTPS workflow can be concise for a public hostname. Traefik uses configured certificate resolvers, and the relevant router must use the resolver. The correct challenge and storage setup depends on the deployment. DNS challenges, for example, require credentials for the DNS provider; keep those secrets out of public Compose files and source repositories.

Before troubleshooting certificate issuance, verify the hostname's DNS and whether the chosen challenge can reach the server. For a broader look at how proxy choices differ, see this guide to choosing an Nginx alternative.

A quick decision checklist

  • A few stable sites on one server: Start with Caddy if you prefer a compact, centralized config.
  • Compose services change often: Consider Traefik if Docker labels and provider discovery fit your deployment workflow.
  • A mostly static Compose stack: Either can work. Caddy can proxy to Compose service names; Traefik can use labels or other configuration sources.
  • Kubernetes: Compare the specific provider or controller integration, supported APIs, and operational requirements. Standalone configuration behavior does not tell you everything about a Kubernetes deployment.
  • Performance is the deciding factor: Benchmark the versions and settings you plan to run. TLS, middleware, concurrency, payloads, hardware, and the backend all affect results; there is no universal winner based on a simple comparison.

Whichever you choose, test with the same hostnames, networks, TLS requirements, and deployment process you expect to use. Pick the configuration model your team can understand and maintain—not just the one with the shortest example.

I originally published a more detailed version of this guide on the SSHFlow blog.

I'm also building SSHFlow — an SSH client where every server gets its own workspace for terminals, SFTP, code, and databases.