ガジェットコンパス

ガジェット探求の旅に終わりはない
🔍
DokkuTraefiknginxLet's EncryptHTTPSラベルベースルーティングRoute53SSL証明書リバースプロキシ自動化

Dokku + Traefik完全ガイド:nginxの複雑設定から卒業して自動HTTPSを実装する実践手順

👤 いわぶち 📅 2025-12-10 ⭐ 4.5点 ⏱️ 20m

📌 1分で分かる記事要約

  • Dokku標準のnginx設定は複数サービス・複数ドメインになると管理が急速に複雑化する問題がある
  • TraefikはDockerラベルベースのルーティングで、設定行数を1/5に削減できる革新的なソリューション
  • Let’s EncryptとRoute53の連携により、複雑なSSL証明書管理が完全自動化される
  • 本記事では、実際に動作するコマンド例を示しながら、Dokku初心者でも実装できる段階的な手順を解説
  • nginx設定ファイルの編集から解放されて、アプリのラベルを付けるだけで本番運用ができる状態を実現できる

📝 結論

Dokku上でマルチドメイン・マルチサービスを運用する場合、TraefikはnginxからのHTTPS・ルーティング管理を劇的にシンプル化します。アプリにラベルを付けるだけで自動HTTPS取得・ルーティング・負荷分散が完成し、運用負荷を大幅に軽減できる実践的なアプローチです。


問題提起:Dokku標準のnginxが抱える課題

Dokkuを使ってAPIやWebアプリケーションをセルフホストしている開発者の多くは、最初の1〜2個のサービス公開までは、Dokku標準のnginxプラグインで十分と感じています。しかし、サービスが増えていくにつれて、以下のような課題が顕在化してきます。

nginxの設定ファイルが肥大化する

Dokku標準のnginxはテンプレートベースで自動生成されますが、カスタム要件(Basic認証、特定パスのリダイレクト、ヘッダ付与など)が増えると、/home/dokku/<app>/nginx.conf.d/ に手動で設定を追加する必要が出てきます。アプリが5個、10個と増えていくと、nginx.confの総行数は数百行を超え、どのブロックがどのアプリに対応しているのか追跡が困難になります。

HTTPS証明書管理の複雑性

Dokku標準のdokku-letsencryptプラグインは単一ドメインの証明書更新には優秀ですが、複数のサブドメイン(api.example.com、admin.example.com、app.example.comなど)を管理する場合、各ドメインの証明書更新タイミングが異なり、更新失敗時の対応も煩雑になります。

サービス追加時の手作業が増える

新しいAPIやサービスを追加するたびに、以下の作業が必要になります:

  1. Dokkuでアプリを作成
  2. Gitでコードをpush
  3. nginx設定ファイルを編集(ドメイン、ルーティング、認証など)
  4. Let’s Encryptで証明書を取得
  5. nginx設定をテストしてリロード

このプロセスは手作業が多く、typoやコンフリクトのリスクが高まります。

設定ミスによるダウンタイム

nginxの設定ファイルにsyntax errorがあると、nginx -tで検出されても、その原因特定と修正に時間がかかります。特に複数のlocationブロックが絡み合っている場合、予期しない動作が起きることもあります。


Traefikという解決策:ラベルベースルーティングの魔法

TraefikはGoで実装された次世代のリバースプロキシで、Dockerコンテナに付与したラベルを読み取り、動的にルーティング設定を生成します。Dokku環境では、Traefikプラグインを導入することで、nginxの複雑な設定管理から完全に解放されます。

Traefikが実現する3つの革新

1. ラベルベースのルーティング定義

nginxのserverブロックやlocationディレクティブを書く代わりに、Dokkuアプリにtraefik.*という環境変数(またはラベル)を付与するだけで、ルーティングが完成します。

dokku config:set my-api \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_MYAPI_RULE='Host(`api.example.com`)' \
  TRAEFIK_HTTP_ROUTERS_MYAPI_ENTRYPOINTS=websecure \
  TRAEFIK_HTTP_ROUTERS_MYAPI_TLS=true

この数行で、nginxなら30〜50行かかる設定が完成します。

2. Let’s Encryptの完全自動化

Traefikに組み込まれたACME(Automated Certificate Management Environment)機能により、ホスト名ごとに自動的にLet’s Encrypt証明書を取得・更新します。DNS-01検証を使えば、Route53などのDNSプロバイダと連携して、ワイルドカード証明書も自動取得可能です。

3. 動的なサービスディスカバリ

Dokkuアプリをデプロイしてラベルを追加するだけで、Traefikが自動的にそれを検出し、ルーティングテーブルに追加します。設定ファイルのリロード、nginx再起動といった手作業が一切不要です。


全体アーキテクチャ:どのようにして「魔法」が実現されるのか

Dokku + Traefik構成を図式化すると、以下のようになります。

インターネット

  [80/443ポート]

┌─────────────────────┐
│   Traefik Container │
│  (リバースプロキシ) │
│  - ルーティング     │
│  - HTTPS/TLS       │
│  - Let's Encrypt   │
└─────────────────────┘
    ↓  ↓  ↓
┌────────────────────────────────────────┐
│        Dokku Host (Docker)             │
│                                        │
│  ┌──────────────┐  ┌──────────────┐  │
│  │  my-api      │  │  my-admin    │  │
│  │  (Port 5000) │  │  (Port 3000) │  │
│  └──────────────┘  └──────────────┘  │
│                                        │
│  各アプリにTraefik用ラベルが付与      │
│  → Traefikが自動検出・ルーティング   │
└────────────────────────────────────────┘

フロー詳細:

  1. ユーザーがhttps://api.example.com/usersにアクセス
  2. Traefik(ホストの80/443をlisten)がリクエストを受け取る
  3. Host(api.example.com)というルールにマッチするルーターを検索
  4. 該当ルーターがmy-apiサービス(Port 5000)を指しているため、そこへプロキシ
  5. my-apiコンテナが/usersエンドポイントを処理して応答
  6. Traefikがレスポンスをクライアントに返す

この一連の流れで、nginxの設定ファイルは一切必要ありません。


前提条件と環境確認

本記事の手順を実行するには、以下の環境が必要です。

必須要件

  • サーバ環境:Ubuntu 22.04 LTS以上(Dokkuがサポートしているディストリビューション)
  • Dokkuインストール済みdokku versionコマンドで確認可能な状態
  • パブリックIP:サーバがインターネットからアクセス可能
  • ドメイン:Route53またはその他のDNSで管理されているドメイン(例:example.com)
  • ポート開放:ホストファイアウォールで80番(HTTP)と443番(HTTPS)が開放されていること
  • Docker動作:Dokkuに含まれるDockerが正常に動作していること

確認コマンド

# Dokkuのバージョン確認
dokku version

# Dockerの動作確認
docker ps

# ホストのポート確認(80/443が使用されていないこと)
sudo netstat -tlnp | grep -E ':(80|443)'

ステップ1:Dokku標準のnginxを無効化(Traefik導入の準備)

TraefikをDokku環境の唯一のリバースプロキシにするため、まずDokku標準のnginxを無効化する必要があります。

なぜnginxを無効化するのか

Dokku標準のnginxとTraefik両方が同時に80/443ポートをlistenしようとすると、ポート競合エラーが発生し、どちらも正常に起動できません。Traefik導入時は、ホストの80/443をTraefikに一本化するのがベストプラクティスです。

無効化手順

# Dokku標準のnginx-vhostsプラグインを無効化
dokku plugin:disable nginx-vhosts

# Dokku標準のLet's Encryptプラグインも無効化
# (Traefik側のACMEで証明書管理を一元化するため)
dokku plugin:disable letsencrypt

# 確認:プラグインが無効化されたことを確認
dokku plugin:list

既存アプリへの影響

既にDokku上で稼働しているアプリがある場合、この操作により一時的にHTTPアクセスが遮断されます。本番環境で実施する場合は、メンテナンス時間を事前に告知し、実施してください。


ステップ2:Traefikプラグインのインストール

Dokku用のTraefikプラグインをインストールします。

プラグインのインストール

# Dokkuプラグインディレクトリに移動
cd /var/lib/dokku/plugins

# Traefikプラグインをクローン
sudo git clone https://github.com/dokku-community/dokku-traefik.git traefik

# プラグインをインストール
dokku plugin:install

# インストール確認
dokku traefik:version

インストール後の確認

# Traefikプラグインのサブコマンドを確認
dokku traefik:help

# 出力例:
# traefik:disable                   Disable traefik
# traefik:enable                    Enable traefik
# traefik:logs                      Show traefik logs
# traefik:set                       Set traefik configuration
# ...

ステップ3:Traefikの初期設定(ACME・Let’s Encrypt)

TraefikがLet’s Encryptから自動的に証明書を取得できるよう、ACME(Automated Certificate Management Environment)を設定します。

3-1. ACMEメールアドレスの設定

Let’s Encryptは、証明書の有効期限が近づくと、設定したメールアドレスに通知を送ります。

# グローバル設定としてACMEメールを設定
dokku config:set --global \
  TRAEFIK_ACME_EMAIL=your-email@example.com

3-2. ステージング環境でのテスト(重要)

Let’s Encryptにはレートリミット(1時間に5回まで)があり、設定ミスで何度も失敗するとブロックされます。本番前に必ずステージング環境でテストしてください。

# ステージング環境(テスト用、自己署名証明書)を使用
dokku config:set --global \
  TRAEFIK_ACME_CA_SERVER=https://acme-staging-v02.api.letsencrypt.org/directory

3-3. ACMEストレージの設定

証明書メタデータを保存するファイルのパスを指定します。

# ストレージパスを設定
dokku config:set --global \
  TRAEFIK_ACME_STORAGE=/var/lib/traefik/acme.json

# ストレージディレクトリを作成
sudo mkdir -p /var/lib/traefik
sudo touch /var/lib/traefik/acme.json

# パーミッション設定(Traefikが読み書きできるように)
sudo chmod 600 /var/lib/traefik/acme.json
sudo chown 1000:1000 /var/lib/traefik/acme.json  # Traefikコンテナのユーザに合わせる

3-4. HTTP-01検証の有効化

Let’s Encryptの検証方式として、HTTP-01(ポート80でのチャレンジ)を使用します。

# HTTP-01チャレンジを有効化
dokku config:set --global \
  TRAEFIK_ACME_HTTP_ENTRYPOINT=web

ステップ4:Route53連携(DNS-01検証の設定)

複数のサブドメインやワイルドカード証明書を取得する場合、DNS-01検証が便利です。Route53と連携するための設定を行います。

4-1. IAMユーザの作成と権限設定

AWS管理コンソールでIAMユーザを作成し、Route53への最小権限を付与します。

推奨IAMポリシー:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets"
      ],
      "Resource": "arn:aws:route53:::hostedzone/Z1234567890ABC"
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ListHostedZones",
        "route53:ListResourceRecordSets"
      ],
      "Resource": "*"
    }
  ]
}

Z1234567890ABCは自分のHosted Zone IDに置き換えてください。

4-2. アクセスキーの発行

IAMユーザに対してAccess Key IDとSecret Access Keyを発行します。

# AWS CLI で確認(オプション)
aws iam list-access-keys --user-name traefik-user

4-3. Dokkuへの認証情報設定

発行したAWSの認証情報をDokku経由でTraefikに注入します。

# AWS認証情報をグローバル設定として登録
dokku config:set --global \
  AWS_ACCESS_KEY_ID=AKIA... \
  AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxx \
  AWS_REGION=us-east-1

# DNS-01プロバイダとしてRoute53を指定
dokku config:set --global \
  TRAEFIK_ACME_DNS_CHALLENGE_PROVIDER=route53

4-4. DNS反映待ちタイムアウトの調整

DNS-01検証では、TXTレコードの反映を待つ必要があります。環境によっては反映に時間がかかるため、タイムアウト値を調整します。

# DNS反映待ちタイムアウトを120秒に設定
dokku config:set --global \
  LEGO_DNS_TIMEOUT=120

ステップ5:Traefikコンテナの起動

ここまでの設定を反映させて、Traefikコンテナを起動します。

5-1. Traefikの起動

# Traefikを有効化・起動
dokku traefik:enable
dokku traefik:start

# 起動確認
dokku traefik:info

5-2. ログの確認

# Traefikのログを確認
dokku traefik:logs

# 出力例:
# time="2025-12-10T08:19:13Z" level=info msg="Traefik version 3.0.0"
# time="2025-12-10T08:19:14Z" level=info msg="Starting Traefik"
# ...

5-3. ポート確認

# Traefikが80/443をlistenしていることを確認
sudo netstat -tlnp | grep -E ':(80|443)'

# 出力例:
# tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1234/traefik
# tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      1234/traefik

ステップ6:実践例1 - シンプルなAPIの公開(api.example.com)

それでは、実際にDokkuアプリをTraefik経由で公開してみましょう。最初の例は、REST APIをapi.example.comで公開するケースです。

6-1. Dokkuアプリの作成

# アプリを作成
dokku apps:create my-api

# 環境変数を設定(アプリ側の設定)
dokku config:set my-api \
  NODE_ENV=production \
  PORT=5000

6-2. アプリのデプロイ

# Gitリモートを追加
git remote add dokku dokku@your-server:my-api

# コードをpush(自動デプロイ)
git push dokku main:master

6-3. Traefik用ラベルの設定

# Traefik用ラベルを環境変数として設定
dokku config:set my-api \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_MYAPI_RULE='Host(`api.example.com`)' \
  TRAEFIK_HTTP_ROUTERS_MYAPI_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_MYAPI_TLS=true \
  TRAEFIK_HTTP_ROUTERS_MYAPI_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_MYAPI_LOADBALANCER_SERVER_PORT=5000

6-4. DNS設定の確認

Route53またはお使いのDNSプロバイダで、api.example.comがDokkuサーバのIPアドレスを指していることを確認してください。

# DNS確認コマンド例
dig api.example.com

# 出力例:
# api.example.com.  300  IN  A  203.0.113.42

6-5. アクセステスト

# HTTPでアクセス(自動的にHTTPSにリダイレクト)
curl -I http://api.example.com/

# 出力例:
# HTTP/1.1 301 Moved Permanently
# Location: https://api.example.com/

# HTTPSでアクセス
curl -I https://api.example.com/

# 出力例:
# HTTP/2 200
# content-type: application/json

ステップ7:実践例2 - 複数サブドメインの管理(api / admin / app)

次に、複数のサブドメインで異なるサービスを公開する、より実践的なシナリオを見てみましょう。

7-1. 3つのアプリを作成

# REST API
dokku apps:create my-api
dokku config:set my-api PORT=5000

# 管理画面
dokku apps:create my-admin
dokku config:set my-admin PORT=3000

# フロントエンド
dokku apps:create my-frontend
dokku config:set my-frontend PORT=8080

7-2. 各アプリにTraefik用ラベルを設定

my-api(api.example.com):

dokku config:set my-api \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_API_RULE='Host(`api.example.com`)' \
  TRAEFIK_HTTP_ROUTERS_API_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_API_TLS=true \
  TRAEFIK_HTTP_ROUTERS_API_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_API_LOADBALANCER_SERVER_PORT=5000

my-admin(admin.example.com):

dokku config:set my-admin \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_ADMIN_RULE='Host(`admin.example.com`)' \
  TRAEFIK_HTTP_ROUTERS_ADMIN_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_ADMIN_TLS=true \
  TRAEFIK_HTTP_ROUTERS_ADMIN_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_ADMIN_LOADBALANCER_SERVER_PORT=3000

my-frontend(app.example.com):

dokku config:set my-frontend \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_RULE='Host(`app.example.com`)' \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_TLS=true \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_FRONTEND_LOADBALANCER_SERVER_PORT=8080

7-3. 設定の確認

# 各アプリの設定を確認
dokku config my-api | grep TRAEFIK
dokku config my-admin | grep TRAEFIK
dokku config my-frontend | grep TRAEFIK

7-4. Traefikダッシュボードでの可視化

Traefikに組み込まれたダッシュボードを有効化すると、設定されたルーターやサービスを視覚的に確認できます。

# ダッシュボードを有効化(オプション)
dokku config:set --global \
  TRAEFIK_API_DASHBOARD=true \
  TRAEFIK_API_INSECURE=false

# ダッシュボードURL(例)
# https://traefik.example.com/dashboard/

ステップ8:パスベースルーティング(同一ドメイン内での分岐)

同じドメイン(例:example.com)で異なるパスをそれぞれ別のアプリに振り分ける場合の設定方法です。

8-1. シナリオ

https://example.com/api      → my-api(ポート5000)
https://example.com/admin    → my-admin(ポート3000)
https://example.com/         → my-frontend(ポート8080)

8-2. ラベル設定

# API(/api で始まるパス)
dokku config:set my-api \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_API_RULE='Host(`example.com`) && PathPrefix(`/api`)' \
  TRAEFIK_HTTP_ROUTERS_API_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_API_TLS=true \
  TRAEFIK_HTTP_ROUTERS_API_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_API_LOADBALANCER_SERVER_PORT=5000 \
  TRAEFIK_HTTP_MIDDLEWARES_API_STRIPPREFIX_PREFIXES='/api'

# 管理画面(/admin で始まるパス)
dokku config:set my-admin \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_ADMIN_RULE='Host(`example.com`) && PathPrefix(`/admin`)' \
  TRAEFIK_HTTP_ROUTERS_ADMIN_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_ADMIN_TLS=true \
  TRAEFIK_HTTP_ROUTERS_ADMIN_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_ADMIN_LOADBALANCER_SERVER_PORT=3000 \
  TRAEFIK_HTTP_MIDDLEWARES_ADMIN_STRIPPREFIX_PREFIXES='/admin'

# フロントエンド(ルートパス)
dokku config:set my-frontend \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_RULE='Host(`example.com`)' \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_TLS=true \
  TRAEFIK_HTTP_ROUTERS_FRONTEND_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_FRONTEND_LOADBALANCER_SERVER_PORT=8080

8-3. ミドルウェア(StripPrefix)の役割

TRAEFIK_HTTP_MIDDLEWARES_API_STRIPPREFIX_PREFIXES='/api'は、Traefikがアプリにリクエストを転送する際に、パスプレフィックス(/api)を削除するよう指示します。

例:

  • クライアント → https://example.com/api/users
  • Traefik → my-api/users として転送
  • アプリ → /api を削除された /users を処理

これにより、アプリ側で/apiプレフィックスを考慮せずに実装できます。


ステップ9:Basic認証の追加(管理画面の保護)

機密性の高い管理画面には、Basic認証を追加して保護します。

9-1. htpasswdファイルの生成

# htpasswdコマンドでユーザ認証情報を生成
htpasswd -c /tmp/htpasswd admin

# パスワード入力プロンプトが出現
# New password: ****
# Re-type new password: ****

# ファイル内容を確認
cat /tmp/htpasswd

# 出力例:
# admin:$apr1$abcdef12$XXXXXXXXXXXXXXXXXXXXXXXXX

9-2. Dokku経由での認証設定

# Base64エンコード(Traefikが要求する形式)
htpasswd_content=$(cat /tmp/htpasswd | base64 -w0)

# Dokkuに設定
dokku config:set my-admin \
  TRAEFIK_HTTP_MIDDLEWARES_ADMIN_AUTH_BASICAUTH_USERS="${htpasswd_content}" \
  TRAEFIK_HTTP_ROUTERS_ADMIN_MIDDLEWARES=admin_auth@docker

9-3. アクセステスト

# 認証なしでアクセス(401 Unauthorized が返される)
curl -I https://admin.example.com/

# 認証ありでアクセス
curl -I -u admin:password https://admin.example.com/

# 出力例:
# HTTP/2 200

ステップ10:ヘルスチェックの設定

Traefikはバックエンドのヘルスチェックをサポートしており、不健全なコンテナへのトラフィックを自動的に遮断できます。

10-1. アプリ側のヘルスチェックエンドポイント

まず、アプリ側で/healthzエンドポイントを実装します(例:Node.js)。

// app.js
app.get('/healthz', (req, res) => {
  res.status(200).json({ status: 'ok' });
});

10-2. Traefik側のヘルスチェック設定

dokku config:set my-api \
  TRAEFIK_HTTP_SERVICES_API_LOADBALANCER_HEALTHCHECK_PATH='/healthz' \
  TRAEFIK_HTTP_SERVICES_API_LOADBALANCER_HEALTHCHECK_INTERVAL='10s' \
  TRAEFIK_HTTP_SERVICES_API_LOADBALANCER_HEALTHCHECK_TIMEOUT='5s'

10-3. 動作確認

# Traefikログでヘルスチェック結果を確認
dokku traefik:logs | grep healthz

# 出力例:
# time="2025-12-10T08:19:13Z" level=debug msg="Health check for my-api: ok"

トラブルシューティング:よくある問題と対処法

Dokku + Traefik導入時に直面しやすい問題と、その解決方法を解説します。

問題1:「ブラウザで404が返される」

原因候補:

  1. Traefik用ラベルが正しく設定されていない
  2. アプリがまだ起動していない
  3. DNS設定がサーバIPを指していない

対処方法:

# ラベル設定を確認
dokku config my-api | grep TRAEFIK

# アプリが起動しているか確認
dokku ps:list

# Traefikのルーター設定を確認
dokku traefik:logs | grep "my-api"

# DNS設定を確認
dig api.example.com

# Traefikコンテナに入ってデバッグ
docker exec -it traefik /bin/sh
# その中で curl http://my-api-web.dokku.svc.cluster.local:5000/ を試す

問題2:「HTTPSで証明書エラーが出る」

原因候補:

  1. DNS設定がまだ反映されていない
  2. Let’s Encryptのレートリミットに達している
  3. ACME設定が間違っている

対処方法:

# ACME設定を確認
dokku config:get --global TRAEFIK_ACME_EMAIL
dokku config:get --global TRAEFIK_ACME_CA_SERVER

# Traefikログで証明書取得エラーを確認
dokku traefik:logs | grep -i "acme\|certificate"

# acme.jsonファイルが存在・読み取り可能か確認
ls -la /var/lib/traefik/acme.json

# ステージング環境でテスト中か確認
# (ステージング環境ではブラウザに警告が出ます)

問題3:「コンテナ内のアプリがport 5000で待ち受けているはずなのに502 Bad Gateway」

原因候補:

  1. TRAEFIK_HTTP_SERVICES_*_LOADBALANCER_SERVER_PORTが間違ったポート番号
  2. アプリがコンテナ内で127.0.0.1だけをlistenしている(0.0.0.0にバインドする必要がある)
  3. アプリが起動に失敗している

対処方法:

# アプリのログを確認
dokku logs my-api

# コンテナに入ってポートをチェック
dokku enter my-api web

# コンテナ内でnetstatを実行
netstat -tlnp

# 出力例:
# Proto Recv-Q Send-Q Local Address  Foreign Address  State   PID/Program
# tcp        0      0 0.0.0.0:5000   0.0.0.0:*        LISTEN  1/node

# Dockerfileで EXPOSE を確認
cat Dockerfile | grep EXPOSE

問題4:「複数のドメイン・複数のアプリで、ルーティングが混乱している」

原因候補:

  1. ラベル名(ルーター名)が重複している
  2. ルール(Host / PathPrefix)が曖昧で、複数のルーターにマッチしている
  3. ミドルウェア設定が他のアプリに影響している

対処方法:

# 全アプリのTraefik設定を一覧表示
for app in $(dokku apps:list); do
  echo "=== $app ==="
  dokku config $app | grep TRAEFIK
done

# Traefikダッシュボードで可視化(有効な場合)
# https://traefik.example.com/dashboard/

# ルール優先度を確認(Traefikログで)
dokku traefik:logs | grep -i "rule\|priority"

ベストプラクティス:安定運用のための指針

Dokku + Traefik環境を長期的に安定運用するための、実践的なベストプラクティスをまとめました。

命名規則の統一

ラベル名やルーター名を統一的なルールで命名することで、設定の可読性と管理性が大幅に向上します。

# 推奨パターン:
# TRAEFIK_HTTP_ROUTERS_<APPNAME>_*
# TRAEFIK_HTTP_SERVICES_<APPNAME>_*
# TRAEFIK_HTTP_MIDDLEWARES_<APPNAME>_<PURPOSE>_*

# 例:my-api アプリの場合
TRAEFIK_HTTP_ROUTERS_MYAPI_RULE='Host(`api.example.com`)'
TRAEFIK_HTTP_SERVICES_MYAPI_LOADBALANCER_SERVER_PORT=5000
TRAEFIK_HTTP_MIDDLEWARES_MYAPI_AUTH_BASICAUTH_USERS='...'

設定変更のワークフロー

新しいアプリを追加・設定を変更する際の標準的なフロー:

  1. ステージング環境でテスト
    本番に反映する前に、テスト用ドメイン(staging-api.example.comなど)で動作確認
  2. 設定ドキュメント化
    各アプリのTraefik設定をREADME.mdなどにまとめておく
  3. 段階的な本番反映
    一度にすべての設定を変更せず、1アプリずつ本番に反映
  4. ログ監視
    本番反映後、Traefikログを監視して問題がないか確認

セキュリティのベストプラクティス

  • AWS認証情報の管理
    AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYは絶対にGitにコミットしない。.envファイルで管理し、本番サーバにのみデプロイ
  • Basic認証の強化
    管理画面には必ずBasic認証を設定し、ユーザ名・パスワードは定期的に変更
  • Traefikダッシュボードの保護
    ダッシュボードを有効にする場合は、Basic認証またはIP制限で保護

ログ監視とアラート

# Traefikログを定期的に確認
dokku traefik:logs | tail -100

# エラーログだけをフィルタリング
dokku traefik:logs | grep -i "error\|warn"

# 本番環境では外部ログサービスに送信
# (Datadog, Splunk, CloudWatch など)

証明書更新の監視

Let’s Encryptの証明書は90日有効で、30日前から自動更新が開始されます。

# 証明書の有効期限を確認
openssl s_client -connect api.example.com:443 -showcerts | \
  openssl x509 -noout -dates

# 出力例:
# notBefore=Dec 10 08:19:13 2025 GMT
# notAfter=Mar 10 08:19:13 2026 GMT

nginx vs Traefik:設定量の比較

同じ要件(複数サブドメイン、HTTPS、Basic認証)を実装する場合、設定量がどの程度削減されるか比較してみましょう。

nginx従来型の設定例

# api.example.com 用の設定(HTTPSリダイレクト + TLS + Basic認証)
server {
    listen 80;
    server_name api.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate /var/lib/dokku/letsencrypt/certs/api.example.com.crt;
    ssl_certificate_key /var/lib/dokku/letsencrypt/certs/api.example.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        auth_basic "Restricted";
        auth_basic_user_file /home/dokku/my-api/htpasswd;

        proxy_pass http://my-api-80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /healthz {
        proxy_pass http://my-api-80/healthz;
        access_log off;
    }
}

# admin.example.com 用の設定(同様に30〜40行)
# app.example.com 用の設定(同様に30〜40行)
# ... 合計120〜150行

総行数:約120〜150行

Traefik(ラベルベース)の設定例

# api.example.com 用の設定
dokku config:set my-api \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_API_RULE='Host(`api.example.com`)' \
  TRAEFIK_HTTP_ROUTERS_API_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_API_TLS=true \
  TRAEFIK_HTTP_ROUTERS_API_TLS_CERTRESOLVER=letsencrypt \
  TRAEFIK_HTTP_SERVICES_API_LOADBALANCER_SERVER_PORT=5000 \
  TRAEFIK_HTTP_MIDDLEWARES_API_AUTH_BASICAUTH_USERS='...' \
  TRAEFIK_HTTP_ROUTERS_API_MIDDLEWARES=api_auth@docker \
  TRAEFIK_HTTP_SERVICES_API_LOADBALANCER_HEALTHCHECK_PATH='/healthz'

# admin.example.com 用の設定(同様に8〜10行)
# app.example.com 用の設定(同様に8〜10行)
# ... 合計24〜30行

総行数:約24〜30行

削減率

  • nginx:120〜150行
  • Traefik:24〜30行
  • 削減率:80%削減(約1/5に圧縮)

さらに重要な点として、Traefik設定はプログラム的に扱える環境変数なため、設定の自動生成・バージョン管理・CI/CDパイプラインへの組み込みが容易です。


自動HTTPSの仕組み:Let’s Encrypt × Traefik × Route53

Traefik + Dokku環境で、自動HTTPS取得がどのように実現されるかを、詳しく解説します。

フロー全体

1. ユーザが https://api.example.com にアクセス

2. Traefikが「api.example.com の証明書がない」と判定

3. Traefikが Let's Encrypt に証明書リクエストを送信

4. Let's Encrypt が DNS-01 チャレンジを要求

5. Traefik が Route53 API を呼び出し
   _acme-challenge.api.example.com の TXT レコードを作成

6. Let's Encrypt が TXT レコードを確認(DNS反映待ち)

7. 検証成功 → 証明書を発行

8. Traefik が証明書を /var/lib/traefik/acme.json に保存

9. Traefik が新しい証明書をロード

10. ユーザが https://api.example.com にアクセス可能に

証明書の有効期限と自動更新

Let’s Encryptの証明書は90日間有効です。Traefikは自動的に以下のスケジュールで更新を試みます。

  • 有効期限30日前:更新処理を開始
  • 有効期限1日前:最後の更新試行
  • 有効期限後:証明書エラー(通常はここまでに更新完了)
# 証明書ファイルから有効期限を確認
openssl x509 -in /var/lib/traefik/acme.json -noout -dates

# または、ブラウザのアドレスバーの鍵アイコンから確認
# → 「証明書を表示」→「有効期間」を確認

DNS-01検証の利点

DNS-01検証(Route53を使用)には、HTTP-01検証にない利点があります。

項目HTTP-01DNS-01
ポート80番が必要ポート不要
ファイアウォールポート80を開放必須制限可能
ワイルドカード証明書不可可能
複数IPでの運用各IPで検証が必要1つのDNS設定で完結
CDN背後での運用複雑シンプル

運用シナリオ別ガイド

実際の運用では、様々なシナリオに直面します。以下は代表的なケースと対応方法です。

シナリオ1:新しいAPIバージョンをBlue-Green方式で段階的に切り替える

既存のv1から新しいv2へ、トラフィックを段階的に移行したい場合:

# v1 アプリ(既存)
dokku apps:create my-api-v1
dokku config:set my-api-v1 \
  TRAEFIK_HTTP_ROUTERS_API_RULE='Host(`api.example.com`)' \
  TRAEFIK_HTTP_ROUTERS_API_ENTRYPOINTS=web,websecure \
  TRAEFIK_HTTP_ROUTERS_API_TLS=true

# v2 アプリ(新規)
dokku apps:create my-api-v2
dokku config:set my-api-v2 \
  TRAEFIK_ENABLE=false  # 最初は無効化

# v2 のテスト完了後、ラベルを有効化
dokku config:set my-api-v2 \
  TRAEFIK_ENABLE=true \
  TRAEFIK_HTTP_ROUTERS_APIV2_RULE='Host(`api-v2.example.com`)' \
  ...

# トラフィック切り替え:v1 を無効化、v2 を有効化
dokku config:set my-api-v1 TRAEFIK_ENABLE=false
dokku config:set my-api-v2 TRAEFIK_ENABLE=true
# (ラベルを付け替える)

シナリオ2:本番環境での急なスケールアップ

トラフィック急増に対応するため、同じアプリを複数インスタンス起動したい場合:

# 既存アプリのスケール設定
dokku ps:scale my-api=3  # 3個のプロセスを起動

# Traefik は自動的に複数インスタンスにロードバランシング
# (ラベル設定は変更不要)

シナリオ3:ステージング環境と本番環境の同時運用

同じコードベースをステージング・本番で並行運用する場合:

# ステージング環境
dokku apps:create my-api-staging
dokku config:set my-api-staging \
  TRAEFIK_HTTP_ROUTERS_API_STAGING_RULE='Host(`staging-api.example.com`)' \
  ...

# 本番環境
dokku apps:create my-api-production
dokku config:set my-api-production \
  TRAEFIK_HTTP_ROUTERS_API_PROD_RULE='Host(`api.example.com`)' \
  ...

# 本番環境でのテスト完了後、本番環境にデプロイ

まとめ:Dokku + Traefik で実現できる理想的なデプロイ環境

Dokku + Traefikの組み合わせにより、以下のような理想的なデプロイ環境が実現されます。

実現されるメリット

nginxの複雑な設定ファイルから解放
アプリにラベルを付けるだけでルーティング完成。ファイル編集による誤設定のリスク排除。

自動HTTPS取得・更新
Let’s Encryptとの連携で、証明書の取得・更新が完全自動化。有効期限切れの心配なし。

スケーラビリティ
新しいサブドメインやサービスを追加する際、設定行数はほぼ一定。サービス数が増えても管理負荷が増えない。

可視化とデバッグ
Traefikダッシュボードでルーティング状態をリアルタイムに確認。問題発生時の原因特定が容易。

セキュリティ強化
Basic認証、IP制限、ヘッダ操作などをミドルウェアで一元管理。設定の統一性が向上。

運用効率化
CI/CDパイプラインに設定を組み込み、デプロイ時の設定変更を自動化可能。

次のステップ

本記事で紹介した基本的な設定ができたら、以下の発展的なトピックにも挑戦してみてください。

  • Traefikのミドルウェア活用:CORS設定、レートリミット、キャッシング
  • ワイルドカード証明書の取得*.example.comで複数サブドメインをカバー
  • 複数Dokkuサーバの統合管理:複数のホストをTraefikで一元制御
  • 監視・アラート:Prometheus + Grafanaでメトリクス可視化
  • ログ集約:ELK Stack や Datadog への統合

Dokku + Traefikは、小規模スタートアップから中堅企業まで、あらゆる規模のセルフホスト環境に対応できる、実用的で拡張性の高いソリューションです。


参考資料

本記事で紹介した内容は、2025年12月時点のバージョンに基づいています。ツールのアップデートに伴い、コマンドやパラメータが変更される可能性があるため、最新のドキュメントを合わせて参照することをお勧めします。

🗂️ 人気カテゴリ

記事数の多いカテゴリから探す