Traefik: обратный прокси для Docker без головной боли

Настройка обратного прокси в Docker-окружении - задача, с которой рано или поздно сталкивается каждый, кто запускает больше одного сервиса на сервере. Классический подход: Nginx с ручным редактированием конфигов, перезагрузка после каждого изменения, отдельный Certbot для сертификатов. Это работает, но когда контейнеров становится десятки, а деплои происходят несколько раз в день - ручное управление конфигами превращается в источник ошибок и потерянного времени.

Traefik решает эту проблему через автообнаружение сервисов. Вместо того чтобы писать конфиг под каждый контейнер, достаточно добавить несколько лейблов в docker-compose.yml - и Traefik сам настроит маршрутизацию, получит TLS-сертификат и начнёт проксировать трафик. Остановил контейнер - маршрут исчез автоматически. Запустил новый - появился без перезагрузки прокси. Это не маркетинговый тезис, а буквальное описание того, как это работает.

В этой статье разберём Traefik v3 (актуальная версия на 2026 год) с нуля: архитектуру, установку, подключение реальных сервисов (WordPress, FastAPI, Portainer), настройку middleware, автоматические сертификаты Let's Encrypt, балансировку нагрузки и мониторинг. Плюс честное сравнение с Nginx и Caddy - со случаями, когда Traefik не лучший выбор.

Что такое Traefik и зачем он нужен

Traefik - это облачно-нативный обратный прокси и балансировщик нагрузки, написанный на Go компанией Traefik Labs. Первая версия вышла в 2016 году; актуальная стабильная версия - v3.3 (февраль 2026). Основное отличие от классических прокси - встроенный Service Discovery: Traefik умеет читать метаданные контейнеров Docker, подов Kubernetes, сервисов Consul и других оркестраторов, автоматически строить конфигурацию маршрутизации и обновлять её без перезапуска.

Ключевые возможности Traefik v3:

  • Автообнаружение через провайдеры: Docker, Docker Swarm, Kubernetes (CRD и Ingress), файловый провайдер, Consul, etcd
  • Автоматические TLS-сертификаты через Let's Encrypt (ACME) с поддержкой HTTP-01, DNS-01 и TLS-ALPN-01 challenge
  • Встроенный dashboard с реальным состоянием маршрутов
  • Middleware-пайплайн: аутентификация, rate limiting, заголовки, редиректы, circuit breaker
  • Маршрутизация TCP и UDP (не только HTTP)
  • Нативная поддержка HTTP/2 и HTTP/3 (QUIC)
  • Метрики для Prometheus, трассировки для Jaeger/Zipkin/OTLP
  • Plugin-система для расширения функциональности

Когда Traefik реально полезен: микросервисная архитектура с динамическим составом сервисов, CI/CD окружения где контейнеры поднимаются и падают автоматически, мультиарендные платформы. Когда он избыточен: один статический сайт на сервере, конфигурация которого меняется раз в месяц - там хватит Nginx за пять минут.

Как Traefik отличается от Nginx и Caddy

Все три инструмента решают задачу обратного проксирования, но с принципиально разными философиями. Nginx - статическая конфигурация, максимальная гибкость, высокая производительность. Caddy - автоматический HTTPS по умолчанию, простой синтаксис. Traefik - динамическое обнаружение, нативная интеграция с Docker и Kubernetes.

Критерий Traefik v3 Nginx Caddy v2
Конфигурация DockerЛейблы в docker-compose.yml, автообнаружениеРучной nginx.conf или nginx-proxy образРучной Caddyfile или API
Авто-TLS (Let's Encrypt)Встроено, настраивается через лейблыЧерез Certbot + cron + reloadВстроено, автоматически для любого домена
Перезагрузка при измененияхНе нужна, hot reloadНужна (nginx -s reload)Не нужна через API
ПроизводительностьВысокая, но выше latency чем NginxМаксимальная, эталонСопоставима с Traefik
Потребление памяти~50-80 MB в покое~10-30 MB в покое~30-60 MB в покое
Kubernetes IngressНативная поддержка CRDЧерез nginx-ingress controllerЧерез Gateway API (экспериментально)
TCP/UDP маршрутизацияВстроенаЧерез stream блокОграничена
Dashboard/UIВстроенНет (только /stub_status)Нет
Middleware экосистемаБогатая, + плагиныЧерез модули (часто требует компиляции)Встроенные директивы
Когда выбиратьDocker/K8s с динамическими сервисамиВысокие нагрузки, статические конфиги, legacyПростые сценарии с авто-HTTPS без Docker

Важный момент по производительности: в большинстве реальных сценариев разница между Traefik и Nginx незаметна до 10 000+ RPS на один инстанс. При высоких нагрузках (50 000+ RPS) Nginx действительно выигрывает за счёт event-driven архитектуры и минимальных накладных расходов.

Архитектура Traefik: EntryPoints, Routers, Services, Middleware

Traefik обрабатывает трафик через четыре концепции. Разберём их по порядку - от входящего запроса до бэкенда.

EntryPoints - точки входа: сетевые порты, на которых Traefik слушает трафик. Обычно порт 80 (HTTP) и 443 (HTTPS).

Routers - маршрутизаторы. Каждый определяет правило: какие запросы он обрабатывает. Правила пишутся на DSL: Host(`example.com`), PathPrefix(`/api`), Host(`app.com`) && PathPrefix(`/v2`).

Services - описание бэкенда: один или несколько серверов, алгоритм балансировки, параметры health check. Для Docker-контейнера Traefik создаёт Service автоматически.

Middleware - цепочка преобразований запроса/ответа между роутером и сервисом. Примеры: BasicAuth, RateLimit, Headers, RedirectScheme, StripPrefix.

Схема прохождения запроса:

Клиент
  |
EntryPoint (:443, HTTPS)
  |
Router (правило: Host(`app.example.com`))
  |
Middleware цепочка (auth -> rate-limit -> security-headers)
  |
Service (load balancer -> backend контейнеры)
  |
Ваш контейнер (:8080)

Конфигурация делится на два уровня:

  • Статическая - загружается при старте, не меняется на ходу. Содержит EntryPoints, провайдеры, настройки ACME. Задаётся через traefik.yml.
  • Динамическая - меняется без перезапуска. Содержит Routers, Services, Middleware. Поступает от провайдеров (Docker лейблы, файловый провайдер).

Установка Traefik через Docker Compose

Минимальная рабочая конфигурация Traefik v3 для production-окружения. Предполагается домен с A-записью, указывающей на IP сервера.

mkdir -p /opt/traefik/data
cd /opt/traefik
touch data/acme.json
chmod 600 data/acme.json

Файл статической конфигурации /opt/traefik/data/traefik.yml:

api:
  dashboard: true
  insecure: false

log:
  level: INFO
  format: json

accessLog:
  format: json

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt
    http3:
      advertisedPort: 443

certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@example.com
      storage: /data/acme.json
      httpChallenge:
        entryPoint: web

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: traefik-public
  file:
    filename: /data/dynamic.yml
    watch: true

metrics:
  prometheus:
    addEntryPointsLabels: true
    addServicesLabels: true

Файл /opt/traefik/docker-compose.yml:

services:
  traefik:
    image: traefik:v3.3
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    ports:
      - "80:80"
      - "443:443/tcp"
      - "443:443/udp"
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/acme.json:/data/acme.json
      - ./data/dynamic.yml:/data/dynamic.yml:ro
    networks:
      - traefik-public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
      - "traefik.http.routers.traefik-dashboard.service=api@internal"
      - "traefik.http.routers.traefik-dashboard.middlewares=dashboard-auth"
      - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$xyz$$hashedpassword"

networks:
  traefik-public:
    external: true
docker network create traefik-public
docker compose up -d
docker compose logs -f traefik

Обратите внимание: exposedByDefault: false - важная настройка безопасности. Контейнер становится доступным только если у него есть лейбл traefik.enable=true.

Подключение сервисов через лейблы

Разберём три реальных примера подключения сервисов.

WordPress

services:
  wordpress:
    image: wordpress:6.7-php8.3-apache
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: secretpassword
    volumes:
      - wp_data:/var/www/html
    networks:
      - traefik-public
      - internal
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wordpress.rule=Host(`blog.example.com`)"
      - "traefik.http.routers.wordpress.entrypoints=websecure"
      - "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
      - "traefik.http.services.wordpress.loadbalancer.server.port=80"
      - "traefik.http.routers.wordpress.middlewares=security-headers@file"

  db:
    image: mariadb:11.4
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: secretpassword
      MYSQL_ROOT_PASSWORD: rootpassword
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - internal

volumes:
  wp_data:
  db_data:

networks:
  traefik-public:
    external: true
  internal:
    internal: true

FastAPI приложение

services:
  fastapi-app:
    image: myapp:latest
    restart: unless-stopped
    networks:
      - traefik-public
      - internal
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.fastapi.rule=Host(`api.example.com`)"
      - "traefik.http.routers.fastapi.entrypoints=websecure"
      - "traefik.http.routers.fastapi.tls.certresolver=letsencrypt"
      - "traefik.http.services.fastapi.loadbalancer.server.port=8000"
      - "traefik.http.routers.fastapi.middlewares=api-rate-limit@docker,security-headers@file"
      - "traefik.http.middlewares.api-rate-limit.ratelimit.average=100"
      - "traefik.http.middlewares.api-rate-limit.ratelimit.burst=200"
      - "traefik.http.middlewares.api-rate-limit.ratelimit.period=1m"

Portainer

services:
  portainer:
    image: portainer/portainer-ce:2.21.5
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - portainer_data:/data
    networks:
      - traefik-public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.rule=Host(`portainer.example.com`)"
      - "traefik.http.routers.portainer.entrypoints=websecure"
      - "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"

volumes:
  portainer_data:

networks:
  traefik-public:
    external: true

Важные правила при работе с лейблами:

  • Имена роутеров, сервисов и middleware должны быть уникальными в пределах всего Traefik-инстанса.
  • Лейбл traefik.http.services.NAME.loadbalancer.server.port нужен, если контейнер слушает не на стандартном порту.
  • При нескольких сетях в контейнере укажите явно: traefik.docker.network=traefik-public.
  • Символ $ в лейблах (в BasicAuth хеше) экранируется как $$ в docker-compose.yml.

Middleware: аутентификация, rate limiting, заголовки безопасности

BasicAuth

apt install apache2-utils
htpasswd -nb admin mypassword
# Вывод: admin:$apr1$xyz$somehashedvalue

# Или через Docker
docker run --rm httpd:alpine htpasswd -nb admin mypassword

Определение middleware в файловом провайдере dynamic.yml:

http:
  middlewares:
    basic-auth:
      basicAuth:
        users:
          - "admin:$apr1$xyz$somehashedvalue"
        removeHeader: true

Rate Limiting

http:
  middlewares:
    rate-limit-strict:
      rateLimit:
        average: 50
        burst: 100
        period: 1m
        sourceCriterion:
          ipStrategy:
            depth: 1

    rate-limit-standard:
      rateLimit:
        average: 200
        burst: 400
        period: 1m

Заголовки безопасности

http:
  middlewares:
    security-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        frameDeny: true
        contentTypeNosniff: true
        browserXssFilter: true
        referrerPolicy: "strict-origin-when-cross-origin"
        customResponseHeaders:
          X-Powered-By: ""
          Server: ""

    compression:
      compress:
        minResponseBodyBytes: 1024

Применение нескольких middleware через запятую:

labels:
  - "traefik.http.routers.myapp.middlewares=security-headers@file,rate-limit-standard@file,basic-auth@file"

Суффикс @file означает, что middleware определён в файловом провайдере. @docker - в лейблах Docker.

TLS и автоматические сертификаты Let's Encrypt

Traefik поддерживает три ACME challenge:

  • HTTP-01 - самый простой. Требует открытый порт 80. Не работает для wildcard.
  • TLS-ALPN-01 - проверка через порт 443. Полезно, если 80 закрыт.
  • DNS-01 - единственный способ для wildcard (*.example.com). Требует интеграцию с DNS-провайдером.

Конфигурация нескольких резолверов в traefik.yml:

certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@example.com
      storage: /data/acme.json
      httpChallenge:
        entryPoint: web

  letsencrypt-dns:
    acme:
      email: admin@example.com
      storage: /data/acme-dns.json
      dnsChallenge:
        provider: cloudflare
        delayBeforeCheck: 30
        resolvers:
          - "1.1.1.1:53"

  letsencrypt-staging:
    acme:
      email: admin@example.com
      storage: /data/acme-staging.json
      caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
      httpChallenge:
        entryPoint: web

Для DNS-01 через Cloudflare - переменные окружения в compose:

environment:
  - CF_API_EMAIL=admin@example.com
  - CF_DNS_API_TOKEN=your_cloudflare_api_token

Wildcard-сертификат в лейблах:

labels:
  - "traefik.http.routers.myapp.tls.certresolver=letsencrypt-dns"
  - "traefik.http.routers.myapp.tls.domains[0].main=example.com"
  - "traefik.http.routers.myapp.tls.domains[0].sans=*.example.com"

Важные детали: файл acme.json должен иметь права 600. Используйте staging-резолвер при отладке - Let's Encrypt ограничивает до 5 дублирующих сертификатов в неделю на домен. Traefik автоматически обновляет сертификаты за 30 дней до истечения.

Минимальная версия TLS и наборы шифров:

tls:
  options:
    modern:
      minVersion: VersionTLS13
    intermediate:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

Статическая конфигурация через файлы YAML

Файловый провайдер позволяет описывать роутеры и сервисы в YAML вместо лейблов. Это удобно для внешних серверов (вне Docker) или переиспользуемых middleware.

Пример dynamic.yml с маршрутизацией к внешним серверам и TCP:

http:
  routers:
    legacy-app:
      rule: "Host(`legacy.example.com`)"
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers
      service: legacy-backend

  services:
    legacy-backend:
      loadBalancer:
        servers:
          - url: "http://192.168.1.50:8080"
        healthCheck:
          path: /health
          interval: 30s
          timeout: 5s

    grpc-backend:
      loadBalancer:
        servers:
          - url: "h2c://grpc-service:50051"

tcp:
  routers:
    postgres:
      rule: "HostSNI(`postgres.example.com`)"
      entryPoints:
        - postgres-entry
      tls:
        passthrough: true
      service: postgres-service

  services:
    postgres-service:
      loadBalancer:
        servers:
          - address: "postgres-container:5432"

TCP EntryPoint добавить в статическую конфигурацию:

entryPoints:
  postgres-entry:
    address: ":5432"

При watch: true Traefik перечитывает файл на лету без перезапуска.

Балансировка нагрузки и health check

Балансировка между несколькими репликами в Docker Compose:

services:
  webapp:
    image: mywebapp:latest
    deploy:
      replicas: 3
    networks:
      - traefik-public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.webapp.entrypoints=websecure"
      - "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.webapp.loadbalancer.server.port=8000"
      - "traefik.http.services.webapp.loadbalancer.sticky.cookie=true"
      - "traefik.http.services.webapp.loadbalancer.sticky.cookie.name=lb_session"
      - "traefik.http.services.webapp.loadbalancer.sticky.cookie.secure=true"
      - "traefik.http.services.webapp.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.webapp.loadbalancer.healthcheck.interval=10s"
      - "traefik.http.services.webapp.loadbalancer.healthcheck.timeout=3s"

Circuit breaker - автоматическое отключение нездорового бэкенда:

http:
  middlewares:
    circuit-breaker:
      circuitBreaker:
        expression: "ResponseCodeRatio(500, 600, 0, 600) > 0.30 || NetworkErrorRatio() > 0.10"
        checkPeriod: 10s
        fallbackDuration: 30s
        recoveryDuration: 10s

Это выражение открывает circuit breaker, если более 30% ответов - 5xx ошибки, или более 10% - сетевые ошибки. После открытия - 30 секунд возврата ошибки клиенту, затем 10 секунд на восстановление.

Мониторинг и dashboard

Traefik предоставляет три уровня наблюдаемости: встроенный dashboard, метрики для Prometheus и структурированные логи.

Dashboard показывает в реальном времени: все активные роутеры, сервисы и их health, middleware цепочки, сертификаты TLS и срок их действия. Доступен по домену из лейблов.

Ключевые метрики Prometheus:

  • traefik_entrypoint_requests_total - общее число запросов по entrypoint
  • traefik_service_requests_total - запросы по сервисам с кодами ответа
  • traefik_service_request_duration_seconds - задержки (histogram)
  • traefik_service_server_up - состояние бэкенда (0/1)
  • traefik_tls_certs_not_after - срок истечения сертификатов

Полный стек мониторинга (Prometheus + Grafana):

services:
  prometheus:
    image: prom/prometheus:v3.1.0
    restart: unless-stopped
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.retention.time=15d"
    networks:
      - traefik-public
      - monitoring
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.prometheus.rule=Host(`prometheus.example.com`)"
      - "traefik.http.routers.prometheus.entrypoints=websecure"
      - "traefik.http.routers.prometheus.tls.certresolver=letsencrypt"
      - "traefik.http.routers.prometheus.middlewares=basic-auth@file"

  grafana:
    image: grafana/grafana:11.4.0
    restart: unless-stopped
    environment:
      GF_SECURITY_ADMIN_PASSWORD: changeme
      GF_USERS_ALLOW_SIGN_UP: "false"
    volumes:
      - grafana_data:/var/lib/grafana
    networks:
      - traefik-public
      - monitoring
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.grafana.rule=Host(`grafana.example.com`)"
      - "traefik.http.routers.grafana.entrypoints=websecure"
      - "traefik.http.routers.grafana.tls.certresolver=letsencrypt"

volumes:
  prometheus_data:
  grafana_data:

networks:
  monitoring:
    internal: true

Готовый Grafana дашборд для Traefik - ID 12250 (Traefik 2 for Docker) или ID 17346 (Traefik Official). Импорт: Dashboards - Import - введите ID.

OpenTelemetry трассировка в Traefik v3:

tracing:
  otlp:
    grpc:
      endpoint: "jaeger:4317"
      insecure: true
  sampleRate: 0.1

Типичные ошибки и troubleshooting

СимптомВероятная причинаРешение
404 от TraefikНет лейбла traefik.enable=true или контейнер не в сети traefik-publicdocker inspect CONTAINER | grep Networks
502 Bad GatewayНеверный порт в лейблах или приложение не запущеноПроверить loadbalancer.server.port, docker logs CONTAINER
Сертификат не получаетсяДомен не ведёт на IP сервера, порт 80 закрыт, rate limitdig A domain.com, открыть порт 80, использовать staging
Самоподписанный сертификатНе указан tls.certresolverДобавить traefik.http.routers.NAME.tls.certresolver=letsencrypt
acme.json permission deniedНеверные права на файлchmod 600 /opt/traefik/data/acme.json
Middleware не применяетсяНеверный суффикс (@docker/@file), опечатка в имениПроверить dashboard, включить log.level: DEBUG
Бесконечный редиректПриложение само делает редирект или не понимает X-Forwarded-ProtoДобавить customRequestHeaders: X-Forwarded-Proto: https
Конфликт имён роутеровДва контейнера с одинаковым именем роутераTraefik логирует "duplicate router name" - исправить уникальность

Полезные команды для диагностики:

# Состояние роутеров через API
curl http://localhost:8080/api/http/routers | jq .

# Конкретный роутер
curl http://localhost:8080/api/http/routers/myapp@docker | jq .

# Все сервисы
curl http://localhost:8080/api/http/services | jq .

# Логи с фильтрацией ошибок
docker logs traefik -f 2>&1 | grep -i "error\|warn\|acme"

# Сеть и лейблы контейнера
docker inspect webapp | jq '.[0].NetworkSettings.Networks'
docker inspect webapp | jq '.[0].Config.Labels'

FAQ

Можно ли использовать Traefik без Docker, для обычных процессов на сервере?

Да. Файловый провайдер позволяет описывать бэкенды как статические URL: url: "http://127.0.0.1:3000". Traefik проксирует к ним трафик и выдаёт TLS-сертификаты так же, как для Docker-контейнеров. Удобно при миграции, когда часть сервисов уже в контейнерах.

Как Traefik v3 отличается от v2?

Основные изменения: нативная поддержка HTTP/3 без экспериментальных флагов, переход с Jaeger/Zipkin на OTLP для трассировки, новый синтаксис правил маршрутизации (совместимость сохранена), улучшенная поддержка Kubernetes Gateway API. Миграция с v2 на v3 в большинстве случаев - только обновление образа и проверка deprecated-параметров по официальному migration guide.

Что делать при нескольких инстансах Traefik для высокой доступности?

При нескольких инстансах каждый независимо запрашивает сертификаты у Let's Encrypt, что быстро приводит к превышению rate limit. Решение - централизованное хранилище: Redis или общий NFS-том для acme.json. В Traefik v3 Redis поддерживается как хранилище ACME через acme.storage: "redis://...".

Traefik умеет проксировать TCP без TLS (MySQL, Redis)?

Да. TCP-роутер с HostSNI(`*`) перехватывает весь TCP-трафик на EntryPoint. Без SNI нельзя маршрутизировать по имени хоста - только по порту. Для каждого TCP-сервиса без TLS выделяют отдельный порт в EntryPoints.

Насколько безопасно монтировать Docker socket в Traefik?

Монтирование /var/run/docker.sock даёт Traefik root-эквивалентный доступ к хосту. Снизить риск: использовать socket proxy (Tecnativa Docker Socket Proxy), ограничивающий API-вызовы только на чтение; запускать с no-new-privileges:true; в production рассмотреть Kubernetes, где Traefik работает без прямого доступа к socket.

Как отладить правило маршрутизации, которое не срабатывает?

Первый шаг - открыть dashboard и найти роутер. Нет роутера - проблема в провайдере (лейблы не читаются). Роутер есть, статус красный - проблема в сервисе или health check. Включите log.level: DEBUG и выполните тестовый запрос - в логах будет точная информация о том, какое правило сработало.

Заключение

Traefik v3 - зрелый инструмент, который за 10 лет прошёл путь от эксперимента до де-факто стандарта для обратного проксирования в Docker-окружениях. Автообнаружение сервисов, встроенный ACME, горячая перезагрузка конфигурации и богатая система middleware решают 90% задач без ручного написания конфигов.

Главные сильные стороны: нулевые операционные затраты на добавление нового сервиса (только лейблы в compose-файле), автоматическое управление сертификатами, прозрачность через dashboard и метрики. Слабые стороны: выше порог вхождения по сравнению с Nginx для простых сценариев, Docker socket создаёт поверхность атаки, при нагрузках выше 50k RPS стоит тестировать производительность.

Если вы запускаете несколько сервисов в Docker и тратите время на ручное управление Nginx-конфигами - Traefik окупит время на изучение за первые же несколько деплоев. Если же у вас один статический сайт или требования к производительности на уровне 100k+ RPS - оставайтесь на Nginx.

Хотите попробовать на изолированном сервере без риска для production? Подойдёт VPS с NVMe и KVM - поднять тестовое окружение с нуля займёт 15 минут.