SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor

Міграція Traefik v2 на v3: що зламається

Traefik v3 не запускається з swarmMode або pilot у static config. Виправте помилку "incompatible deprecated install configuration option", а потім оновіть правила.

Що змінюється між Traefik v2 і v3

Міграція з Traefik v2 на v3 здебільшого полягає в перейменуванні. Найвідоміша зміна — middleware ipWhiteList перейменовано на ipAllowList. Крім цього, v3 суворіше перевіряє синтаксис правил роутерів: PathPrefix втрачає підтримку regex-функцій, кілька matchers перейменовано або видалено, а деякі провайдери й параметри повністю вилучено. Усе інше продовжує працювати: entrypoints, налаштування сертифікатів ACME, процес із Docker labels і ваш acme.json. У v3 також є режим сумісності, який підтримує синтаксис правил v2. Тому спочатку можна оновити binary, а потім переписувати правила для кожного сервісу окремо, не виконуючи всі зміни за один ризикований вечір.

У цьому посібнику використовується налаштування Docker Compose на основі labels із посібника з reverse proxy Traefik. Ту сторінку написано для v3; цей матеріал призначений для сервера, на якому досі запущено tag traefik:v2.

Перейменування та вилучення

  • ipWhiteList тепер має назву ipAllowList — і для HTTP middleware, і для TCP middleware. Внутрішні параметри не змінилися, тому sourcerange зберігає точне значення. Поточні релізи v3, зокрема v3.7, і далі приймають стару назву як deprecated alias і продовжують застосовувати список, записуючи для неї попередження про застарілу назву. Тому саме це перейменування не спричиняє простою під час переходу. Усе одно перейменуйте її: стара назва deprecated, а v2.11 уже розуміє ipAllowList, тому перейменування можна застосувати до оновлення.
  • providers.docker.swarmMode=true вилучено. Для Swarm передбачено окремий provider, який налаштовується як providers.swarm.endpoint.
  • Розділ pilot повністю вилучено.
  • experimental.http3 вилучено. HTTP/3 вмикається безпосередньо на entrypoint.
  • tls.caOptional вилучено з providers і middleware forwardAuth. Якщо цей middleware проксирує self-hosted Authentik SSO, видалення рядка caOptional є всією необхідною міграцією, оскільки адреса forwardAuth, довірені заголовки та outpost за ними працюють у v3 так само.
  • Metrics provider InfluxDB v1, provider Rancher і provider Marathon вилучено.
  • Трасування перенесено до OpenTelemetry. Спеціалізовані бекенди трасування, зокрема інтеграції Jaeger і Zipkin, вилучено, а v3 натомість експортує OTLP (протокол OpenTelemetry).
  • Deprecated-параметри ssl* усередині middleware headers (sslRedirect, sslHost та решту) вилучено. Їх замінили редиректи entrypoint і middleware redirectScheme.

Ці вилучення важливіші, ніж може здатися, оскільки Traefik відмовляється запускатися, якщо статична конфігурація містить вилучений або невідомий параметр. Залишений рядок pilot, swarmMode, experimental.http3 або provider tls.caOptional зупиняє контейнер під час запуску: спочатку Traefik записує рядок із назвою залишеного параметра, наприклад Docker provider tls.CAOptional option has been removed in v3, а потім завершує роботу з помилкою incompatible deprecated install configuration option found. У релізах до v3.4 останнє повідомлення має формулювання incompatible deprecated static option found. Параметр, про який Traefik взагалі не знає, наприклад через друкарську помилку, зупиняє його з помилкою field not found і відповідним повідомленням. Очистьте статичну конфігурацію, перш ніж змінювати тег image.

Якщо Traefik справді не знає назви middleware (через друкарську помилку або тому, що назву вилучено, а не залишено як alias), результат інший: router, який посилається на нього, завантажується з помилкою замість маршруту, dashboard позначає його, а API повертає middleware "offce@docker" does not exist. Запити до цього hostname отримують 404, оскільки router не запустився. Зверніть увагу: ipwhitelist НЕ належить до цієї категорії в поточній v3. Він зберігається як deprecated alias, тому label без перейменування продовжує працювати, але для нього записується попередження про застарілу назву.

Синтаксис правил змінюється

Саме в правилах відбувається основна частина переписування. Зміни у v3:

  • Кавування не змінилося. Обидві версії приймають значення правил у зворотних лапках або в екранованих подвійних лапках і відхиляють одинарні лапки, тому Host(app.example.com) і Host("app.example.com") з екранованими подвійними лапками залишаються коректними без змін.
  • PathPrefix більше не підтримує регулярні вирази або заповнювачі у стилі {id}. Правило v2 на кшталт PathPrefix(/api/{version:v[0-9]+}) потрібно замінити на matcher PathRegexp, записаний у синтаксисі регулярних виразів Go.
  • Тепер matchers приймають одне значення. У v2 дозволявся запис Host(app.example.com,www.example.com); у v3 потрібно використовувати Host(app.example.com) || Host(www.example.com). Винятки — Header, HeaderRegexp, Query і QueryRegexp. Вони й надалі приймають ім’я та значення.
  • Headers і HeadersRegexp перейменовано на Header і HeaderRegexp.
  • HostHeader видалено. Використовуйте Host, який у v3 відповідає тому самому значенню.
  • Додано два matchers: PathRegexp і QueryRegexp. ClientIP для зіставлення адреси клієнта в правилі вже існував у v2.11 і переноситься без змін.

Добра новина: просте правило Host(app.example.com), записане у зворотних лапках, уже відповідає синтаксису v3. Більшість невеликих конфігурацій Compose використовують саме такий запис, тому для більшості labels не потрібно змінювати правила.

Перевірте мітки перед початком

Розмір міграції можна оцінити одним пошуком, оскільки кожна несумісна зміна мітки залишає шаблон, який може знайти grep:

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

Кожен збіг — це один рядок для редагування. ipwhitelist стає ipallowlist. HostHeader стає Host. Headers стає Header. Заповнювач {...} усередині PathPrefix стає зіставником PathRegexp. Кома всередині Host() перетворюється на два зіставники Host(), об’єднані оператором ||. Нуль збігів означає, що ваші labels уже відповідають синтаксису v3, і міграція зводиться до статичної конфігурації та тегу image. Повний екран збігів — також слушний момент запитати себе, чи справді це все ще правильний proxy для цього сервера; у матеріалі як Traefik порівнюється з Nginx і Caddy вартість такого переписування зіставлено з тим, що інші два варіанти вимагатимуть від вас для кожного застосунку.

Що залишається без змін

Точки входу та їхній редирект з HTTP на HTTPS, ACME-resolver-и з обома типами challenge, exposedByDefault, labels router і service, loadbalancer.server.port та dashboard у v3 працюють так само, як у v2. Ваші сертифікати також збережуться, оскільки v3 продовжує читати acme.json, створений v2. Проте перед початком усе одно зробіть резервну копію цього файла, оскільки відкат із його втратою одразу призведе до досягнення ліміту Let's Encrypt на дублікати сертифікатів:

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

Шлях міграції

Крок 1: зафіксуйте те, що використовується сьогодні. Замініть будь-який тег traefik:latest або traefik:v2 на точний реліз, який ви використовуєте, наприклад traefik:v2.11, і зафіксуйте весь каталог compose у git. Кожен наступний крок можна буде скасувати за допомогою checkout. Якщо відтворення окремого сервісу за допомогою docker compose up -d <service> ще не стало звичною операцією, посібник з основ Docker Compose описує операції, на яких ґрунтується ця міграція.

Крок 2: очистьте статичну конфігурацію та ввімкніть режим сумісності. Видаліть усі опції, які v3 вилучив (pilot, swarmMode, tls.caOptional, experimental.http3), а потім вкажіть v3 обробляти правила за замовчуванням як синтаксис v2. У traefik.yml:

core:
  defaultRuleSyntax: v2

Або передайте це як flag у списку compose command:: --core.defaultRuleSyntax=v2. Режим сумісності охоплює лише синтаксис правил. Він не повертає вилучені опції та не перейменовує middleware автоматично.

Крок 3: перейменуйте middleware, поки ще використовується v2.11. Знайдіть у compose-файлах старі назви: grep -rn ipwhitelist docker-compose*.yml. Змініть кожен label ipwhitelist на ipallowlist і відтворіть ці сервіси за допомогою docker compose up -d. У v2.11 уже є middleware IPAllowList, тому перейменовані label працюють ще до переходу, а попередження про застарілий IPWhiteList зникає з журналів v2. Релізи, старші за v2.11, не знають нової назви, тому якщо на кроці 1 ви зафіксували старішу версію v2, спочатку перейдіть на traefik:v2.11. (Якщо якась назва залишиться, поточна v3 і далі підтримує стару назву як застарілий alias, тому список продовжить застосовуватися; виправте це під час наступного проходу, а не о 2:00 ночі.)

Крок 4: змініть тег image. Встановіть для image Traefik поточний реліз v3 — traefik:v3.7 станом на 11 October 2026 (v3.7.14 є останнім patch-релізом), а потім:

docker compose up -d
docker compose logs -f traefik

Оскільки режим сумісності ввімкнено, ваші правила v2 продовжать зіставлятися. Оскільки перейменування middleware уже виконано у v2.11, ці router запустяться без помилок. У справному журналі немає рядка field not found і рядка does not exist.

Реалістично оцініть вікно недоступності, яке створює цей крок. Router, що посилається на назву middleware, яку v3 справді не розпізнає (через помилку в написанні або вилучену опцію), буде недоступним від моменту запуску нового Traefik до виправлення його label і відтворення контейнера застосунку. Якщо маршрут не може навіть короткочасно перериватися, видаліть підозріле middleware з label middlewares цього router до переходу, додайте його знову після переходу та заздалегідь визначте, чи може маршрут працювати без нього протягом цієї хвилини.

Крок 5: мігруйте правила для кожного сервісу окремо. Працюйте з одним застосунком за раз: перепишіть його правило відповідно до синтаксису v3, відтворіть лише цей сервіс за допомогою docker compose up -d app і перевірте його перед переходом до наступного. Якщо для певного сервісу правило ще неможливо переписати, додайте лише для цього router label-виняток traefik.http.routers.app.ruleSyntax=v2 і продовжуйте міграцію.

Крок 6: вимкніть режим сумісності. Коли всі правила використовують синтаксис v3, видаліть defaultRuleSyntax і всі label ruleSyntax, перезапустіть Traefik і переконайтеся, що кожен router і далі позначений зеленим у dashboard. Не залишайте режим сумісності ввімкненим: у v3.4 Traefik позначив обидві опції як застарілі, а в наступній major-версії вилучить їх. Це міст, а не кінцева конфігурація.

До і після: labels одного сервісу

Ось один застосунок, у якому одночасно відбулися всі типові зміни: багатозначний Host, заповнювач PathPrefix і middleware ipWhiteList. Блок 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

І той самий сервіс після міграції на 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

Змінилися два labels. Правило розділило багатозначний Host на два matchers, об’єднані через ||, і замінило заповнювач на PathRegexp, а label middleware замінив ipwhitelist на ipallowlist. Entrypoint, засіб розв’язання сертифікатів, зв’язок router із middleware та порт сервісу не змінилися.

Перевірте кожен сервіс за допомогою dashboard

Після кожної зміни відкривайте сторінку HTTP routers у dashboard. Усі routers мають бути зеленими. Router зі значком помилки вказує точну проблему. Зазвичай це middleware, якого немає під новою назвою, або правило, яке v3 не може обробити. Потім перевірте доступ ззовні, по одному hostname за раз:

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

200 або звичайний redirect вашого застосунку означає, що маршрутизація й TLS працюють. 404 від Traefik означає, що router не запустився. Поверніться до dashboard і прочитайте його помилку. Під час роботи тримайте docker compose logs -f traefik відкритим у другому терміналі, оскільки кожна помилка парсингу з’являється там одразу після перезапуску контейнера.

Відкат без самообману

Зберігайте файл compose для v2, його статичну конфігурацію та резервну копію acme.json, доки всі сервіси не працюватимуть через v3 і не пройдуть реальну перевірку. Відкат означає перемикання на коміт до міграції та запуск docker compose up -d. Потрібно відновити весь файл, а не лише тег образу, оскільки синтаксис, доступний тільки у v3, у v2 є некоректним так само, як синтаксис v2 був некоректним у v3: засіб зіставлення PathRegexp там не розбереться. Перейменовані мітки ipallowlist працюють у v2.11, але не в жодному старішому випуску v2, який не знає нової назви. Якщо acme.json було втрачено або пошкоджено, відновіть резервну копію перед запуском v2. Так відкат не витратить ліміт Let's Encrypt на повторну видачу п’яти сертифікатів одночасно.

FAQ

Чи потрібно переписувати кожне правило маршрутизатора для Traefik v3?

Ні. Просте правило Host(app.example.com), записане у зворотних апострофах, дійсне в обох версіях і охоплює більшість конфігурацій Compose. Переписування потрібне лише тоді, коли правило використовувало функції, доступні тільки у v2: regex або заповнювачі всередині Path і PathPrefix, кілька імен хостів в одному Host() або вилучені зіставники Headers, HeadersRegexp і HostHeader.

Що сталося з ipWhiteList у Traefik v3?

Його перейменували на ipAllowList. Конфігурація всередині не змінилася, тому мітка v2 на кшталт traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 перетворюється на такий самий рядок із ipallowlist. v2.11 уже приймає нову назву, тож перейменувати її можна до оновлення. Поточні випуски v3, зокрема v3.7, усе ще приймають стару назву як застарілий псевдонім, тому неперейменована мітка продовжує застосовувати список дозволених адрес, але в журналі з’являється попередження. Не сприймайте це як причину відкладати перейменування: застарілі назви можуть бути вилучені у випуску, а ім’я middleware, якого Traefik справді не знає, спричиняє помилку маршрутизатора та відповідь 404. Помилку видно на dashboard, а запити до цього імені хоста повертають 404.

Чи може Traefik v3 і надалі читати синтаксис правил v2?

Так. У статичній конфігурації задайте core.defaultRuleSyntax: v2, щоб під час міграції синтаксис v2 залишався типовим, а після повернення типового значення використовуйте мітку ruleSyntax=v2 для окремих маршрутизаторів, які ще не перенесено. Обидва параметри слід вважати тимчасовими: Traefik оголосив їх застарілими у v3.4 і вилучить у наступній мажорній версії.

Чи збережуться мої сертифікати Let's Encrypt після оновлення?

Так. Traefik v3 продовжує читати файл acme.json, який створила v2, тому сертифікати не перевидаються лише через зміну бінарного файлу. Проте перед початком роботи скопіюйте цей файл у безпечне місце, оскільки відкат або видалення тому, через яке втрачається acme.json, змушує повторно випустити всі сертифікати одночасно. Let's Encrypt дозволяє випустити не більше п’яти дублікатів сертифіката на тиждень для того самого набору імен хостів.

Чому Traefik v3 не запускається після оновлення?

Майже завжди причина в тому, що статична конфігурація все ще містить параметр, вилучений у v3, а Traefik відмовляється запускатися, якщо не розпізнає параметр. Для відомих залишкових параметрів (pilot, providers.docker.swarmMode, experimental.http3 і tls.caOptional у провайдерів) журнал називає причину, а потім містить повідомлення incompatible deprecated install configuration option found (incompatible deprecated static option found у v3.4 і раніших версіях). Для параметрів, про які v3 нічого не знає, наприклад через помилку в написанні, з’являється повідомлення field not found із зазначенням вузла. Видаліть або замініть кожен такий параметр, потім знову запустіть контейнер.