SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor

Nâng cấp Traefik v2 lên v3: lỗi và cách sửa

Traefik v3 báo lỗi “incompatible deprecated install configuration option” nếu còn swarmMode hoặc pilot. Sửa static config rồi đổi rule từng service.

Những gì thay đổi giữa Traefik v2 và v3

Việc chuyển từ Traefik v2 sang v3 chủ yếu là đổi tên. Thay đổi nổi tiếng nhất là middleware ipWhiteList được đổi thành ipAllowList. Ngoài ra, v3 siết chặt cú pháp router rule (PathPrefix không còn các tính năng regex, một số matcher được đổi tên hoặc bị xóa), loại bỏ hoàn toàn một số provider và option, còn các thành phần khác vẫn hoạt động: entrypoint, cấu hình chứng chỉ ACME, quy trình dùng Docker label và acme.json của bạn đều được giữ nguyên. v3 cũng có compatibility mode để tiếp tục dùng cú pháp rule của v2. Vì vậy, bạn có thể nâng cấp binary trước rồi viết lại rule cho từng service, thay vì phải đổi tất cả trong một lần đầy rủi ro.

Hướng dẫn này giả định bạn dùng thiết lập Docker Compose dựa trên label trong hướng dẫn reverse proxy Traefik. Trang đó dùng v3-native; còn trang này dành cho máy chủ vẫn đang chạy tag traefik:v2.

Các mục đổi tên và bị loại bỏ

  • ipWhiteList nay là ipAllowList, áp dụng cho cả HTTP middleware và TCP middleware. Các option bên trong không thay đổi, nên sourcerange vẫn giữ nguyên ý nghĩa. Các bản release v3 hiện tại, bao gồm v3.7, vẫn chấp nhận tên cũ dưới dạng alias deprecated và tiếp tục áp dụng danh sách, đồng thời ghi log cảnh báo deprecated cho tên này. Vì vậy, riêng việc đổi tên này không làm dịch vụ ngừng hoạt động khi chuyển sang v3. Dù vậy, hãy đổi tên: tên cũ đã deprecated, còn v2.11 đã hiểu ipAllowList, nên có thể triển khai việc đổi tên trước khi upgrade.
  • providers.docker.swarmMode=true đã bị loại bỏ. Swarm có provider riêng, được cấu hình bằng providers.swarm.endpoint.
  • Phần pilot đã bị loại bỏ hoàn toàn.
  • experimental.http3 đã bị loại bỏ. HTTP/3 được bật trực tiếp trên entrypoint.
  • tls.caOptional đã bị loại bỏ khỏi providers và khỏi forwardAuth middleware. Nếu middleware này đứng trước Auth​​entik SSO tự host, xóa dòng caOptional là toàn bộ phần migration cần làm, vì địa chỉ forwardAuth, các trusted headers và outpost phía sau vẫn hoạt động giống nhau trên v3.
  • Metrics provider InfluxDB v1, Rancher provider và Marathon provider đã bị loại bỏ.
  • Tracing đã chuyển sang OpenTelemetry. Các tracing backend riêng, bao gồm các integration Jaeger và Zipkin, đã bị loại bỏ; thay vào đó, v3 export OTLP (giao thức OpenTelemetry).
  • Các option ssl* deprecated bên trong headers middleware (sslRedirect, sslHost và các option còn lại) đã bị loại bỏ. Entrypoint redirection và redirectScheme middleware đã thay thế chúng.

Các mục bị loại bỏ này quan trọng hơn vẻ ngoài, vì Traefik sẽ không khởi động nếu static configuration chứa option đã bị loại bỏ hoặc không được nhận diện. Một dòng pilot, swarmMode, experimental.http3 hoặc provider tls.caOptional còn sót lại sẽ làm container dừng khi boot: trước tiên Traefik ghi log một dòng nêu tên mục còn sót lại (ví dụ, option tls.CAOptional của Docker provider đã bị loại bỏ trong v3), sau đó dừng với incompatible deprecated install configuration option found. Các release đến v3.4 ghi thông báo cuối dưới dạng incompatible deprecated static option found. Một option mà Traefik hoàn toàn không nhận diện, chẳng hạn typo, sẽ làm Traefik dừng với field not found, khiến node không khởi động theo. Hãy dọn static configuration trước khi thay image tag.

Một middleware mà Traefik thực sự không nhận diện (do typo hoặc do tên đã bị loại bỏ thay vì được giữ lại dưới dạng alias) sẽ lỗi theo cách khác: router tham chiếu đến middleware đó sẽ load kèm lỗi thay vì tạo route, dashboard đánh dấu middleware đó, còn API trả về middleware "offce@docker" does not exist. Request đến hostname đó nhận 404 vì router chưa bao giờ khởi động. Lưu ý rằng ipwhitelist KHÔNG thuộc nhóm này trên v3 hiện tại: nó vẫn tồn tại dưới dạng alias deprecated, nên label chưa đổi tên vẫn âm thầm hoạt động.

Cú pháp rule thay đổi

Rule là nơi thực hiện các thay đổi rewrite thực sự. Những thay đổi trong v3:

  • Cách đặt dấu trích dẫn không thay đổi. Cả hai phiên bản đều nhận giá trị của rule trong backtick hoặc double quote đã escape và đều từ chối single quote. Vì vậy, Host(app.example.com) và Host("app.example.com") với double quote đã escape vẫn hợp lệ như cũ.
  • PathPrefix không còn hỗ trợ regular expression hoặc placeholder kiểu {id}. Rule v2 như PathPrefix(/api/{version:v[0-9]+}) phải chuyển thành matcher PathRegexp được viết theo cú pháp regular expression của Go.
  • Matcher hiện chỉ nhận một giá trị. v2 cho phép Host(app.example.com,www.example.com); v3 yêu cầu Host(app.example.com) || Host(www.example.com). Các ngoại lệ là Header, HeaderRegexp, Query và QueryRegexp. Những matcher này vẫn nhận một name cùng một value.
  • Headers và HeadersRegexp được đổi tên thành Header và HeaderRegexp.
  • HostHeader bị loại bỏ. Hãy dùng Host, matcher này khớp cùng đối tượng trong v3.
  • Có 2 matcher mới: PathRegexp và QueryRegexp. ClientIP, dùng để khớp địa chỉ client bên trong một rule, đã có từ v2.11 và được giữ nguyên trong v3.

Điểm thuận lợi là rule Host(app.example.com) đơn giản được viết bằng backtick đã là cú pháp v3 hợp lệ. Hầu hết Compose setup nhỏ đều dùng đúng dạng này. Vì vậy, phần lớn label có thể migrate mà không cần sửa rule.

Kiểm tra label trước khi bắt đầu

Bạn có thể đo quy mô migration bằng một lần tìm kiếm, vì mọi thay đổi label gây lỗi đều để lại một pattern mà grep có thể tìm thấy:

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

Mỗi kết quả là một dòng cần sửa. ipwhitelist trở thành ipallowlist. HostHeader trở thành Host. Headers trở thành Header. Placeholder {...} bên trong PathPrefix trở thành matcher PathRegexp. Dấu phẩy bên trong Host() trở thành hai matcher Host() được nối bằng ||. Không có kết quả nghĩa là các label của bạn đã dùng cú pháp v3 hợp lệ, và migration chỉ còn phần cấu hình tĩnh cùng image tag. Nếu màn hình hiển thị đầy kết quả, đây cũng là lúc hợp lý để xem xét liệu proxy này còn phù hợp với máy chủ hay không. Traefik khác Nginx và Caddy như thế nào sẽ giúp bạn so sánh chi phí viết lại này với những gì hai lựa chọn còn lại yêu cầu cho từng app.

Những phần không thay đổi

Entrypoint và cơ chế redirect từ HTTP sang HTTPS, ACME resolver với cả hai loại challenge, exposedByDefault, các label của router và service, loadbalancer.server.port cùng dashboard vẫn hoạt động trong v3 như trong v2. Các certificate của bạn cũng được giữ nguyên vì v3 tiếp tục đọc acme.json do v2 tạo. Tuy vậy, hãy backup file này trước khi bắt đầu. Nếu rollback làm mất file, bạn sẽ ngay lập tức gặp rate limit cấp certificate trùng lặp của Let's Encrypt:

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

Lộ trình migration

Bước 1: cố định phiên bản bạn đang chạy. Đổi mọi tag traefik:latest hoặc traefik:v2 thành đúng release hiện tại, ví dụ traefik:v2.11, rồi commit toàn bộ thư mục compose vào git. Từ đó, mọi bước tiếp theo đều có thể hoàn tác bằng checkout. Nếu bạn chưa quen với việc tạo lại một service riêng bằng docker compose up -d <service>, hướng dẫn cơ bản về Docker Compose trình bày các thao tác được dùng trong migration này.

Bước 2: dọn cấu hình tĩnh và bật compatibility mode. Xóa mọi option bị v3 loại bỏ (pilot, swarmMode, tls.caOptional, experimental.http3), rồi yêu cầu v3 mặc định xử lý các rule theo cú pháp v2. Trong traefik.yml:

core:
  defaultRuleSyntax: v2

Hoặc truyền dưới dạng flag trong danh sách compose command:: --core.defaultRuleSyntax=v2. Compatibility mode chỉ áp dụng cho cú pháp rule. Nó không khôi phục các option đã bị loại bỏ và cũng không tự đổi tên middleware.

Bước 3: đổi tên middleware khi vẫn đang chạy v2.11. Tìm tên cũ trong các file compose: grep -rn ipwhitelist docker-compose*.yml. Sửa mọi label ipwhitelist thành ipallowlist rồi tạo lại các service đó bằng docker compose up -d. v2.11 đã có middleware IPAllowList, nên các label mới hoạt động trước khi chuyển sang v3 và cảnh báo deprecation của IPWhiteList sẽ không còn xuất hiện trong log v2. Các release cũ hơn v2.11 không nhận diện tên mới. Vì vậy, nếu bạn đã pin một bản v2 cũ ở bước 1, trước tiên hãy nâng lên traefik:v2.11. (Nếu còn sót một label, v3 hiện tại vẫn chấp nhận tên cũ dưới dạng alias deprecated, nên rule vẫn tiếp tục được áp dụng; hãy sửa ở lần rà soát tiếp theo, không cần xử lý lúc 2am.)

Bước 4: đổi image tag. Đặt image Traefik thành release v3 hiện tại, traefik:v3.7 tính đến ngày 11 October 2026 (v3.7.14 là patch mới nhất), rồi chạy:

docker compose up -d
docker compose logs -f traefik

Vì compatibility mode đang bật, các rule v2 vẫn khớp. Vì đã đổi tên middleware từ v2.11, các router đó cũng khởi động mà không gặp lỗi. Log bình thường không có dòng field not found và cũng không có dòng does not exist.

Hãy đánh giá đúng khoảng gián đoạn mà bước này có thể gây ra. Một router tham chiếu đến tên middleware mà v3 thực sự không nhận diện được (do gõ sai hoặc do option đã bị loại bỏ) sẽ ngừng hoạt động ngay khi Traefik mới khởi động, cho đến khi bạn sửa label và tạo lại app container của router đó. Nếu một route thực sự không được phép gián đoạn, hãy xóa middleware đáng ngờ khỏi label middlewares của router đó trước khi chuyển đổi, rồi thêm lại sau. Đồng thời, hãy quyết định trước route đó có thể tạm thời chạy không có middleware trong khoảng một phút hay không.

Bước 5: migrate rule theo từng service. Xử lý từng app: viết lại rule theo cú pháp v3, chỉ tạo lại service đó bằng docker compose up -d app, rồi kiểm tra trước khi chuyển sang service tiếp theo. Nếu một service có rule mà bạn chưa thể viết lại, hãy thêm label escape hatch traefik.http.routers.app.ruleSyntax=v2 cho riêng router đó rồi tiếp tục.

Bước 6: tắt compatibility mode. Khi mọi rule đã dùng cú pháp v3, xóa defaultRuleSyntax và mọi label ruleSyntax, restart Traefik, rồi xác nhận tất cả router vẫn hiển thị màu xanh trong dashboard. Không nên tiếp tục dùng compatibility mode: Traefik đã deprecate cả 2 option này từ v3.4 và sẽ loại bỏ chúng trong major version tiếp theo. Đây là giải pháp chuyển tiếp, không phải cấu hình đích.

Trước và sau: label của một service

Đây là một app áp dụng đồng thời mọi thay đổi phổ biến: một Host có nhiều giá trị, một placeholder PathPrefix và một middleware ipWhiteList. Block 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

Cùng service đó sau khi migrate sang 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

Hai label đã thay đổi. Rule tách Host có nhiều giá trị thành 2 matcher được nối bằng || và thay placeholder bằng PathRegexp. Label của middleware đổi ipwhitelist thành ipallowlist. Entrypoint, certificate resolver, cách nối router với middleware và service port không thay đổi.

Kiểm tra từng service bằng dashboard

Sau mỗi lần chuyển đổi, mở trang HTTP routers của dashboard. Tất cả router phải hiển thị màu xanh. Router có huy hiệu lỗi sẽ nêu chính xác vấn đề. Thường đó là middleware không tồn tại dưới tên mới hoặc một rule v3 không thể phân tích. Sau đó xác nhận từ bên ngoài, từng hostname một:

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

200 hoặc redirect thông thường của app cho biết routing và TLS vẫn hoạt động. 404 từ Traefik cho biết router chưa khởi động; quay lại dashboard và đọc lỗi của router đó. Giữ docker compose logs -f traefik mở trong terminal thứ hai khi thao tác, vì mọi lỗi phân tích đều xuất hiện ở đó ngay khi một container restart.

Trung thực khi rollback

Giữ lại file compose v2, cấu hình tĩnh của file này và bản backup acme.json cho đến khi mọi service đều được định tuyến qua v3 và đã được kiểm thử thực tế. Rollback nghĩa là checkout commit trước khi migration rồi chạy docker compose up -d. Phải rollback toàn bộ file, không chỉ đổi image tag, vì cú pháp chỉ có trên v3 sẽ sai khi chạy dưới v2, giống hệt cách cú pháp v2 bị sai dưới v3: matcher PathRegexp sẽ không parse được. Các label ipallowlist đã đổi tên vẫn dùng được trên v2.11, nhưng không dùng được trên bất kỳ bản v2 cũ hơn nào vì các bản đó không nhận diện tên mới. Nếu acme.json bị mất hoặc hỏng trong quá trình này, hãy khôi phục bản backup trước khi khởi động v2. Nhờ đó, rollback không làm tiêu tốn rate limit của Let's Encrypt bằng cách cấp lại 5 certificate cùng lúc.

FAQ

Tôi có phải viết lại mọi router rule cho Traefik v3 không?

Không. Rule Host(app.example.com) thông thường được viết bằng backtick hợp lệ ở cả hai phiên bản và đáp ứng phần lớn thiết lập Compose. Chỉ cần viết lại khi rule sử dụng tính năng chỉ có ở v2: regex hoặc placeholder bên trong Path và PathPrefix, nhiều hostname trong một Host(), hoặc các matcher Headers, HeadersRegexp và HostHeader đã bị loại bỏ.

Điều gì đã xảy ra với ipWhiteList trong Traefik v3?

Nó được đổi tên thành ipAllowList, còn cấu hình bên trong không thay đổi. Vì vậy, một label v2 như traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 sẽ trở thành cùng dòng đó nhưng có ipallowlist. v2.11 đã chấp nhận tên mới, nên bạn có thể đổi tên trước khi upgrade. Các bản phát hành v3 hiện tại, bao gồm v3.7, vẫn chấp nhận tên cũ dưới dạng alias deprecated. Vì vậy, label chưa đổi tên vẫn áp dụng allowlist, chỉ ghi cảnh báo vào log. Hãy xem đây là thời gian tạm thời, không phải lý do để bỏ qua việc đổi tên. Tên deprecated là những tên mà một bản phát hành có thể loại bỏ. Ngược lại, middleware có tên mà Traefik thực sự không biết sẽ fail rõ ràng, kèm router error và 404. Dashboard hiển thị lỗi, còn request đến hostname đó trả về 404.

Traefik v3 còn đọc được cú pháp rule của v2 không?

Có. Đặt core.defaultRuleSyntax: v2 trong static configuration để tiếp tục dùng cú pháp v2 làm mặc định trong khi migrate. Sau khi đổi mặc định trở lại, dùng label ruleSyntax=v2 theo từng router cho các router còn sót lại. Hãy xem cả hai tùy chọn này là tạm thời. Traefik đã đánh dấu chúng là deprecated trong v3.4 và sẽ loại bỏ chúng ở major version tiếp theo.

Chứng chỉ Let's Encrypt của tôi có còn sau khi upgrade không?

Có. Traefik v3 vẫn đọc file acme.json do v2 tạo, nên chứng chỉ không được cấp lại chỉ vì binary đã thay đổi. Tuy vậy, hãy sao chép file này đến một nơi an toàn trước khi bắt đầu. Rollback hoặc volume bị xóa làm mất acme.json sẽ buộc phải cấp lại toàn bộ chứng chỉ cùng lúc. Let's Encrypt chỉ cho phép 5 chứng chỉ trùng lặp mỗi tuần với cùng một tập hostname.

Vì sao Traefik v3 không khởi động sau khi upgrade?

Gần như luôn là vì static configuration vẫn chứa một option đã bị v3 loại bỏ. Traefik từ chối khởi động khi gặp option mà nó không nhận diện. Với các option còn sót lại phổ biến (pilot, providers.docker.swarmMode, experimental.http3 và tls.caOptional của các provider), log sẽ ghi rõ nguyên nhân rồi báo incompatible deprecated install configuration option found (incompatible deprecated static option found trên v3.4 và các phiên bản cũ hơn). Với mọi thứ mà v3 chưa từng biết đến, chẳng hạn typo, log báo field not found kèm node tương ứng. Xóa hoặc thay thế từng option, rồi khởi động lại container.