traefik

Traefik

概要

Traefik(トラフィック)は、クラウドネイティブなリバースプロキシ/エッジルーター。Docker や Kubernetes などのプロバイダから動的に設定を取得し、ルーティング・TLS 終端・ヘルスチェック・ミドルウェア適用などを自動化できる。

TLS 終端とは

TLS 終端(TLS termination)は、エッジ(Traefik などのリバースプロキシ)で TLS を復号して HTTP としてバックエンドに転送する方式。証明書管理と暗号処理をフロントに集約し、バックエンドは平文 HTTP で動作させる。

  • 目的: 証明書の集中管理、CPU 負荷のオフロード、HTTP ルーティング/ミドルウェア活用
  • メリット: 自動 HTTPS(Let’s Encrypt)、HTTP/2/ALPN、セキュリティヘッダや認証などを一括適用
  • 注意点: Traefik→バックエンド間は平文になるため、同一ホスト/プライベートネットワークで隔離、必要に応じて内部 mTLS を検討
  • 代替: TLS パススルー(Traefik では復号せず透過転送)。HTTP ルールやミドルウェアは使えない

設定例(Docker ラベル):

# 例:Traefik で TLS 終端(HTTPS を終端し、内部は HTTP:3000)
labels:
  - traefik.http.routers.web-app.entrypoints=websecure
  - traefik.http.routers.web-app.tls=true
  - traefik.http.routers.web-app.tls.certresolver=le
  - traefik.http.services.web-app.loadbalancer.server.port=3000
# 例:TLS パススルー(TCP ルーター。Traefik は復号しない)
labels:
  - traefik.tcp.routers.secure-svc.rule=HostSNI(`secure.example.com`)
  - traefik.tcp.routers.secure-svc.entrypoints=websecure
  - traefik.tcp.routers.secure-svc.tls.passthrough=true
  - traefik.tcp.services.secure-svc.loadbalancer.server.port=8443

主な特徴

  • 動的構成(プロバイダ): Docker、Kubernetes、File などから自動で設定を反映
  • 自動 HTTPS(Let’s Encrypt): 証明書の取得・更新を自動化
  • 高機能ルーティング: Host/Path/Headers/Method などで柔軟にマッチ
  • ミドルウェア: リダイレクト、Basic 認証、圧縮、RateLimit、IP AllowList、Header 付与など
  • 負荷分散とヘルスチェック、スティッキーセッション
  • 観測性: ダッシュボード、アクセスログ、メトリクス(Prometheus, OTLP)
  • HTTP/2、gRPC、WebSocket、TCP/UDP(DBやMQなど)も対応

コア概念(v2)

  • EntryPoints: Traefik がリッスンするポート(例: web=80, websecure=443)
  • Routers: リクエストのマッチ条件(Host(example.com) など)と適用設定(TLS、Middlewares、Services)
  • Middlewares: ルールに合致したリクエストへ適用(リダイレクト、認証、ヘッダ付与など)
  • Services: バックエンド(アプリ)群への負荷分散設定(port、servers、sticky 等)
  • Providers: 設定の取得元(Docker、Kubernetes、File)。変更を検知して自動反映

Traefikの歴史(ざっくり年表)

  • 2015年: Containous 社が Traefik v1.0 を公開 — コンテナ時代のリバースプロキシ/LBとして登場、Docker/Marathon/K8s 連携を訴求
  • 2016年: Docker Swarm・Kubernetes サポート拡充 — docker.sock を読み取りコンテナ自動検出・ルーティング生成
  • 2017年: v1.3〜v1.7 で機能拡張 — Let’s Encrypt 自動証明書、ACME DNS、カナリア、ヘルスチェックなど
  • 2018年: K8s Ingress Controller として採用増 — v1 系が安定し、Nginxからの移行例が増える
  • 2019年: Traefik v2.0 — ルーター/ミドルウェア/サービスの3層モデル、K8s CRD、TCP/UDPプロキシ対応
  • 2020年: 社名を Containous → Traefik Labs に変更 — 商用版 Traefik Enterprise 提供開始
  • 2021年: v2.x がデファクト化 — Docker/K8s両対応とダイナミック設定が評価
  • 2023年: v3.0 プレリリース — HTTP/3 対応、性能改善、設定簡素化
  • 2024年: v3.0 安定版リリース — セキュリティ強化(例: TLS 1.3 デフォルト化)、プラグインエコシステム拡充

選定への示唆

  • Docker/Kubernetes とネイティブ統合された自動化(検出・再読込不要)
  • ACME/Let’s Encrypt を内蔵し HTTPS 運用コストを大幅削減
  • v2 の柔軟なルーティングとミドルウェアで多様な要件に対応
  • TCP/UDP 対応で gRPC や一部非HTTPプロトコルも取り扱い可能
  • OSS と Enterprise の選択肢があり、規模拡大にも対応

技術選定の考え方

  • 目的とユースケース
    • 複数サービスをDockerで運用し、追加・変更が頻繁 → Traefikが適切(自動検出/自動HTTPS)
    • 単一サービスで構成が固定、細かなL7チューニング(rewrite/map/Lua)や強力なキャッシュが必要 → nginxも有力
  • ルーティングと自動化
    • Dockerラベルでホットリロード不要の自動反映 → Traefik
    • 生成済みnginx.confを配布・明示的に管理 → nginx
  • HTTPS/証明書運用
    • Let’s Encryptの自動取得・更新を簡便に → Traefik
    • 企業CA・HSM・詳細TLSポリシーの厳格管理 → nginxでも可
  • TLS終端 vs パススルー
    • 終端(termination): ミドルウェア(認証/ヘッダ/RateLimit)や詳細HTTPルールが必要。内部はプライベートネットで隔離
    • パススルー(passthrough): エンドツーエンドTLS必須、非HTTP(TCP/gRPCのまま)を透過、下流にWAF/IDPがある
  • 運用規模と基盤
    • 単一ホスト → docker compose + Traefik
    • 複数ホスト/高可用 → Kubernetes(Traefik Ingress/Nginx Ingress)を検討
  • セキュリティの前提
    • docker.sockはdocker-socket-proxy経由、ダッシュボード公開時は認証必須(api.insecure=false)
    • acme.jsonは永続化し0600権限、80/443の開放とDNS設定を整備
    • 公開ネットワークと内部ネットワークを分離(DBは公開しない)
  • リポジトリ/ネットワーク設計
    • インフラ用リポ(例: private-gateway)と各アプリのリポを分離
    • 外部共有ネットワーク(例: proxy-net)を作成し、公開するコンテナだけ参加させTraefikラベル付与
    • DB用リポ(例: private-db-stack)は内部ネットワークのみ接続、ポート公開/Traefikラベルなし
  • 命名規則と運用
    • kebab-caseで統一(services/volumes/middlewares)
    • restart: unless-stopped と healthcheck を併用
    • 監視(アクセスログ/メトリクス)を有効化

導入チェックリスト

  • DNSのA/AAAAをサーバーIPへ、80/443開放
  • acme.jsonをボリューム永続化し0600権限
  • api.insecure=false、ダッシュボードはBasic認証やIP制限
  • proxy-net(外部ネットワーク)を作成、公開が必要なサービスのみ参加
  • 各サービスに正しいHost/Pathルールとloadbalancer.server.port
  • healthcheckとrestart: unless-stopped設定を確認
  • バックアップ対象: acme.json、Traefik設定、Composeファイル

開発環境向け 最小構成(v3.5)

ローカル開発でTraefikを最短で試すための最小セット。ダッシュボードをhttp://localhost:8080で有効化します(開発専用)。

docker-compose.yml(抜粋):

services:
  traefik:
    image: traefik:v3.5
    ports:
      - "80:80"
      - "8080:8080"  # Traefik Dashboard
    volumes:
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro

静的設定ファイル traefik.yml:

api:
  dashboard: true
  insecure: true

entryPoints:
  web:
    address: ":80"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

解説:

  • image: traefik:v3.5 — v3系の安定版を使用
  • ports: 80はHTTP入口、8080はダッシュボード(開発のみ開放)
  • volumes:
    • ./traefik.yml — 静的設定(エントリポイント/ダッシュボード/プロバイダ)
    • /var/run/docker.sock:ro — Dockerプロバイダがコンテナを自動検出(本番はsocket-proxy推奨)
  • api.insecure: true — ダッシュボードを認証なしで公開する開発用フラグ(本番では禁止)
  • entryPoints.web: “:80” — HTTP入口を定義
  • providers.docker.exposedByDefault: false — ラベルで明示したサービスのみ公開(安全側)

アプリを公開する最小ラベル例(開発):

services:
  my-app:
    image: yourorg/app:dev
    labels:
      - traefik.enable=true
      - traefik.http.routers.my-app.entrypoints=web
      - traefik.http.routers.my-app.rule=Host(`app.localhost`)
      - traefik.http.services.my-app.loadbalancer.server.port=3000
  • Host(app.localhost) はローカルで 127.0.0.1 に解決されるため便利
  • アプリ内部のリッスンポート(例:3000)を loadbalancer.server.port に指定

注意(本番との違い):

  • ダッシュボードは insecure: true にしない。HTTPS化と認証で保護
  • Let’s Encrypt などの証明書自動取得は本構成には含めない(本番構成で追加)
  • docker.sock は直接マウントせず、docker-socket-proxy の使用を検討

よく使う構成(Docker Compose)

以下は本番でも使える最小構成例。自動 HTTPS、HTTP→HTTPS リダイレクト、ダッシュボード保護などを含む。

version: '3.8'

services:
  traefik:
    image: traefik:v2.11
    container_name: traefik
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --api.dashboard=true
      - --api.insecure=false               # 公開時は必ず false(ダッシュボードはルーターで保護)
      - --certificatesresolvers.le.acme.email=you@example.com
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.httpchallenge=true
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-letsencrypt:/letsencrypt
    restart: unless-stopped
    labels:
      # ダッシュボードをサブドメインで公開(Basic 認証で保護)
      - traefik.enable=true
      - traefik.http.routers.traefik.rule=Host(`traefik.example.com`)
      - traefik.http.routers.traefik.entrypoints=websecure
      - traefik.http.routers.traefik.tls=true
      - traefik.http.routers.traefik.tls.certresolver=le
      - traefik.http.routers.traefik.service=api@internal
      - traefik.http.routers.traefik.middlewares=traefik-auth
      # Basic 認証(例): 下のハッシュはサンプルです。実運用は自分で生成
      - traefik.http.middlewares.traefik-auth.basicauth.users=admin:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/

  # HTTP → HTTPS リダイレクト用の catch-all ルーター(任意)
  redirect:
    image: traefik:v2.11
    labels:
      - traefik.enable=true
      - traefik.http.routers.http-catchall.entrypoints=web
      - traefik.http.routers.http-catchall.rule=HostRegexp(`{any:.+}`)
      - traefik.http.routers.http-catchall.middlewares=redirect-to-https
      - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
    deploy:
      replicas: 0 # Traefik サービスに内包させる運用も可(ここは例示のため)

  web-app:
    image: yourorg/yourapp:latest
    depends_on:
      - traefik
    expose:
      - "3000"
    restart: unless-stopped
    labels:
      - traefik.enable=true
      # ルーティング
      - traefik.http.routers.web-app.rule=Host(`example.com`)
      - traefik.http.routers.web-app.entrypoints=websecure
      - traefik.http.routers.web-app.tls=true
      - traefik.http.routers.web-app.tls.certresolver=le
      # バックエンド Service のポート指定
      - traefik.http.services.web-app.loadbalancer.server.port=3000
      # 代表的なミドルウェア(圧縮、セキュアヘッダ)
      - traefik.http.routers.web-app.middlewares=web-app-compress,web-app-sec-headers
      - traefik.http.middlewares.web-app-compress.compress=true
      - traefik.http.middlewares.web-app-sec-headers.headers.stsSeconds=31536000
      - traefik.http.middlewares.web-app-sec-headers.headers.stsIncludeSubdomains=true
      - traefik.http.middlewares.web-app-sec-headers.headers.forceSTSHeader=true
      - traefik.http.middlewares.web-app-sec-headers.headers.frameDeny=true

volumes:
  traefik-letsencrypt:

ヒント:

  • Basic 認証のハッシュは htpasswd で生成(例: htpasswd -nb admin 'your-password'
  • acme.json は 600 権限にして永続化すること(Let’s Encrypt レート制限の回避にも重要)
  • providers.docker.exposedbydefault=false により、明示的に traefik.enable=true のものだけ公開
  • DNS の A/AAAA レコードを正しい IP に向ける(HTTP-01 チャレンジには 80 番が必要)

代表的なミドルウェア

  • redirectScheme: HTTP→HTTPS などプロトコル変換
  • basicAuth / forwardAuth: 認証
  • rateLimit: レート制限
  • headers: セキュリティヘッダ追加(HSTS、X-Frame-Options 等)
  • stripPrefix / addPrefix: パス調整
  • compress: レスポンス圧縮

ベストプラクティス

  • ダッシュボードは公開しないか、必ず認証で保護(api.insecure=false
  • 証明書ストレージ(acme.json)はボリュームで永続化し、権限 600
  • プロジェクト全体でケバブケース命名(services、volumes、middlewares など)
  • restart: unless-stopped とヘルスチェックを併用して可用性を確保
  • ルールはできるだけ具体的に(Host と Path を併用し誤ルーティングを防止)
  • アクセスログとメトリクスを有効化して監視(Prometheus, Loki, OTLP など)

トラブルシューティング

  • 404 はルーター未一致の可能性(rule/entrypoints/Host の綴り・DNS を確認)
  • 502/504 はバックエンド未起動やポート不一致(loadbalancer.server.port
  • 証明書発行失敗は 80 番ポート到達性やレート制限、ドメイン設定を確認
  • whoami テスト: traefik/whoami をデプロイしてルーティング動作確認
  • ログレベルを上げて原因調査(--log.level=DEBUG

参考リンク