Contents
1️⃣ Docker Compose による Traefik 基本構成
このセクションでは、Traefik コンテナ本体と必須ボリューム・ネットワークを定義した docker-compose.yml を作成します。
Docker ソケットのマウントや環境変数の取り込み方法に注意しながら、最小限の設定で起動できる形にまとめました。
1.1 docker‑compose.yml の全体像
以下は完成形です。各項目の意味は後述しますが、一読すれば 「このファイルだけで起動できる」 ことが分かります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
version: "3.9" services: traefik: image: traefik:v3 # 執筆時点の最新安定版イメージ container_name: traefik command: - --configFile=/etc/traefik/traefik.yml ports: - "80:80" - "443:443" - "8080:8080" # ダッシュボード(HTTPS 経由でアクセス) volumes: - ./traefik.yml:/etc/traefik/traefik.yml:ro - ./dynamic.yml:/etc/traefik/dynamic.yml:ro - ./acme.json:/acme.json # Docker ソケットは読み取り専用でマウントし、最小権限化のために `docker-proxy` を使用する例も示します - /var/run/docker.sock:/var/run/docker.sock:ro env_file: - .env # ここで .env の変数を自動的に注入 environment: TZ: Asia/Tokyo networks: - web restart: unless-stopped networks: web: external: true # 事前に作成した外部ネットワークを使用 |
補足ポイント
- Docker ソケットは
ro(読み取り専用)でマウントし、Traefik が Docker API を参照できるだけの権限に留めます。さらに安全にしたい場合は、docker-proxy や Docker Engine の Remote API(TLS 認証付き)を利用し、ソケット自体をコンテナに渡さない構成も検討してください。 env_file:を追加することで、.envに書いた環境変数がすべて自動的にコンテナへ注入されます。個別にenvironment:で列挙する必要はありません。
1.2 必要な外部ネットワークの作成
docker-compose.yml では external: true としているため、デプロイ前に手動でネットワークを作成します。以下のコマンドを実行してください。
|
1 2 |
docker network create web |
このネットワークは他のアプリケーションコンテナ(例:whoami, nginx など)と共有し、Traefik が自動的に検出できるようにします。
2️⃣ 静的設定ファイル traefik.yml の作成
このセクションでは Traefik 本体の エントリポイント、Docker プロバイダー、API ダッシュボード を定義し、Basic 認証による保護方法を示します。
設定はすべて YAML の構文チェック が通る形で記述しているので、そのまま配置できます。
2.1 基本的なエントリポイントとプロバイダー
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
entryPoints: http: address: ":80" http: redirections: entryPoint: to: https scheme: https https: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false # 明示的にラベル付与したコンテナだけを公開 |
- HTTP → HTTPS のリダイレクトは
entryPoints.http.redirectionsによって自動化されます。 exposedByDefault: falseにすることで、意図しないコンテナが外部に露出するリスクを低減できます。
2.2 ダッシュボードと Basic 認証の設定
|
1 2 3 4 5 6 7 8 9 10 11 |
api: dashboard: true insecure: false # HTTPS 経由のみ許可 http: middlewares: auth-basic: basicAuth: users: - "admin:$apr1$Z3J6eW9L$YjA2cC1XvK5g1G0F6h4zH0" # bcrypt ではなく Apache の MD5 ハッシュ例 |
Basic 認証ハッシュの完全サンプルと生成方法
- 上記は
admin / password123をhtpasswd -nbB admin password123で生成したハッシュです(実際には Bcrypt が推奨されます)。 - 完全なコマンド例:
|
1 2 3 |
# Bcrypt 推奨(Traefik は bcrypt に対応) htpasswd -nbB admin MyStrongPassword | sed 's/\\$/$/g' |
- 生成された文字列を
users:配列に貼り付ければ、ダッシュボードへのアクセスは認証が必須になります。 - ハッシュは 機密情報なので、別ファイル(例:
auth.htpasswd)に保存し、traefik.ymlからfile:で参照する方法もあります。
3️⃣ ACME リゾルバの設定(証明書自動取得)
Let’s Encrypt の証明書を取得するための ACME リゾルバ を static 設定に組み込みます。ここでは HTTP‑01 と DNS‑01(Cloudflare/Route53) の2パターンを提示し、環境変数管理のベストプラクティスも併せて解説します。
3.1 HTTP‑01(シンプル構成)
|
1 2 3 4 5 6 7 8 |
certificatesResolvers: httpResolver: acme: email: your@email.com storage: /acme.json httpChallenge: entryPoint: http |
storageに永続化したacme.jsonを指定し、取得した証明書情報をファイルに保存します。- この構成だけで、A レコードが正しく指向しているドメインは自動的に証明書が発行されます。
3.2 DNS‑01(Cloudflare)
.env に API トークンを格納
|
1 2 3 |
# .env (リポジトリには commit しないこと) CF_API_TOKEN=xxxxxxxxxxxxxxxxxxxxxxx |
traefik.yml 側の設定
|
1 2 3 4 5 6 7 8 9 |
certificatesResolvers: cfResolver: acme: email: your@email.com storage: /acme.json dnsChallenge: provider: cloudflare # CF_API_TOKEN はコンテナ起動時に自動で読み込まれる |
3.3 DNS‑01(Route53)
.env の例
|
1 2 3 4 |
AWS_ACCESS_KEY_ID=YOURKEYID AWS_SECRET_ACCESS_KEY=YOURSECRET AWS_DEFAULT_REGION=ap-northeast-1 |
traefik.yml 側の設定
|
1 2 3 4 5 6 7 8 9 |
certificatesResolvers: route53Resolver: acme: email: your@email.com storage: /acme.json dnsChallenge: provider: route53 # AWS 系環境変数は公式ドライバが自動で取得 |
.env の読み込みについて
docker-compose.yml に env_file: を記述したので、Compose 起動時に上記 .env が自動的にコンテナへ注入されます。
重要ポイント:.env は必ず .gitignore に追加し、機密情報がリポジトリに流出しないよう管理してください。
4️⃣ 動的設定ファイル dynamic.yml と TLS の自動適用
静的設定でリゾルバを定義したら、実際のサービス(例:whoami)へ router / service / tls を紐付けます。
ここではシンプルな例と、ワイルドカード証明書取得時の設定方法を示します。
4.1 基本的な router/service 設定
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
http: routers: whoami-router: entryPoints: - https rule: "Host(`whoami.example.com`)" service: whoami-service tls: certResolver: httpResolver # HTTP‑01 を使用 services: whoami-service: loadBalancer: servers: - url: "http://whoami:80" |
certResolverに先ほど定義したリゾルバ名(httpResolver,cfResolverなど)を指定すると、Traefik が自動的に証明書取得・更新を行います。
4.2 ワイルドカード取得時の DNS‑01 設定例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
http: routers: wildcard-router: entryPoints: - https rule: "Host(`sub.example.com`) || Host(`api.example.com`)" service: dummy-service tls: certResolver: cfResolver # Cloudflare DNS‑01 services: dummy-service: loadBalancer: servers: - url: "http://dummy:80" |
- この router が最初にリクエストを受けると、Traefik は Cloudflare に
_acme-challenge.example.comの TXT レコードを作成し、検証が通ればワイルドカード証明書がacme.jsonに保存されます。
5️⃣ セキュリティ強化・運用上の注意点
以下では実装時に見落としがちだが重要なポイントをまとめます。「やってはいけない」ことと 推奨手順 を対比させて記載しています。
5.1 Docker ソケットの最小権限化
| 手法 | 説明 | メリット |
|---|---|---|
ro マウント + exposedByDefault: false |
コンテナは読み取り専用で API にアクセスでき、かつ自動公開が無効化される | 攻撃面を最小限に抑えられる |
| Docker Remote API (TLS) を使用 | ホスト側で TLS 認証付きポート(例:2376)を公開し、Traefik がそれへ接続 | ソケット自体を共有しないので、権限分離が明確になる |
docker-proxy コンテナ経由 |
中間プロキシが限定的な API コマンドだけを許可 | 必要最小限の機能だけを提供できる |
推奨:まずは
roマウントで運用し、要件に応じて Remote API へ移行してください。
5.2 Basic 認証ハッシュの完全サンプル
|
1 2 3 4 5 |
# Bcrypt (12 cost) 推奨例 htpasswd -nbB admin SuperSecret123 | sed 's/\\$/$/g' # 出力例: admin:$2y$12$K9vJrYpG6h5Z1u7VbqM4eO6E7dFjzX8Qk9lH0nR2tU3vW5xYzAa5a |
この文字列を traefik.yml の users: 配列に貼り付ければ、完全なハッシュが利用できます。
※ MD5 系 ($apr1$) でも動作しますが、セキュリティ上は Bcrypt が推奨されます。
5.3 acme.json の権限自動設定
acme.json は Traefik のみが読み書きできるように 600 にしておく必要があります。
以下の エントリポイントスクリプトを作成し、Compose の command: で実行させます。
entrypoint.sh
|
1 2 3 4 5 6 7 8 9 10 11 |
#!/usr/bin/env sh # 起動前に acme.json の権限を確保 if [ -f /acme.json ]; then chmod 600 /acme.json else touch /acme.json && chmod 600 /acme.json fi # Traefik 本体を起動 exec traefik "$@" |
Docker Compose 側の変更点
|
1 2 3 4 5 6 7 |
services: traefik: # ... 既存設定はそのまま entrypoint: ["/entrypoint.sh"] volumes: - ./entrypoint.sh:/entrypoint.sh:ro # スクリプトをマウント |
このスクリプトにより、コンテナ起動時に自動で権限が設定されるため 手動作業が不要 になります。
5.4 acme.json のバックアップ戦略
| 手順 | 内容 |
|---|---|
| 定期コピー | cp /acme.json /backup/acme-$(date +%F).json を cron(例:毎日 02:00)で実行 |
| リモート保存 | aws s3 cp ... や rclone sync でオフサイトへ転送 |
| ローテーション | find /backup -type f -mtime +30 -delete にて 30 日超過分を削除 |
ポイント:バックアップも同様に
600権限で保管し、アクセス制御を徹底してください。
5.5 ダッシュボードへの IP 制限(任意)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
http: middlewares: ip-whitelist: ipWhiteList: sourceRange: - "203.0.113.0/24" # 管理者が利用するネットワークだけ許可 # router に適用例 routers: api-dashboard: entryPoints: [https] rule: "Host(`monitor.example.com`)" service: api@internal middlewares: [auth-basic, ip-whitelist] |
ipWhiteListミドルウェアで管理者 IP のみアクセス可能にし、認証情報が漏れてもリスクを限定できます。
6️⃣ トラブルシューティングとベストプラクティスまとめ
6.1 よくあるエラーと対処法
| エラーメッセージ | 主な原因 | 確認ポイント |
|---|---|---|
cannot fetch ACME directory |
ネットワーク遮断・プロキシ未設定 | ホストから外部へ curl https://acme-v02.api.letsencrypt.org/directory が成功するか |
dns-01 challenge failed |
API トークン権限不足、環境変数未読込 | .env のキーが正しいか、Traefik コンテナ内で printenv CF_API_TOKEN できるか |
http-01 challenge not reachable |
ポート 80 が閉じている、リダイレクトループ | セキュリティグループ・ファイアウォール設定を確認し、curl -I http://yourdomain/.well-known/acme-challenge/... が取得できるか |
permission denied on /acme.json |
権限 600 が付与されていない | エントリポイントスクリプトが実行されたか、docker exec traefik ls -l /acme.json で確認 |
デバッグ手順
- ログレベル上げる:Compose に
command: ["--log.level=DEBUG", "--configFile=/etc/traefik/traefik.yml"]を追加。 - ステージング環境でテスト:
acme.stagingエンドポイントを使用し、レートリミットや失敗時の影響を抑える。
6.2 本番運用で守るべきベストプラクティス
| 項目 | 推奨設定 |
|---|---|
| 証明書取得方式 | 単一ドメインは HTTP‑01、ワイルドカードや複数サブドメインは DNS‑01(最小権限の API トークン) |
| 環境変数管理 | .env に格納し .gitignore で除外、Compose の env_file: で自動注入 |
| acme.json 永続化 | ボリュームマウント + 起動時 chmod 600 スクリプト + 定期バックアップ |
| ダッシュボード保護 | HTTPS + Basic 認証(bcrypt)+ 任意で IP ホワイトリスト |
| ログレベル | 本番は INFO、障害時に DEBUG に切り替え |
| テスト環境 | Let’s Encrypt Staging エンドポイントで事前検証し、本番へ切り替える |
7️⃣ 完全なディレクトリ構成例
|
1 2 3 4 5 6 7 8 9 10 11 |
project-root/ ├─ docker-compose.yml ├─ traefik.yml ├─ dynamic.yml ├─ acme.json # 初回は空ファイルを作成 (touch acme.json) ├─ entrypoint.sh # 権限自動設定スクリプト ├─ .env # 機密情報(CF_API_TOKEN, AWS_… 等) └─ .gitignore ├─ .env └─ acme.json # リポジトリにコミットしない |
この構成をそのまま docker compose up -d すれば、Traefik が自動的に Let’s Encrypt 証明書を取得し、HTTPS 経由で安全にサービスを提供できます。
🎉 まとめ
- Docker Compose と Traefik v3 の組み合わせだけで、証明書の取得・更新が完全自動化されます。
- セキュリティ対策(Docker ソケット最小権限化、Basic 認証ハッシュ、acme.json 権限管理)を忘れずに実装してください。
- 環境変数とネットワークの事前準備が整っていれば、数分で本番レベルのリバースプロキシが完成します。
ぜひこの手順をベースに、自社インフラや開発環境へ導入してみてください。質問や実装上の課題は、公式ドキュメントやコミュニティフォーラムで随時チェックすると安心です。