SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor

Migração do Traefik v2 para v3: o que quebra

O Traefik v3 falha com `swarmMode` ou `pilot` na configuração estática. Veja como corrigir o erro de opção obsoleta e migrar as regras.

O que muda entre o Traefik v2 e o v3

A migração do Traefik v2 para o v3 consiste sobretudo em renomear componentes. A alteração mais conhecida é a mudança do middleware ipWhiteList para ipAllowList. Além disso, o v3 torna a sintaxe das regras dos routers mais rigorosa. PathPrefix deixa de aceitar funcionalidades de expressões regulares, e vários matchers são renomeados ou removidos. Alguns providers e opções também deixam de existir. O restante continua a funcionar: entrypoints, a configuração de certificados ACME, o fluxo de trabalho com labels do Docker e o seu acme.json são mantidos. O v3 também inclui um modo de compatibilidade que mantém o funcionamento da sintaxe de regras do v2. Assim, pode atualizar primeiro o binário e reescrever as regras de um serviço de cada vez, em vez de fazer toda a alteração numa única sessão com risco elevado.

Este guia pressupõe a configuração baseada em labels do Docker Compose descrita em o guia do reverse proxy Traefik. Essa página usa o v3 de forma nativa. Este guia destina-se ao servidor que ainda executa uma tag traefik:v2.

As renomeações e remoções

  • ipWhiteList passa a ser ipAllowList, tanto para o middleware HTTP como para o middleware TCP. As opções internas não mudam, por isso sourcerange mantém exatamente o mesmo significado. As versões atuais da v3, incluindo a v3.7, ainda aceitam o nome antigo como alias obsoleto e continuam a aplicar a lista, registando um aviso de obsolescência. Por isso, esta renomeação não interrompe nada durante a atualização. Faça a renomeação na mesma: o nome antigo está obsoleto e a v2.11 já entende ipAllowList, portanto a renomeação pode ser aplicada antes da atualização.
  • providers.docker.swarmMode=true foi removido. O Swarm tem agora o seu próprio provider, configurado como providers.swarm.endpoint.
  • A secção pilot foi totalmente removida.
  • experimental.http3 foi removido. O HTTP/3 é ativado diretamente no entrypoint.
  • tls.caOptional foi removido dos providers e do middleware forwardAuth. Se esse middleware estiver à frente de um SSO Authentik self-hosted, eliminar a linha caOptional é toda a migração necessária, porque o endereço do forwardAuth, os cabeçalhos confiáveis e o outpost por trás deles comportam-se da mesma forma na v3.
  • O provider de métricas InfluxDB v1, o provider Rancher e o provider Marathon foram removidos.
  • O tracing passou para o OpenTelemetry. Os backends de tracing dedicados, incluindo as integrações Jaeger e Zipkin, foram removidos, e a v3 exporta OTLP (o protocolo OpenTelemetry).
  • As opções obsoletas ssl* dentro do middleware headers (sslRedirect, sslHost e as restantes) foram removidas. Os redirecionamentos do entrypoint e o middleware redirectScheme substituíram-nas.

Estas remoções são mais importantes do que parecem, porque o Traefik recusa iniciar quando a configuração estática contém uma opção que foi removida ou que não reconhece. Uma linha pilot, swarmMode, experimental.http3 ou tls.caOptional de um provider que tenha ficado na configuração impede o contentor de arrancar: primeiro, o Traefik regista uma linha com o nome da opção que ficou, por exemplo, a opção tls.CAOptional do provider Docker foi removida na v3; depois, falha com incompatible deprecated install configuration option found. As versões até à v3.4 apresentam essa última mensagem como incompatible deprecated static option found. Uma opção que o Traefik nunca reconheceu, como um erro de escrita, interrompe o arranque com field not found e o nó em vez disso. Limpe a configuração estática antes de alterar a tag da imagem.

Um nome de middleware que o Traefik realmente não reconhece, devido a um erro de escrita ou porque foi removido sem alias, falha de outra forma: o router que o referencia é carregado com um erro em vez de uma rota, o dashboard assinala-o e a API comunica middleware "offce@docker" does not exist. Os pedidos para esse hostname recebem um 404 porque o router nunca arrancou. Tenha em atenção que ipwhitelist NÃO pertence a esta categoria na v3 atual: continua disponível como alias obsoleto, por isso um label sem renomeação continua a funcionar silenciosamente.

A sintaxe das regras mudou

As regras são onde o rewriting efetivamente acontece. As alterações na v3 são:

  • As aspas não são uma delas. Ambas as versões aceitam os valores das regras entre backticks ou entre aspas duplas escapadas e rejeitam aspas simples. Portanto, Host(app.example.com) e Host("app.example.com") com aspas duplas escapadas continuam válidos.
  • PathPrefix já não entende expressões regulares nem placeholders no formato {id}. Uma regra da v2 como PathPrefix(/api/{version:v[0-9]+}) deve passar a usar um matcher PathRegexp escrito na sintaxe de expressões regulares do Go.
  • Os matchers agora aceitam um único valor. A v2 permitia Host(app.example.com,www.example.com); a v3 exige Host(app.example.com) || Host(www.example.com). As exceções são Header, HeaderRegexp, Query e QueryRegexp, que continuam a aceitar um nome e um valor.
  • Headers e HeadersRegexp foram renomeados para Header e HeaderRegexp.
  • HostHeader foi removido. Use Host, que corresponde ao mesmo na v3.
  • Foram adicionados dois matchers: PathRegexp e QueryRegexp. ClientIP, usado para corresponder ao endereço do cliente dentro de uma regra, já existia na v2.11 e mantém-se inalterado.

A boa notícia é que uma regra simples Host(app.example.com) escrita com backticks já é uma sintaxe válida na v3. A maioria das configurações pequenas do Compose usa exatamente essa forma. Por isso, a maioria dos labels pode ser migrada sem alterações nas regras.

Audite os seus labels antes de começar

Pode medir a dimensão da migração com uma pesquisa, porque cada alteração incompatível de um label deixa um padrão que o grep consegue encontrar:

grep -rnE 'ipwhitelist|HostHeader|Headers\(|PathPrefix\(`[^`]*\{|Host\(`[^`]*`,' docker-compose*.yml

Cada ocorrência corresponde a uma linha para editar. ipwhitelist passa a ipallowlist. HostHeader passa a Host. Headers passa a Header. Um placeholder {...} dentro de PathPrefix passa a ser um matcher PathRegexp. Uma vírgula dentro de Host() passa a ser dois matchers Host() ligados por ||. Zero ocorrências significa que os seus labels já usam uma sintaxe v3 válida, e a migração fica limitada à configuração estática e à tag da imagem. Uma tela cheia de ocorrências também é um bom momento para perguntar se este ainda é o proxy certo para o servidor, e como o Traefik se compara com o Nginx e o Caddy relaciona esse custo de reescrita com o que os outros dois exigem de si por aplicação.

O que permanece igual

Os entrypoints e o respetivo redirecionamento de HTTP para HTTPS, os resolvers ACME com os dois tipos de desafio, exposedByDefault, os labels de routers e serviços, loadbalancer.server.port e o dashboard continuam a funcionar na v3 como funcionavam na v2. Os seus certificados também são mantidos, porque a v3 continua a ler o acme.json criado pela v2. Faça uma cópia de segurança do ficheiro antes de começar. Assim, evita que um rollback que o perca atinja diretamente o limite de taxa de certificados duplicados da Let's Encrypt:

cp ./letsencrypt/acme.json ./letsencrypt/acme.json.v2-backup

O caminho da migração

Passo 1: fixe o que executa atualmente. Altere qualquer etiqueta traefik:latest ou traefik:v2 para a release exata que está a usar, por exemplo traefik:v2.11, e faça commit de todo o diretório do compose no git. Todos os passos seguintes tornam-se reversíveis com um checkout. Se recriar um único serviço com docker compose up -d <service> ainda não for uma operação habitual, o guia básico do Docker Compose explica as operações usadas nesta migração.

Passo 2: limpe a configuração estática e ative o modo de compatibilidade. Remova todas as opções que a v3 eliminou (pilot, swarmMode, tls.caOptional, experimental.http3) e indique à v3 que deve interpretar as regras como sintaxe da v2 por predefinição. Em traefik.yml:

core:
  defaultRuleSyntax: v2

Ou como uma flag na lista command: do compose: --core.defaultRuleSyntax=v2. O modo de compatibilidade abrange apenas a sintaxe das regras. Não recupera opções eliminadas nem renomeia middlewares automaticamente.

Passo 3: aplique as renomeações dos middlewares enquanto ainda está na v2.11. Procure os nomes antigos nos ficheiros do compose: grep -rn ipwhitelist docker-compose*.yml. Edite todas as etiquetas ipwhitelist para ipallowlist e recrie esses serviços com docker compose up -d. A v2.11 já inclui o middleware IPAllowList, pelo que as etiquetas renomeadas funcionam antes da mudança, e o aviso de descontinuação de IPWhiteList deixa de aparecer nos logs da v2. As releases anteriores à v2.11 não conhecem o nome novo. Por isso, se fixou uma v2 mais antiga no passo 1, atualize primeiro para traefik:v2.11. (Se alguma ocorrência passar despercebida, a v3 atual ainda aceita o nome antigo como alias descontinuado, por isso a lista continua a ser aplicada. Corrija-a na passagem seguinte, e não às 2 da manhã.)

Passo 4: altere a etiqueta da imagem. Defina a imagem Traefik para a release atual da v3, traefik:v3.7 em 11 de outubro de 2026 (v3.7.14 é o patch mais recente) e execute:

docker compose up -d
docker compose logs -f traefik

Como o modo de compatibilidade está ativo, as regras da v2 continuam a corresponder. Como as renomeações dos middlewares já foram aplicadas na v2.11, esses routers iniciam sem erros. Um log saudável não contém uma linha field not found nem uma linha does not exist.

Seja realista sobre a janela de indisponibilidade criada por este passo. Um router que referencia um nome de middleware que a v3 realmente não conhece, devido a um erro de digitação ou a uma opção eliminada, fica indisponível a partir do momento em que o novo Traefik inicia até corrigir as respetivas etiquetas e recriar o contentor da aplicação. Se uma rota não puder ficar indisponível nem por um instante, remova o middleware suspeito da etiqueta middlewares desse router antes da mudança, volte a adicioná-lo depois e decida antecipadamente se a rota pode funcionar sem ele durante esse minuto.

Passo 5: migre as regras serviço a serviço. Trabalhe numa aplicação de cada vez: reescreva a respetiva regra para a sintaxe da v3, recrie apenas esse serviço com docker compose up -d app e teste-o antes de continuar. Se um serviço tiver uma regra que ainda não consegue reescrever, atribua a esse router a etiqueta de exceção traefik.http.routers.app.ruleSyntax=v2 e continue.

Passo 6: desative o modo de compatibilidade. Quando todas as regras estiverem na sintaxe da v3, elimine defaultRuleSyntax e quaisquer etiquetas ruleSyntax, reinicie o Traefik e confirme que todos os routers continuam verdes no dashboard. Não mantenha o modo de compatibilidade ativo: a Traefik descontinuou ambas as opções na v3.4 e vai removê-las na próxima versão principal. São uma ponte, não um destino.

Antes e depois: os labels de um serviço

Esta é uma aplicação com todas as alterações mais comuns ao mesmo tempo: um Host com vários valores, um placeholder PathPrefix e um middleware ipWhiteList. O bloco v2:

  app:
    image: app:1.4
    restart: unless-stopped
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`app.example.com`,`www.example.com`) && PathPrefix(`/api/{version:v[0-9]+}`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls.certresolver=le
      - traefik.http.routers.app.middlewares=office
      - traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24
      - traefik.http.services.app.loadbalancer.server.port=8080

E o mesmo serviço migrado para v3:

  app:
    image: app:1.4
    restart: unless-stopped
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=(Host(`app.example.com`) || Host(`www.example.com`)) && PathRegexp(`^/api/v[0-9]+`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls.certresolver=le
      - traefik.http.routers.app.middlewares=office
      - traefik.http.middlewares.office.ipallowlist.sourcerange=10.0.0.0/24
      - traefik.http.services.app.loadbalancer.server.port=8080

Dois labels foram alterados. A regra dividiu o Host com vários valores em dois matchers ligados por || e substituiu o placeholder por PathRegexp. O label do middleware substituiu ipwhitelist por ipallowlist. O entrypoint, o resolver de certificados, a ligação entre o router e o middleware e a porta do serviço não foram alterados.

Teste cada serviço com o dashboard

Depois de cada alteração, abra a página de routers HTTP do dashboard. Todos os routers devem estar verdes. Um router com um indicador de erro identifica o problema exato. Normalmente, trata-se de um middleware que não existe com o novo nome ou de uma regra v3 que não pode ser analisada. Em seguida, confirme o acesso a partir do exterior, um hostname de cada vez:

curl -sI https://app.example.com/api/v1/status

Um 200 ou o redirecionamento normal da sua aplicação indica que o encaminhamento e o TLS continuam a funcionar. Um 404 do Traefik indica que o router não iniciou. Volte ao dashboard e leia o erro. Mantenha docker compose logs -f traefik aberto num segundo terminal enquanto trabalha, porque todas as falhas de análise aparecem nesse local assim que um container é reiniciado.

Honestidade no rollback

Mantenha o ficheiro compose da v2, a respetiva configuração estática e o backup acme.json até todos os serviços serem encaminhados pela v3 e terem sido testados em condições reais. Fazer rollback significa recuperar o commit anterior à migração e executar docker compose up -d. É necessário recuperar o ficheiro completo, não apenas a tag da imagem, porque a sintaxe exclusiva da v3 é inválida na v2, tal como a sintaxe da v2 era inválida na v3: um matcher PathRegexp não será analisado nessa versão. Os labels ipallowlist renomeados funcionam na v2.11, mas não em nenhuma versão v2 mais antiga, que não reconhece o novo nome. Se acme.json tiver sido perdido ou danificado durante o processo, restaure a cópia de backup antes de iniciar a v2. Assim, o rollback não consumirá o seu limite de pedidos da Let's Encrypt ao emitir novamente cinco certificados em simultâneo.

FAQ

Preciso reescrever todas as regras do router para o Traefik v3?

Não. Uma regra simples Host(app.example.com) escrita com backticks é válida nas duas versões e abrange a maioria das configurações do Compose. Só é necessário reescrever as regras que usam funcionalidades exclusivas da v2: expressões regulares ou placeholders dentro de Path e PathPrefix, vários nomes de host dentro de um único Host(), ou os matchers removidos Headers, HeadersRegexp e HostHeader.

O que aconteceu ao ipWhiteList no Traefik v3?

O nome foi alterado para ipAllowList, sem alterações na configuração interna. Por isso, um label da v2 como traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 passa a ser a mesma linha com ipallowlist. A v2.11 já aceita o novo nome, portanto pode fazer a alteração antes do upgrade. As versões atuais da v3, incluindo a v3.7, ainda aceitam o nome antigo como alias obsoleto. Assim, um label sem alteração continua a aplicar a allowlist, mas gera apenas um aviso no log. Considere isto uma tolerância temporária, não uma razão para adiar a alteração. Os nomes obsoletos podem ser removidos numa versão futura. Se o Traefik realmente não reconhecer o nome de um middleware, o erro será explícito: o router apresentará um erro e devolverá 404. O dashboard mostra o erro e os pedidos para esse hostname devolvem 404.

O Traefik v3 ainda consegue ler a sintaxe de regras da v2?

Sim. Defina core.defaultRuleSyntax: v2 na configuração estática para manter a sintaxe da v2 como predefinição durante a migração. Depois de alterar novamente a predefinição, use o label ruleSyntax=v2 por router para os casos individuais que ainda não foram migrados. Considere ambas as opções temporárias: o Traefik marcou-as como obsoletas na v3.4 e irá removê-las na próxima versão principal.

Os meus certificados Let's Encrypt vão continuar disponíveis depois do upgrade?

Sim. O Traefik v3 continua a ler o ficheiro acme.json criado pela v2, portanto os certificados não são emitidos novamente apenas porque o binário mudou. Ainda assim, copie o ficheiro para um local seguro antes de começar. Um rollback ou um volume eliminado que perca acme.json obriga a emitir novamente todos os certificados de uma vez. A Let's Encrypt permite apenas cinco certificados duplicados por semana para o mesmo conjunto de hostnames.

Porque é que o Traefik v3 falha ao iniciar depois do upgrade?

Quase sempre porque a configuração estática ainda contém uma opção removida pela v3. O Traefik recusa iniciar quando encontra opções que não reconhece. Para as opções antigas mais conhecidas (pilot, providers.docker.swarmMode, experimental.http3 e tls.caOptional dos providers), o log identifica a causa e depois apresenta incompatible deprecated install configuration option found (incompatible deprecated static option found na v3.4 e anteriores). Para algo que a v3 nunca reconheceu, como um erro de escrita, apresenta field not found com o nó correspondente. Remova ou substitua cada opção e inicie novamente o contentor.