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

DockerでNginx構築完全ガイド:設定ファイルのマウントからHTTPS化まで

はじめに

深夜1時、端末で docker restart nginx を7回叩いた後も、ブラウザには無情な「502 Bad Gateway」が表示されていました。
「設定ファイルは間違いなく書き換えたはずなのに、なぜ?」
Docker移行当初、Nginxの設定反映には本当に悩まされました。

DockerでNginxを扱う場合、ただ docker run するだけでは不十分です。設定ファイルの正しいマウント方法、SSL証明書の管理、コンテナ間の通信——これらには「Dockerならではの作法」があります。

この記事では、私が数々の失敗から学んだ**「Docker Nginxのベストプラクティス」**を共有します。設定ファイルが反映されない理由から、Let’s Encryptによる全自動HTTPS化、そして実用的なリバースプロキシ構成まで、現場で即使えるノウハウを詰め込みました。

基礎:設定ファイルを正しくマウントする

なぜイメージに焼き込まず、マウントするのか?

設定ファイルをDockerイメージの中に COPY してしまう方法もありますが、開発中は推奨しません。
設定を1行変えるたびにビルドし直すのは時間の無駄ですし、本番環境で急な設定変更が必要になった時、即座に対応できないからです。また、設定とコード(イメージ)は分離すべきです。

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

まずはコンテナ内のどのファイルを上書きすべきかを知りましょう。

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

nginx.conf には通常 include /etc/nginx/conf.d/*.conf; と書かれており、conf.d 以下のファイルを読み込むようになっています。

【重要】正しいマウント手順

ステップ1:デフォルト設定をコピーする
いきなり空のファイルを作ると失敗します。まずはコンテナ内のデフォルト設定を取り出しましょう。

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

# 設定ファイルをホスト側にコピー
mkdir -p ./nginx/conf
docker cp nginx-temp:/etc/nginx/nginx.conf ./nginx/conf/nginx.conf
docker cp nginx-temp:/etc/nginx/conf.d ./nginx/conf/conf.d

# 用済みなので削除
docker stop nginx-temp && docker rm nginx-temp

ステップ2:docker run でディレクトリごとマウント

ここで最大のポイントです。単一ファイルではなく、ディレクトリをマウントすることをお勧めします。

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

なぜディレクトリマウントなのか?(Vimユーザーへの警告)
LinuxでVimなどのエディタを使ってファイルを保存すると、実は「上書き」ではなく「新しいファイル(新しいinode)への置き換え」が行われることがあります。Dockerの単一ファイルマウントはinode(ファイルの物理的な場所)を監視しているため、inodeが変わるとリンク切れのような状態になり、ホスト側で編集してもコンテナ側に反映されなくなります
ディレクトリマウントにすれば、フォルダの中身がどう変わろうと追従してくれるため、このトラブルを回避できます。

実践:HTTPS化(Let’s Encrypt自動更新)

本番環境にHTTPSは必須です。Certbot コンテナと連携させて、無料証明書(Let’s Encrypt)を自動取得・自動更新する構成を作りましょう。

Docker Compose構成例

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: my-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    # Nginxを6時間ごとにリロード(証明書更新を反映するため)
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    # 12時間ごとに更新チェック
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

この構成のミソは、証明書ディレクトリを2つのコンテナで共有している点です。Certbotが更新したファイルを、Nginxが読み込みます。

最初の証明書取得手順

  1. Nginxの設定(conf.d/default.conf)に、認証用パスを通します。
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
  2. docker-compose up -d で起動。
  3. Certbotを実行して証明書を取得。
    docker-compose run --rm certbot certonly --webroot --webroot-path /var/www/certbot -d yourdomain.com
  4. Nginxの設定を書き換え、HTTPSを有効化してリロードします。

応用:コンテナ間のリバースプロキシ

Nginxを「入口」として、背後のAPIサーバー(Node.jsやPython等)にリクエストを振り分ける構成です。

Dockerのカスタムネットワーク機能を使うと、IPアドレスではなくコンテナ名で通信できます。これが非常に便利です。

手順

  1. ネットワークを作成:
    docker network create my-app-net

  2. 両方のコンテナを同じネットワークに入れる:

    # バックエンド
    docker run -d --name my-api --network my-app-net my-api-image
    
    # Nginx
    docker run -d --name nginx --network my-app-net -p 80:80 ... nginx
  3. Nginx設定(conf.d/api.conf):

    server {
        listen 80;
        server_name api.example.com;
    
        location / {
            # コンテナ名「my-api」がそのままドメインとして使える!
            proxy_pass http://my-api:3000;
            
            # クライアントのIPを正しく伝えるためのヘッダー
            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_pass http://my-api:3000; のように、Dockerのサービス名をホスト名として記述できるのがポイントです。IPアドレスを調べる必要はありません。

まとめ

DockerでNginxを使いこなすための3つの鉄則:

  1. ディレクトリマウント:設定ファイルの編集トラブルを避けるために、親フォルダごとマウントする。
  2. Certbot連携:専用コンテナとボリューム共有を使って、HTTPS更新を自動化する。
  3. コンテナ名通信:Dockerネットワークを活用し、設定ファイルにはIPではなくコンテナ名を記述する。

これらを守れば、Nginxコンテナはあなたのインフラの強力なゲートウェイになります。

Docker Nginx構築フロー

設定マウントからHTTPS、リバースプロキシ設定まで

⏱️ Estimated time: 20 min

  1. 1

    Step1: ステップ1:設定ファイルの抽出

    一時コンテナを起動し、docker cp コマンドでデフォルトの nginx.conf と conf.d をホスト側にコピーします。これが運用のベースになります。
  2. 2

    Step2: ステップ2:ディレクトリマウントで起動

    docker run時に -v ./nginx/conf.d:/etc/nginx/conf.d のようにディレクトリ単位でマウントします。これによりファイルの追加や編集が即座に反映されます。
  3. 3

    Step3: ステップ3:HTTPS化(Certbot)

    CertbotコンテナとWebrootディレクトリを共有し、Let's Encrypt証明書を取得します。定期実行スクリプトで自動更新も設定します。
  4. 4

    Step4: ステップ4:リバースプロキシ設定

    同じDockerネットワーク内のアプリコンテナに対し、proxy_pass http://container-name:port; を設定します。コンテナ名での名前解決を活用しましょう。

FAQ

設定ファイルを変更したのにnginx -tが通らない、または反映されません。
Vimなどのエディタで単一ファイルを編集するとinodeが変更され、Dockerのマウントリンクが切れることがあります。コンテナを再起動するか、ディレクトリごとマウントする方式に切り替えてください。
バックエンドのコンテナに接続できません(502エラー)。
Nginxとバックエンドコンテナが同じDockerネットワークに属しているか確認してください(`docker network inspect`)。また、proxy_passには「localhost」ではなく「コンテナ名」を指定する必要があります。
クライアントのIPアドレスがDockerゲートウェイのIPになってしまいます。
リバースプロキシ設定で `proxy_set_header X-Real-IP $remote_addr;` などのヘッダー転送設定を追加してください。また、バックエンドアプリ側でもこれらのヘッダーを信頼する設定(例:Express.jsなら `app.set('trust proxy', true)`)が必要です。

3 min read · 公開日: 2025年12月18日 · 更新日: 2026年1月22日

コメント

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

関連記事