言語を切り替える
テーマを切り替える

Docker で Nginx 構築完全ガイド:設定ファイルのマウント、HTTPS 設定、リバースプロキシ実践

7 回目の docker restart nginx、ブラウザを更新しても——502 エラーのまま。nginx.conf は書き換えたのに、コンテナ内の設定がどうしても反映されない。

Docker で Nginx を動かすときの設定問題は、コンテナ化に取り組む人なら誰もが一度は踏むポイントです。設定ファイルのマウント、HTTPS 証明書、コンテナ間通信——一見シンプルな操作にも、実は細かな落とし穴が潜んでいます。本記事では、設定ファイルの正しいマウント方法から、HTTPS 証明書の自動更新、リバースプロキシのネットワーク設定まで、すぐ使える Docker Nginx の構成案をまとめます。

本記事で学べること:

  • 設定ファイルが反映されない原因と、5 つの正しいマウント方法
  • 自己署名証明書から Let’s Encrypt までの HTTPS 構築手順
  • 他の Docker コンテナをリバースプロキシするときのネットワーク設定
  • 本番環境向けのセキュリティ強化とパフォーマンスチューニング

Docker Nginx の基本設定とファイルマウント

なぜ設定ファイルをマウントするのか

Nginx の設定をイメージに焼き込めばいいのでは?——技術的には可能ですが、運用がつらくなります。

設定を 1 行変えるたびにイメージを再ビルドし、レジストリへプッシュし、pull してコンテナを再起動——この一連の作業だけで十数分は消えます。設定のバージョン管理や、環境ごとの切り替えも面倒です。深夜 2 時に本番障害が起き、設定をすぐロールバックしたいのに、イメージビルドを待つ羽目になる——想像するだけで胃が痛くなります。

設定ファイルをマウントする理由はここにあります。ホスト側のファイルを編集すれば、コンテナ内にすぐ反映される。テスト、ロールバック、チーム開発がすべて楽になります。

Nginx コンテナの主要ディレクトリ構造

まず、Nginx がコンテナ内のどこに何を置いているかを押さえましょう。

/etc/nginx/
├── nginx.conf              # メイン設定ファイル
├── conf.d/                 # サイトごとの設定ディレクトリ
│   └── default.conf        # デフォルトサイト設定
/usr/share/nginx/html       # 静的ファイルのルート
/var/log/nginx/             # ログディレクトリ
    ├── access.log
    └── error.log

重要なのは、nginx.conf に include /etc/nginx/conf.d/*.conf; という行があることです。メイン設定が conf.d 以下の .conf を自動読み込みします。nginx.conf だけマウントして conf.d を忘れる——最初の落とし穴はここです。

正しいマウント手順:ステップバイステップ

いきなりコンテナを起動しないでください。先に準備を済ませると、後のトラブルが大幅に減ります。

ステップ 1:コンテナのデフォルト設定をテンプレートとしてコピー

なぜこうするか?公式のデフォルト設定は検証済みで、ゼロから書くより安全だからです。

# 一時コンテナを起動
docker run --name nginx-temp -d nginx

# デフォルト設定をコピー
docker cp nginx-temp:/etc/nginx/nginx.conf ./nginx/nginx.conf
docker cp nginx-temp:/etc/nginx/conf.d ./nginx/conf.d

# 使い終わったら削除
docker stop nginx-temp && docker rm nginx-temp

ステップ 2:ホスト側に標準ディレクトリ構造を作成

私は Docker 関連ファイルを /opt 以下にまとめる習慣があります。好みに合わせて調整してください。

mkdir -p /opt/nginx/{conf,conf.d,html,logs,ssl}

設定、静的ファイル、ログ、SSL 証明書——必要なものが一度に揃います。

ステップ 3:コンテナを起動し、すべてのディレクトリをマウント

ここが本番です。各 -v のパスマッピングに注目してください。

docker run -d --name my-nginx \
  -p 80:80 -p 443:443 \
  -v /opt/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
  -v /opt/nginx/conf.d:/etc/nginx/conf.d \
  -v /opt/nginx/html:/usr/share/nginx/html \
  -v /opt/nginx/logs:/var/log/nginx \
  -v /opt/nginx/ssl:/etc/nginx/ssl \
  nginx

ポイント:

  • -p 80:80 -p 443:443:HTTP と HTTPS の両ポートを公開(後で HTTPS を設定するため)
  • nginx.conf には :ro(読み取り専用)を付け、コンテナ内プロセスによる誤変更を防ぐ
  • conf.d はディレクトリごとマウント(単一ファイルではなく。理由は後述)

よく踏む 4 つの落とし穴

落とし穴 1:vim で編集するとコンテナ内に同期されない

私が最初にハマったパターンです。ホスト側の nginx.conf を編集してコンテナを再起動しても、反映されません。

原因:vim は保存時にファイルの inode を変えます。Docker のマウントは inode で紐づいているため、inode が変わるとコンテナ内は古いファイルのままになります。

対処法は 2 つ:

  • 案 A:nano など inode を変えないエディタを使う
  • 案 B:単一ファイルではなくディレクトリごとマウントする

今は案 B 一択です。ディレクトリマウントなら inode がどう変わっても追従し、設定ファイルの追加・削除も柔軟にできます。

落とし穴 2:include パスの設定ミス

コンテナ内で nginx.conf を確認しましょう。

docker exec -it my-nginx bash
cat /etc/nginx/nginx.conf | grep include

次の行があることを確認してください。

include /etc/nginx/conf.d/*.conf;

/opt/nginx/conf.d/*.conf(ホスト側パス)に書き換えてしまうと誤りです。コンテナ内ではコンテナ内のパスだけが有効です。

落とし穴 3:conf.d ディレクトリのマウント忘れ

nginx.conf だけマウントしても不十分です。ホスト側 conf.d に新しいサイト設定を追加しても、コンテナからは見えません。

確認方法:

docker exec my-nginx ls /etc/nginx/conf.d

ホスト側 /opt/nginx/conf.d のファイルがすべて表示されるはずです。

落とし穴 4:ファイル権限で Nginx が設定を読めない

Linux では起きやすい問題です。設定ファイルの権限が厳しすぎると、Nginx プロセス(通常 nginx ユーザー)が読み取れません。

対処:

chmod 644 /opt/nginx/conf/nginx.conf
chmod 644 /opt/nginx/conf.d/*.conf

設定変更後は、構文チェックを習慣にしましょう。

docker exec my-nginx nginx -t

syntax is ok と出れば安心です。

単一ファイルマウント vs ディレクトリマウント:どちらを選ぶ?

よく聞かれる質問です。私のおすすめは次のとおり。

メイン設定 nginx.conf:単一ファイル + 読み取り専用(:ro)で十分。頻繁には触らないから

conf.d ディレクトリ:必ずディレクトリマウント。サイト設定を柔軟に追加できる

html、logs:ディレクトリマウント。言うまでもなく

覚えておく原則:複数ファイルを柔軟に管理するならディレクトリマウント。コア設定をバージョン管理したいなら単一ファイル + 読み取り専用保護。

HTTPS 設定と Let’s Encrypt 自動更新

自己署名証明書:開発環境での素早い検証

本番では正規の証明書が必要ですが、開発・テストなら自己署名で十分。数コマンドで済みます。

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /opt/nginx/ssl/nginx.key \
  -out /opt/nginx/ssl/nginx.crt \
  -subj "/C=JP/ST=Tokyo/L=Tokyo/O=Dev/CN=localhost"

このコマンドで 2 つのファイルが生成されます。

  • nginx.key:秘密鍵。絶対に漏らさない
  • nginx.crt:証明書ファイル

次に /opt/nginx/conf.d/ssl.conf を作成します。

server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}

ポイント:

  • ssl_certificate のパスはコンテナ内(/etc/nginx/ssl)。ホスト側の /opt/nginx/ssl ではない
  • ssl_protocols は TLS 1.2 と 1.3 のみ。古いプロトコルには既知の脆弱性がある
  • 起動時に -p 443:443 を忘れずに。HTTPS ポートを公開しないとアクセスできない

設定をホットリロード:

docker exec my-nginx nginx -s reload

https://localhost にアクセスすると、ブラウザが証明書を信頼しないと警告を出します——正常な挙動です。自己署名証明書はそういうもの。「詳細設定から続行」で問題ありません。

Let’s Encrypt:本番環境の無料証明書

Let’s Encrypt は本当に便利です。無料、自動化、世界中で信頼される。唯一の「欠点」は 90 日で期限切れになること——自動更新を組めば気にしなくてよい。

ここでは docker-compose + certbot コンテナの構成を推奨します。手作業よりずっと確実です。

まず完全な docker-compose.yml を見てみましょう。

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: my-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/html:/usr/share/nginx/html
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
    networks:
      - web

  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
    networks:
      - web

networks:
  web:
    driver: bridge

重要なポイント:

1. 証明書と検証ファイルの共有マウント

  • ./certbot/conf を 2 つのコンテナにマウント。certbot が証明書を生成し、nginx が読み込む
  • ./certbot/www は Let’s Encrypt の HTTP 検証(webroot 方式)用

2. Nginx が 6 時間ごとに自動 reload

この command は複雑に見えますが、バックグラウンドで 6 時間ごとに reload するループを起動しているだけです。証明書更新後すぐ反映されます。

3. Certbot が 12 時間ごとに更新をチェック

Let’s Encrypt は 1 日 1 回のチェックを推奨していますが、12 時間にするとより安心です。

初回証明書取得の手順

HTTP 検証用に /opt/nginx/conf.d/ に一時設定 temp.conf を作成します。

server {
    listen 80;
    server_name your-domain.com;  # 自分のドメインに変更

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

サービスを起動:

docker-compose up -d

証明書を申請(your-domain.com と your@email.com を自分の値に置き換え):

docker-compose run --rm certbot certonly --webroot \
  -w /var/www/certbot \
  -d your-domain.com \
  --email your@email.com \
  --agree-tos \
  --no-eff-email

順調なら “Congratulations!” と表示されます。証明書は ./certbot/conf/live/your-domain.com/ にあります。

本番用 HTTPS 設定に更新します。temp.conf を次の内容に書き換えます。

server {
    listen 80;
    server_name your-domain.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # SSL 最適化設定
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_prefer_server_ciphers on;

    # HSTS(HTTPS 強制)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}

設定を reload:

docker-compose exec nginx nginx -s reload

自動更新の検証

Let’s Encrypt 証明書は 90 日有効ですが、certbot は残り 30 日で自動更新します。手動でテストできます。

docker-compose run --rm certbot renew --dry-run

“The dry run was successful” と出れば OK です。

cron ログで更新タスクの動作も確認できます。

docker-compose logs certbot

HTTPS 設定のセキュリティ強化

SSL 設定をより安全にするなら、次も追加できます。

# OCSP Stapling(オンライン証明書ステータス確認)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/your-domain.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# iframe 埋め込み禁止(クリックジャッキング対策)
add_header X-Frame-Options DENY;

# XSS 対策
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

設定後、SSL Labs で SSL 設定のスコアを確認できます。A+ も十分狙えます。

リバースプロキシと Docker コンテナ間通信

コンテナネットワークの基本

Nginx で他の Docker コンテナをプロキシするとき、いちばん面倒なのがネットワーク設定です。コンテナ IP を直接指定して、再起動のたびに IP が変わる——設定の書き直し地獄、経験ある人も多いでしょう。

Docker にはいくつかネットワークモードがありますが、よく使うのは次の 2 つ:

  • bridge(ブリッジ):デフォルト。仮想ブリッジ経由でコンテナ間通信
  • host:ホストのネットワークスタックを直接使用。性能は良いが隔離性は低い

Nginx リバースプロキシでは、カスタム bridge ネットワークを強く推奨します。理由は:

  1. コンテナ間でサービス名をそのまま使える。IP 変化を気にしなくてよい
  2. ネットワークで隔離。プロジェクトごとに独立した通信環境
  3. 自動 DNS 解決。Docker 組み込みのサービスディスカバリ

カスタムネットワークの作成とコンテナ起動

まずカスタムネットワークを作成:

docker network create my-app-network

バックエンドサービス(Node.js API と仮定)を起動:

docker run -d \
  --name backend-api \
  --network my-app-network \
  -e NODE_ENV=production \
  my-backend:latest

Nginx も同じネットワークに接続:

docker run -d \
  --name my-nginx \
  --network my-app-network \
  -p 80:80 -p 443:443 \
  -v /opt/nginx/conf.d:/etc/nginx/conf.d \
  nginx

ポイント:2 つのコンテナが同じネットワークにいれば、Nginx 設定で backend-api という名前でバックエンドにアクセスできます。

Nginx リバースプロキシ設定の実践

/opt/nginx/conf.d/api-proxy.conf を作成します。

upstream backend {
    server backend-api:3000;  # コンテナ名:ポート
    keepalive 32;
}

server {
    listen 80;
    server_name api.example.com;

    # API プロキシ
    location /api/ {
        proxy_pass http://backend/;

        # クライアント情報を転送
        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;

        # WebSocket 対応(必要な場合)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # タイムアウト設定
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 静的ファイルは Nginx が直接配信
    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
}

見落としがちな細部:

1. upstream と proxy_pass のパス処理

proxy_pass http://backend/; の末尾にスラッシュがあります。/api/usershttp://backend/users に転送され(/api プレフィックスが除去される)。

proxy_pass http://backend;(スラッシュなし)だと http://backend/api/users に転送され(パス全体が保持される)。

2. X-Forwarded-For ヘッダーの重要性

バックエンドが実クライアント IP を取得するにはこのヘッダーが必要です。設定しないと、バックエンドから見えるのは Nginx コンテナの IP だけになります。

3. keepalive コネクションプール

upstreamkeepalive 32 で TCP 接続を再利用し、ハンドシェイクのオーバーヘッドを削減できます。高並行シナリオで効果的です。

docker-compose で複数コンテナをまとめて管理

ネットワークを手動作成し、コンテナを 1 つずつ起動するのは面倒です。docker-compose なら一発です。

version: '3.8'

services:
  backend:
    image: my-backend:latest
    container_name: backend-api
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://db:5432/mydb
    networks:
      - app-network
    depends_on:
      - db

  nginx:
    image: nginx:latest
    container_name: my-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/html:/usr/share/nginx/html
      - ./nginx/logs:/var/log/nginx
    networks:
      - app-network
    depends_on:
      - backend

  db:
    image: postgres:14
    container_name: postgres-db
    environment:
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=mydb
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  db-data:

1 コマンドでスタック全体を起動:

docker-compose up -d

Docker が自動的に:

  • app-network という名前のネットワークを作成
  • depends_on の順序でコンテナを起動
  • コンテナ間 DNS 解決を設定

Nginx 設定では backenddb をホスト名としてそのまま使えます。とても楽です。

よくあるプロキシ問題の切り分け手順

問題 1:502 Bad Gateway

最も多いエラー。原因はだいたい次のいずれか:

  • バックエンドが起動していない、または落ちている
  • Nginx とバックエンドが同じネットワークにいない
  • バックエンドの待ち受けポートが違う

切り分け手順:

# バックエンドの稼働確認
docker ps | grep backend

# ネットワーク接続の確認
docker network inspect my-app-network

# Nginx コンテナから疎通テスト
docker exec -it my-nginx sh
ping backend-api
curl http://backend-api:3000/health

ping が通らなければネットワーク設定の問題。curl がタイムアウトならバックエンドの待ち受け設定を疑います。

問題 2:リクエストタイムアウト

デフォルトの proxy タイムアウトは 60 秒。大ファイルアップロードや重い処理など、API の処理時間が長い場合は延長が必要です。

location /api/long-running/ {
    proxy_pass http://backend/;
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
}

問題 3:POST リクエストボディが失われる

POST が GET になったり、ボディが空になることがあります。次の設定を確認してください。

location /api/ {
    proxy_pass http://backend/;
    proxy_request_buffering off;  # リクエストバッファリングを無効化
    client_max_body_size 100M;     # 大きなファイルアップロードを許可
}

複数バックエンドのロードバランシング

バックエンドが複数インスタンスなら、Nginx でロードバランシングできます。

upstream backend_cluster {
    least_conn;  # 最少接続アルゴリズム

    server backend-1:3000 weight=3;  # 重み 3
    server backend-2:3000 weight=1;  # 重み 1
    server backend-3:3000 backup;     # スタンバイサーバー

    keepalive 32;
}

server {
    listen 80;

    location /api/ {
        proxy_pass http://backend_cluster/;
        # ... その他の proxy 設定
    }
}

ロードバランシングアルゴリズム:

  • round-robin(デフォルト):ラウンドロビン
  • least_conn:接続数が最も少ないサーバーを優先
  • ip_hash:同一クライアント IP を常に同じサーバーへ

バックエンドが 1 台落ちても、Nginx は自動的に健全なノードへトラフィックを振り分けます。

本番環境のベストプラクティスとパフォーマンス最適化

設定ファイル管理:そのまま本番に置かない

設定ファイルをサーバーに直置きするのは開発環境のやり方。本番ではもう一段、きちんと管理しましょう。

Git で設定を管理

私は Nginx 設定専用のリポジトリを作り、環境ごとにディレクトリを分けています。メリットは明確:

  • 変更履歴が一目瞭然。ロールバックは git checkout だけ
  • チーム開発がしやすい。PR で設定変更をレビューできる
  • CI/CD と連携し、自動デプロイも可能

設定のテンプレート化

環境ごとに設定はほぼ同じで、差分はごく少数。テンプレート + 変数置換が効きます。デプロイ時に envsubst で変数を置き換えれば OK です。

ログ管理:ディスクが満杯になる前に

Nginx のログは書き込みが速い。高トラフィックサイトなら 1 日数 GB も珍しくありません。放置すると、ある日ディスクが満杯になってコンテナが停止します。

ログローテーション設定

ホスト側で logrotate を設定し、毎日ローテーション、14 日保持、古いログは自動圧縮。ローテーション後は Nginx にログファイルを開き直させる(nginx -s reopen)必要があります。しないと古いファイルに書き続けます。

集中ログの構成

サーバーが複数台なら、ログを集中管理基盤(ELK、Loki、クラウドサービス)へ送るのも手です。Docker ログドライバーや Promtail なら導入も簡単です。

グレースフル reload:ユーザーに気づかせない

設定変更後、docker restart は避けてください。再起動はすべての接続を切断し、処理中のリクエストも失われます。

正しい手順:

# まず構文チェック
docker exec my-nginx nginx -t

# 問題なければ reload
docker exec my-nginx nginx -s reload

reload はグレースフルリロード。新しい worker が新設定を読み込み、古い worker は処理中リクエストを完了してから終了——切り替え中もユーザーは気づきません。

セキュリティ強化チェックリスト

本番公開前に、次を確認してください。

1. Nginx バージョン番号を隠す

デフォルトではエラーページに Nginx バージョンが表示されます。既知の脆弱性を狙った攻撃に使われ得ます。http ブロックに server_tokens off; を追加して非表示に。

2. レート制限で DDoS 対策

シンプルで効果的な防御:

http {
    # IP ごとのリクエスト頻度制限
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    # 同時接続数制限
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}

server {
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        limit_conn conn_limit 10;
        proxy_pass http://backend/;
    }
}

3. 設定ファイルは読み取り専用マウント

メイン設定に :ro を付け、コンテナ内プロセスによる誤変更を防ぐ。

4. 最小権限の原則

nginx.conf に user nginx; があることを確認。root に変更するとセキュリティリスクが大幅に上がります。

パフォーマンスチューニング:Nginx の性能を引き出す

worker プロセス数の最適化

worker_processes auto;  # CPU コア数に自動合わせ
worker_cpu_affinity auto;  # CPU アフィニティを設定

auto は手間いらず。Nginx が CPU コア数を自動検出します。

接続数の最適化

events {
    worker_connections 2048;  # worker あたりの最大接続数
    use epoll;                # Linux では epoll が最も高速
}

理論上の最大同時接続:worker_processes * worker_connections。ただしファイルディスクリプタ上限(ulimit -n)も考慮が必要です。

gzip 圧縮

テキストコンテンツを圧縮すると転送量を 60〜80% 削減できます。

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;  # 圧縮レベル 1〜9、6 が性能と圧縮率のバランス点
    gzip_types
        text/plain
        text/css
        text/xml
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;
    gzip_min_length 1000;  # 1KB 未満は圧縮しない(CPU の無駄)
}

静的リソースのキャッシュ

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
    expires 30d;  # ブラウザキャッシュ 30 日
    add_header Cache-Control "public, immutable";
}

HTTP/2 対応

HTTP/2 は性能を大きく向上させます。有効化も簡単:

server {
    listen 443 ssl http2;  # http2 を追加するだけ
    # ... その他の設定
}

前提は HTTPS であること。HTTP/2 は TLS 上で動作します。

モニタリングとヘルスチェック

最後にモニタリングを忘れずに。Prometheus + Grafana と nginx-prometheus-exporter の組み合わせがおすすめです。Nginx 設定で stub_status を有効化し、Docker 内部ネットワークからのみアクセス可能に制限。Prometheus で metrics を取得し、Grafana でダッシュボードを表示します。

まとめ

ここまでの要点を 4 つに整理します。

設定ファイルのマウント:単一ファイルよりディレクトリマウント。メイン設定は読み取り専用で保護。conf.d と ssl ディレクトリを忘れない。vim の inode 問題にも注意。

HTTPS 設定:開発は自己署名で素早く検証、本番は Let’s Encrypt + Certbot で自動化。docker-compose なら更新もほぼお任せ。

リバースプロキシ:カスタム bridge ネットワークが基本。コンテナ名で通信すれば IP 変更を気にしなくてよい。upstream に keepalive を足せば性能と信頼性が向上。

本番運用:Git で設定をバージョン管理、ログローテーションを忘れず、restart ではなく graceful reload。必要なセキュリティ対策は漏れなく。

Docker Nginx はシンプルに見えて細部が多い。ここまで押さえれば、開発から本番まで安定した Web サービス構成を組み立てられます。

本記事でいくつかの落とし穴を避けられたり、長く悩んでいた問題が解けたなら、執筆の甲斐がありました。ぜひ手を動かしてみてください。困ったことがあれば、コメントで気軽にどうぞ。

最後のアドバイス:本記事の設定テンプレートを保存しておき、次回から再利用しましょう。同じ車輪を何度も作る必要はありません。

Docker で Nginx を構築する完全フロー

設定ファイルのマウント、HTTPS 設定、リバースプロキシの実践。設定が反映されない問題やコンテナ間通信のトラブルを解決

⏱️ 目安時間: 1 時間

  1. 1

    ステップ1: 設定ファイルのマウント:5 つの正しい方法

    5 つの正しいマウント方法:
    • 設定ファイルをマウント:-v ./nginx.conf:/etc/nginx/nginx.conf
    • 設定ディレクトリをマウント:-v ./conf.d:/etc/nginx/conf.d
    • Volume を使う
    • docker-compose で設定
    • ConfigMap(K8s 環境)

    よくある問題:
    • 設定を変更しても反映されない。nginx.conf を書き換えたのにコンテナ内が古いまま
    • -v で設定ディレクトリを正しくマウントする
    • 設定ファイルの形式が正しいか確認

    ベストプラクティス:
    • 単一ファイルよりディレクトリマウント
    • メイン設定は読み取り専用で保護
    • conf.d と ssl ディレクトリを忘れない
    • vim の inode 問題に注意
  2. 2

    ステップ2: HTTPS 設定と Let's Encrypt 自動更新

    HTTPS 設定:
    • Let's Encrypt の無料証明書を使う
    • 自動更新:certbot renew
    • 証明書ディレクトリをマウント:-v ./certs:/etc/nginx/certs
    • SSL 証明書パスを設定
    • HTTP/2 と TLS 1.3 に対応

    Let's Encrypt 設定:
    • certbot で証明書取得:certbot certonly --standalone
    • 自動更新のテスト:certbot renew --dry-run
    • 証明書をコンテナにマウント:-v ./letsencrypt:/etc/letsencrypt
    • nginx.conf で証明書を参照
  3. 3

    ステップ3: リバースプロキシ設定と本番環境のベストプラクティス

    リバースプロキシ設定:
    • upstream でバックエンドコンテナを指定
    • コンテナ名やサービス名を使う:proxy_pass http://backend:8080
    • ヘルスチェックを設定
    • CORS 問題への対処
    • ロードバランシング

    本番環境のベストプラクティス:
    • docker-compose で複数コンテナを管理
    • ヘルスチェックを設定
    • リソース制限を設定
    • ログローテーション
    • 環境変数で設定を管理
    • イメージを定期的に更新

    Docker Nginx はシンプルに見えて細部が多いが、ここまで押さえれば開発から本番まで安定した Web サービス構成を組み立てられる。

FAQ

Docker Nginx の設定ファイルを変更しても反映されないのはなぜ?
よくある問題:設定を変更しても反映されない。nginx.conf を書き換えたのにコンテナ内が古いまま。正しくマウントするには -v で設定ディレクトリをマウントし、設定ファイルの形式も確認する。

5 つの正しいマウント方法:
1) 設定ファイルをマウント:-v ./nginx.conf:/etc/nginx/nginx.conf
2) 設定ディレクトリをマウント:-v ./conf.d:/etc/nginx/conf.d
3) Volume を使う
4) docker-compose で設定
5) ConfigMap(K8s 環境)

ベストプラクティス:
• 単一ファイルよりディレクトリマウント
• メイン設定は読み取り専用で保護
• conf.d と ssl ディレクトリを忘れない
• vim の inode 問題に注意
Docker Nginx の HTTPS はどう設定する?
HTTPS 設定:
• Let's Encrypt の無料証明書を使う
• 自動更新:certbot renew
• 証明書ディレクトリをマウント:-v ./certs:/etc/nginx/certs
• SSL 証明書パスを設定
• HTTP/2 と TLS 1.3 に対応

Let's Encrypt 設定:
• certbot で証明書取得:certbot certonly --standalone
• 自動更新のテスト:certbot renew --dry-run
• 証明書をコンテナにマウント:-v ./letsencrypt:/etc/letsencrypt
• nginx.conf で証明書を参照
Docker Nginx のリバースプロキシはどう設定する?
リバースプロキシ設定:
• upstream でバックエンドコンテナを指定
• コンテナ名やサービス名を使う:proxy_pass http://backend:8080
• ヘルスチェックを設定
• CORS 問題への対処
• ロードバランシング

コンテナ間通信:
• docker-compose でカスタムネットワークを作成
• コンテナを同じネットワークに置く
• サービス名やコンテナ名でアクセス
• upstream でバックエンドサービスを指定
Docker Nginx の本番環境ベストプラクティスは?
本番環境のベストプラクティス:
• docker-compose で複数コンテナを管理
• ヘルスチェックを設定
• リソース制限を設定
• ログローテーション
• 環境変数で設定を管理
• イメージを定期的に更新

Docker Nginx はシンプルに見えて細部が多いが、ここまで押さえれば開発から本番まで安定した Web サービス構成を組み立てられる。

アドバイス:本記事の設定テンプレートを保存しておき、次回から再利用しよう。

6分で読めます · 公開日: 2025年12月18日 · 更新日: 2026年6月8日

関連記事

コメント

GitHubアカウントでログインしてコメントできます