2026-03-27 · TraefikDockerReverse ProxyMigration

Traefik v3 Is Out. Here's What Broke in the Wild.

Traefik v3 starts successfully. Logs nothing obvious. Your containers are running. The routes just return 404. No error. No warning. This is what is actually breaking and why.

Traefik v3 has been out for months. The migration from v2 should have been straightforward — most of the core label syntax is identical. Instead, r/selfhosted and r/docker are full of threads from people whose routes silently stopped working after the upgrade.

Here's what's actually breaking and why.

The silent failure problem

Traefik v3 does not error on invalid or deprecated configuration. It starts successfully. It logs nothing obvious. Your containers are running. The routes just don't exist.

This is why the migration catches people off guard. There's no clear failure signal — just 404s from routes that used to work.

What broke for most people

1. Docker network not explicitly configured

This is the most common failure. In v2, Traefik could usually figure out which Docker network to use for routing. In v3, if Traefik and your containers are on different networks, the route is created but has no healthy backends — returns 404.

# The fix — create a shared external network:
docker network create traefik-public

# Traefik service:
services:
  traefik:
    networks:
      - traefik-public

# Every routed service:
services:
  myapp:
    networks:
      - traefik-public
    labels:
      - "traefik.docker.network=traefik-public"

networks:
  traefik-public:
    external: true

The traefik.docker.network label is now required when multiple networks are involved. In v2 it was optional.

2. Old v1 labels still in compose files

Traefik v1 labels (traefik.frontend.*, traefik.backend, traefik.port) were deprecated in v2 but silently accepted. In v3 they are completely ignored — no warning, no error, no route.

# These do nothing in v3 — remove them:
traefik.frontend.rule=Host:app.example.com
traefik.backend=myapp
traefik.port=3000
traefik.frontend.entryPoints=https

# Replace with:
traefik.enable=true
traefik.http.routers.myapp.rule=Host("app.example.com")
traefik.http.routers.myapp.entrypoints=websecure
traefik.http.routers.myapp.tls.certresolver=letsencrypt
traefik.http.services.myapp.loadbalancer.server.port=3000

3. swarmMode in static config

If your traefik.yml has swarmMode: false inside the Docker provider block, Traefik v3 throws a startup error because Swarm configuration moved to a separate provider.

# v2 static config (breaks in v3):
providers:
  docker:
    swarmMode: false  # Remove this line

# v3 — Swarm is now a separate provider:
providers:
  docker:
    exposedByDefault: false
  # swarm: (only add if actually using Swarm)

4. allowEmptyServices removed

If you had allowEmptyServices: true in your Docker provider config to allow Traefik to start when backends are down — it's gone. Remove it from your config. Traefik v3 handles empty services differently and the option is no longer needed.

How to diagnose what broke

# Check Traefik's view of your routers:
curl http://localhost:8080/api/http/routers | python3 -m json.tool | grep -A5 "status"

# Look for routers with no services or "error" status
# Check which containers Traefik can see:
curl http://localhost:8080/api/http/services | python3 -m json.tool

Enable the Traefik dashboard if you haven't already — it shows you exactly which routes exist and whether their backends are healthy. A router with 0 healthy servers is your problem.

The labels that still work identically

To be clear — the core v2 label syntax is unchanged in v3. These still work:

traefik.enable=true
traefik.http.routers.NAME.rule=Host("domain.com")
traefik.http.routers.NAME.tls.certresolver=letsencrypt
traefik.http.services.NAME.loadbalancer.server.port=3000
traefik.http.middlewares.NAME.redirectscheme.scheme=https

If your setup only uses basic routing with TLS, you may not need to change anything except add the explicit network configuration.

Quick migration checklist

Paste your docker-compose.yml or nginx.conf to detect Traefik v1 label patterns and get exact v3 replacements.

Related guides