【Docker】Nginxローカル開発環境構築完全ガイド|6用途別nginx.conf・SPA/WebSocket/リバプロ・mkcert HTTPS・nginx-proxy

Docker

Nginxは静的配信・リバースプロキシ・ロードバランサ・API gatewayとして本番サーバーで圧倒的シェアを持つWebサーバーです。ローカル開発でDocker + Nginxを組み合わせれば、本番構成をそのまま手元で再現でき、「本番だけで出るバグ」を激減させられます。

多くの入門記事は「静的ファイルを配信するだけ」で終わっていますが、実戦ではSPA(React/Vue/Next.js)のHistory APIフォールバックNode.js/Python/GoバックエンドへのリバースプロキシとWebSocket対応ローカルHTTPS(mkcert)gzip/brotli圧縮複数プロジェクト自動ルーティング(nginx-proxy)キャッシュ・レートリミット・セキュリティヘッダーまで幅広く必要になります。

この記事では、Docker × Nginxの基礎から6つの典型用途パターン別にnginx.confレシピを完全収録し、ローカルHTTPS対応・開発サーバー(Vite/webpack-dev-server)連携・パフォーマンス最適化・セキュリティヘッダー・マルチプロジェクト運用まで、2026年の現場で即使える完全ガイドとしてまとめます。Nginx + PHP-FPM特化の構築は【Docker】Nginx + PHP-FPMの環境をComposeで構築する手順、WordPress特化は【Docker】WordPress環境構築完全ガイドで別途扱っています。

この記事で学べること

  • Nginx × Dockerの6用途マトリクス(静的/SPA/リバプロ/WebSocket/ロードバランサ/API gateway)
  • 30秒で動く最小compose.yml+nginx.conf
  • SPAのHistory APIフォールバック(React/Vue/Nuxt等)
  • Node.js/Python/Go バックエンドへのリバースプロキシ
  • WebSocket対応(Upgrade/Connectionヘッダー)
  • upstreamでロードバランシング(複数インスタンス)
  • ローカルHTTPS(mkcertでTLS証明書)とHTTP/2有効化
  • 開発サーバー(Vite・webpack-dev-server)のHMR透過プロキシ
  • gzip/brotli圧縮とproxy_cacheレスポンスキャッシュ
  • セキュリティヘッダー(CSP/X-Frame-Options/HSTS)
  • 複数プロジェクト自動ルーティング(nginx-proxy
  • Nginx vs Caddy vs Traefik の選定フレーム
スポンサーリンク

30秒クイックスタート:最小構成

ディレクトリ構成
project/
├─ compose.yml
├─ nginx/
│   └─ default.conf
└─ src/
    └─ index.html
compose.yml(最小)
services:
  nginx:
    image: nginx:1.27-alpine
    ports: ["8080:80"]
    volumes:
      - ./src:/usr/share/nginx/html:ro
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    restart: unless-stopped
nginx/default.conf
server {
  listen 80;
  server_name localhost;

  root /usr/share/nginx/html;
  index index.html;

  location / {
    try_files $uri $uri/ =404;
  }
}
起動
docker compose up -d
# http://localhost:8080 で確認

docker compose down

2026年の推奨イメージ:nginx:1.27-alpine(軽量で高速、脆弱性対応も迅速)。nginx:latestは意図せずバージョン変更されるため、本番でも使うならマイナー固定が安全。version:キーは不要(ComposeV2以降)。

Nginxの6用途マトリクス:どのパターンで使うか

Nginxは単なる静的Webサーバーではなく、用途によって設定が大きく変わります。まず「自分の使い方」を特定することが最速の入り口です。

用途 主な設定 代表シーン
① 静的ファイル配信 root + try_files HTML/CSS/JS/LPサイト
② SPAフォールバック try_files $uri /index.html React Router/Vue Router/Nuxt SPA
③ リバースプロキシ proxy_pass Node.js/Python/Go等のAPIへ転送
④ WebSocketプロキシ Upgrade/Connectionヘッダー転送 Socket.IO/GraphQL Subscriptions
⑤ ロードバランサ upstream+weight/ip_hash 複数インスタンス分散
⑥ API gateway locationでパス別にproxy_pass /api → service A、/auth → service B

複数用途を混ぜるのが現代の典型

実案件では①静的(CDN的)+②SPA+③APIリバプロ+④WebSocketを1つのNginxで同時に扱うことが普通です。後述の完全版nginx.confではこれをlocationごとに切り分けて実装します。

パターン①:静的ファイル配信+パフォーマンス最適化

静的配信の実用的なdefault.conf
server {
  listen 80;
  server_name localhost;

  root /usr/share/nginx/html;
  index index.html;

  # 文字コード明示(日本語サイトで重要)
  charset utf-8;

  # gzip圧縮(全レスポンス高速化)
  gzip on;
  gzip_vary on;
  gzip_types text/plain text/css text/javascript application/json application/javascript application/xml+rss image/svg+xml;
  gzip_min_length 1024;
  gzip_comp_level 6;

  # 長期キャッシュ(ハッシュ付きアセットにおすすめ)
  location ~* \.(?:css|js|woff2?|ttf|otf|eot|ico|png|jpg|jpeg|gif|webp|avif|svg)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    try_files $uri =404;
  }

  # HTMLは毎回fetch(誤キャッシュ対策)
  location ~* \.html$ {
    expires -1;
    add_header Cache-Control "no-cache, must-revalidate";
    try_files $uri =404;
  }

  location / {
    try_files $uri $uri/ =404;
  }
}

gzipとbrotliの使い分け

2026年時点ではbrotliがgzipより10〜20%小さくなるためモダンブラウザ向けに推奨。公式nginxイメージはbrotli未対応のため、nginx:mainline-otelghcr.io/nginxinc/nginx-unprivileged、または自前ビルドDockerfilengx_brotliモジュールを組み込むか、CDN側で圧縮(CloudFront/Cloudflare)する方が現実的です。

パターン②:SPA(React/Vue/Nuxt)のHistory APIフォールバック

SPAでブラウザの直接リロードや/users/42のような深いURLへ直アクセスすると404エラーが出るのがNginxでの定番つまづき。try_filesindex.htmlにフォールバックさせるのが解決策です。

SPA向けdefault.conf
server {
  listen 80;
  server_name localhost;

  root /usr/share/nginx/html;
  index index.html;

  # アセットは長期キャッシュ
  location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
  }

  # SPAフォールバック:存在しないパスはindex.htmlに返す
  location / {
    try_files $uri $uri/ /index.html;
  }

  # HTMLはキャッシュさせない(新バージョン即反映)
  location = /index.html {
    expires -1;
    add_header Cache-Control "no-store, must-revalidate";
  }
}

Vite/React/Nuxtビルド出力をNginxに載せる

マルチステージDockerfile
# ビルドステージ
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 配信ステージ
FROM nginx:1.27-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

Vite/Reactはdist/、Nuxt 3 SSGは.output/public/、Next.js SSGはout/が成果物。npm run buildした出力をCOPY --from=builder /app/<出力先>でNginx配信用ディレクトリに置くのが定石です。

パターン③:Node.js/Python/GoバックエンドへのリバースプロキシとDocker Compose連携

実開発で最も使用頻度が高いのがこのパターン。フロント(静的/SPA)とバックエンド(API)を1つのNginxで束ね、CORS問題も同一オリジンで解決します。

compose.yml(Nginx + Node.js API)
services:
  nginx:
    image: nginx:1.27-alpine
    ports: ["8080:80"]
    volumes:
      - ./frontend/dist:/usr/share/nginx/html:ro
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - api
    networks: [app-net]

  api:
    build: ./backend
    expose: ["3000"]       # 外部公開しない、nginx経由のみ
    environment:
      NODE_ENV: development
    volumes:
      - ./backend:/app
      - /app/node_modules
    command: npm run dev
    networks: [app-net]

networks:
  app-net:
default.conf(リバプロ + 静的 + SPA)
upstream api_backend {
  server api:3000;           # Docker内部DNSで解決
  keepalive 32;               # 接続再利用で高速化
}

server {
  listen 80;
  server_name localhost;

  root /usr/share/nginx/html;

  # /api/ パスはNode.jsへ転送
  location /api/ {
    proxy_pass http://api_backend/;   # 末尾/で/api/を剥がす
    proxy_http_version 1.1;
    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;

    # 長時間接続のタイムアウト緩和
    proxy_connect_timeout 30s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;

    # keepalive
    proxy_set_header Connection "";
  }

  # その他はSPAフォールバック
  location / {
    try_files $uri $uri/ /index.html;
  }
}

proxy_passの末尾スラッシュに注意:proxy_pass http://api_backend/;(末尾/あり)は/api/を剥がして転送。proxy_pass http://api_backend;(なし)は/api/のまま転送。この違いでバックエンド側のルート定義と一致しなくて404、という罠がよく起きます。

パターン④:WebSocket対応(Socket.IO / GraphQL Subscriptions)

WebSocketはHTTP/1.1のUpgradeヘッダーで接続を昇格させる仕組みです。Nginxを素通りさせるためにはConnectionUpgradeヘッダーを明示的に転送する必要があります。

WebSocketプロキシの設定
# http {} または server {} の外でも定義可能
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

upstream ws_backend {
  server api:3000;
}

server {
  listen 80;

  # WebSocketエンドポイント
  location /ws/ {
    proxy_pass http://ws_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    # WebSocket特有の長時間接続
    proxy_read_timeout 86400s;   # 1日
    proxy_send_timeout 86400s;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }

  # Socket.IOのfallback(long polling)
  location /socket.io/ {
    proxy_pass http://ws_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Host $host;
  }
}

WebSocket疎通確認

ブラウザDevToolsのNetworkタブで“WS”フィルタし、ステータスが101 Switching Protocolsになっていれば成功。426 Upgrade Required502が出るのはUpgradeヘッダー転送漏れが典型的。

パターン⑤:upstreamでロードバランシング

Nginxのupstreamディレクティブで複数バックエンドへの負荷分散が可能です。ローカル開発でも同時起動で水平スケールを試すのに使えます。

compose.yml(複数APIインスタンス)
services:
  nginx:
    image: nginx:1.27-alpine
    ports: ["8080:80"]
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    networks: [app-net]

  api:
    build: ./backend
    deploy:
      replicas: 3          # 3インスタンス
    expose: ["3000"]
    networks: [app-net]

networks:
  app-net:
upstream分散アルゴリズム
# ラウンドロビン(デフォルト)
upstream api_backend {
  server api:3000;                    # Compose内部DNSで3インスタンスに自動分散
}

# 重み付け
upstream api_backend {
  server api1:3000 weight=3;
  server api2:3000 weight=1;
  server api3:3000 backup;             # 他全滅時のみ使用
}

# IPハッシュ(セッション固定)
upstream api_backend {
  ip_hash;
  server api1:3000;
  server api2:3000;
}

# 最小接続数
upstream api_backend {
  least_conn;
  server api1:3000;
  server api2:3000;
}

# ヘルスチェック付き(passive)
upstream api_backend {
  server api1:3000 max_fails=3 fail_timeout=30s;
  server api2:3000 max_fails=3 fail_timeout=30s;
}

パターン⑥:API gateway構成(マイクロサービス統合)

複数のマイクロサービスをlocationごとにproxy_passすることで統合エンドポイントを作れます。CORSを気にせず同一オリジンでアクセス可能。

マルチサービス統合のconf
upstream auth_service    { server auth:4000; }
upstream user_service    { server users:5000; }
upstream order_service   { server orders:6000; }
upstream frontend        { server web:3000; }

server {
  listen 80;

  # 認証API
  location /api/auth/ {
    proxy_pass http://auth_service/;
    include /etc/nginx/snippets/proxy.conf;
  }

  # ユーザーAPI
  location /api/users/ {
    proxy_pass http://user_service/;
    include /etc/nginx/snippets/proxy.conf;
  }

  # 注文API
  location /api/orders/ {
    proxy_pass http://order_service/;
    include /etc/nginx/snippets/proxy.conf;
  }

  # フロント(Next.jsなど、SSR前提)
  location / {
    proxy_pass http://frontend;
    include /etc/nginx/snippets/proxy.conf;
  }
}
snippets/proxy.conf(共通proxy設定)
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_connect_timeout 30s;
proxy_read_timeout 60s;

snippetsパターン:共通のproxy設定を別ファイルに切り出してincludeで読み込むと、設定の重複を避けられます。新規serviceを足すたびに5〜10行コピペしていた人はぜひ。

Vite/webpack-dev-serverとNginxのHMR連携

開発サーバーのホットリロード(HMR)はWebSocket経由のため、NginxでSPA構成するときはHMR配信をそのまま透過転送するだけで動きます。本番ビルドと同じ構成をローカルで試せるのが最大のメリット。

dev用compose.yml
services:
  nginx:
    image: nginx:1.27-alpine
    ports: ["8080:80"]
    volumes:
      - ./nginx/dev.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - web
    networks: [app-net]

  web:
    image: node:20-alpine
    working_dir: /app
    volumes:
      - .:/app
    command: npm run dev -- --host 0.0.0.0
    expose: ["5173"]       # Viteの既定
    networks: [app-net]

  api:
    build: ./backend
    expose: ["3000"]
    networks: [app-net]

networks:
  app-net:
dev.conf(HMRと API統合)
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

upstream vite_dev { server web:5173; }
upstream api_dev  { server api:3000; }

server {
  listen 80;

  location /api/ {
    proxy_pass http://api_dev/;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
  }

  # Viteのdev serverへ全て転送(HMR WebSocket含む)
  location / {
    proxy_pass http://vite_dev;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Host $host;
  }
}

Viteはvite.config.tsserver.hmr.clientPort: 8080の設定が必要になる場合があります。HMRが効かない時はDevToolsのWSタブで接続先ポートを確認し、Vite側のhmr設定を調整してください。

ローカルHTTPS:mkcertでHTTP/2 + SSL

OAuth認証/Stripe/Service Worker/セキュアCookie(SameSite=None)などはHTTPS必須。mkcertで信頼済み証明書を作ってNginxに載せると数分で対応できます。

mkcertで証明書作成
# mkcertインストール(macOS)
brew install mkcert
mkcert -install    # ローカルCAインストール(初回のみ)

# 証明書発行
mkdir -p certs
mkcert -key-file ./certs/local.key -cert-file ./certs/local.crt \
  local.dev app.local.dev localhost 127.0.0.1
compose.yml(HTTPS対応)
services:
  nginx:
    image: nginx:1.27-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/https.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs:/etc/nginx/certs:ro
https.conf(HTTP/2 + SSL)
# HTTPはリダイレクト
server {
  listen 80;
  server_name local.dev;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  http2 on;                              # Nginx 1.25.1+はhttp2 on;構文
  server_name local.dev;

  ssl_certificate     /etc/nginx/certs/local.crt;
  ssl_certificate_key /etc/nginx/certs/local.key;

  # モダンなTLS設定
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers off;
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:10m;

  # 静的/SPAなど既存locationをここに
  root /usr/share/nginx/html;
  location / {
    try_files $uri $uri/ /index.html;
  }
}
hostsに追加
# /etc/hosts (macOS/Linux) or C:\Windows\System32\drivers\etc\hosts
127.0.0.1   local.dev app.local.dev

# 起動後
# → https://local.dev/ に鍵マーク付きでアクセス成功

Nginx 1.25.1以降のhttp2構文変更

旧来のlisten 443 ssl http2;は非推奨になり、http2 on;ディレクティブが推奨に。警告が出る場合は新構文に書き換えを。

nginx-proxyで複数プロジェクト自動ルーティング

フリーランスや複数案件を並行管理する人にはnginx-proxyが神機能。Docker Socketを監視してVIRTUAL_HOST環境変数を持つコンテナを自動で配信対象に追加します。

共通proxy/compose.yml
# proxy/compose.yml
services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./certs:/etc/nginx/certs:ro
    networks: [proxy-net]

networks:
  proxy-net:
各プロジェクトの設定
# projects/siteA/compose.yml
services:
  web:
    image: nginx:1.27-alpine
    environment:
      VIRTUAL_HOST: sitea.localhost
      VIRTUAL_PORT: 80
      HTTPS_METHOD: noredirect
    volumes:
      - ./dist:/usr/share/nginx/html:ro
    networks: [proxy-net]

networks:
  proxy-net:
    external: true
    name: proxy_proxy-net
起動
# 共通プロキシを1回だけ起動
docker compose -f proxy/compose.yml up -d

# 各プロジェクト追加
docker compose -f projects/siteA/compose.yml up -d
docker compose -f projects/siteB/compose.yml up -d

# hostsに追加すればブラウザでアクセス可能
# 127.0.0.1   sitea.localhost siteb.localhost

nginxproxy/acme-companionを追加すれば、VIRTUAL_HOSTに応じてLet’s Encrypt証明書を自動取得・更新してくれます。本番でも使える構成で、ステージング/本番の切替がほぼ同じ設定で完結。

セキュリティヘッダーの基本セット

ローカル開発でも本番と同じセキュリティヘッダーを付けておくと、「本番で急に動かなくなる」を防げます。

security-headers.conf
# /etc/nginx/snippets/security-headers.conf

# XSS対策(モダンブラウザはCSPを使う)
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;

# HTTPS運用時
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

# 最低限のCSP(実際はプロジェクト固有に)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self';" always;
serverブロックで読み込み
server {
  listen 443 ssl;
  http2 on;

  # ... 他の設定

  include /etc/nginx/snippets/security-headers.conf;

  location / {
    try_files $uri $uri/ /index.html;
  }
}

Content-Security-Policy本番リリース前に必ずプロジェクト固有に調整。広告SDK・アナリティクス・外部フォント(Google Fonts)などがscript-srcstyle-srcに追加必要です。ブラウザDevToolsのConsoleでCSP違反が警告として出るので確認しながら調整。

Nginx vs Caddy vs Traefik:ローカル開発での選定

ツール 強み 弱み 向いているケース
Nginx 事実上の標準/本番実績/高速/柔軟 設定構文の学習コスト/SSL自動化は別ツール必要 本番と同構成にしたい/学習重視
Caddy SSL自動取得(Let’s Encrypt内蔵)/設定がシンプル 学習資料が少ない/本番実績は徐々に 個人開発/SSLが面倒なケース
Traefik Docker label駆動/SSL自動/ダッシュボード 素のHTTPサーバー機能は弱い/Kubernetes向き マイクロサービス/docker自動発見

まずNginxを学ぶべき理由

2026年の時点でもWebサーバーシェア&案件需要でNginxが圧倒的。Caddyは個人開発で便利、TraefikはK8sで真価を発揮しますが、企業Web開発の現場ではNginxの設定が書けるかどうかがそのまま開発力の差になります。「最初の1本」はNginxを推奨。

よくあるトラブルと対処

①設定変更が反映されない

設定テスト+リロード
# 設定テスト(構文エラーチェック)
docker compose exec nginx nginx -t

# リロード(ゼロダウンタイム)
docker compose exec nginx nginx -s reload

# 完全再起動(reloadで反映されない場合)
docker compose restart nginx

②502 Bad Gateway

バックエンドに接続できないエラー。原因の定番は①upstreamのホスト名/ポートがcomposeのservice名と一致していない、②バックエンドがまだ起動完了していない、③Docker networkが別(networksセクションの設定漏れ)。docker compose logs nginxconnect() failedの詳細を確認。

③413 Request Entity Too Large

アップロード上限の引き上げ
http {
  client_max_body_size 128M;   # アップロードサイズ上限
}

# serverまたはlocationでも設定可能
server {
  client_max_body_size 128M;
  ...
}

④Windowsでファイルマウントが遅い

Windows(Docker Desktop)でbind mount経由のファイル読み込みは遅い場合があります。対処:①WSL2側のファイルシステムに置く(\\wsl$\Ubuntu\home\以下)、②named volumeにビルド成果物を置く、③OrbStack(Mac)/Rancher Desktopなど代替へ乗り換え。

⑤ログが見たい

ログ確認と設定
# リアルタイム追跡
docker compose logs -f nginx

# access.log/error.logを詳細化(nginx.conf)
http {
  log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

  access_log /var/log/nginx/access.log main;
  error_log  /var/log/nginx/error.log warn;
}

⑥CORSエラー

リバースプロキシ経由(/apiを同一オリジンで提供)ならCORSは発生しません。それでも必要ならlocation内にadd_header "Access-Control-Allow-Origin" "https://example.com";等を追加。プリフライト対応はOPTIONSメソッドでreturn 204する必要があります。

よくある質問

Qnginx:latest と nginx:1.27-alpine どちらを使う?
A1.27-alpine推奨。latestは意図せずバージョンが変わるため本番と齟齬が出やすい。alpine版は軽量で脆弱性対応も迅速。マイナーバージョン固定(1.27)にするとセキュリティパッチはビルド時に自動更新されて安全です。
QNginx単体でHTTPSを動かすには?
ALet’s Encrypt+certbotが定番ですが、Docker ComposeなしでTSL設定を自力で書くのは煩雑。ローカル開発ならmkcertで十分、本番はcertbot-nginxnginx-proxy + acme-companionが楽です。詳しくは本記事「ローカルHTTPS」セクションや【Docker】WordPress環境構築完全ガイドのmkcert部分を参照。
QSPAで直リロードが404になる
ASPAはクライアントサイドルーティングなのに対し、Nginxはファイルシステム上の実ファイルを探しに行くため。try_files $uri $uri/ /index.html;location /に書けば解決。本記事「パターン②:SPA」セクション参照。
Qcompose内でproxy_passのホスト名は何を書く?
Acompose.ymlで定義したサービス名をそのまま使えます。Docker ComposeがサービスのDNS解決を自動でやってくれるため、proxy_pass http://api:3000;のように書けばOK。IPアドレス直書きは不要かつアンチパターンです。
QWebSocketが502になる
AUpgrade/Connectionヘッダーの転送漏れが99%。proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade;を必ず設定し、mapディレクティブで$connection_upgradeを定義してください。本記事「パターン④」参照。
Qnginx.confの変更後、再起動せずに反映させたい
Adocker compose exec nginx nginx -s reloadゼロダウンタイムリロード可能。Nginxはマスタープロセスが古いworkerを安全に終了させ、新workerに引き継ぐ仕組み。本番でも使えるテクニック。リロード前はnginx -tで構文チェックを忘れずに。
Qupstreamとserverディレクティブ、どう使い分ける?
Aupstreamバックエンドサーバーのグループ定義(複数サーバー、重み、ip_hash等)、server受信するHTTPサーバーの定義(ポート、server_name、location)。upstreamで定義したグループ名をproxy_pass http://api_backend;のようにserverブロック内のlocationで参照するのが典型パターンです。
QNginx設定の文法エラーを防ぐには?
Adocker compose exec nginx nginx -tで構文チェック。VS Codeならshanoor.vscode-nginx拡張、JetBrainsなら内蔵Nginxサポートでリアルタイム警告が出ます。reload前に必ずnginx -tを実行する習慣がベスト。
QDockerで本番と開発の設定を分けたい
Acompose.yml(共通)+compose.dev.ymlcompose.prod.ymlオーバーライドするパターンが主流。docker compose -f compose.yml -f compose.prod.yml up -dで本番設定を適用。nginx.confもdev.confprod.confを別ファイルで用意し、マウント先を切替えれば同じイメージで両対応できます。

関連記事

まとめ

  • 推奨イメージはnginx:1.27-alpineversion:キーは不要
  • Nginxの6用途:静的/SPA/リバプロ/WebSocket/LB/API gateway
  • SPAはtry_files $uri $uri/ /index.html;でHistory APIフォールバック
  • リバプロはupstream + proxy_pass末尾/の有無でパス剥がしに注意
  • WebSocketはmap $http_upgrade $connection_upgradeUpgrade/Connection転送
  • 開発サーバー(Vite/webpack)はHMR WSをそのまま透過プロキシ
  • ローカルHTTPSはmkcerthttp2 on;(Nginx 1.25.1+新構文)
  • 複数プロジェクト管理はnginx-proxyVIRTUAL_HOSTで自動ルーティング
  • セキュリティヘッダー(HSTS/X-Frame-Options/CSP)はsnippetsに切り出してinclude
  • gzip圧縮+長期キャッシュでパフォーマンス最適化
  • 設定変更はnginx -tnginx -s reloadでゼロダウンタイム
  • 502の典型:upstreamホスト名/depends_on/Docker networkの食い違い

Nginx × Dockerは、本番と同じ構成をローカルで再現するための最も実用的な組み合わせです。本記事の6パターン(静的/SPA/リバプロ/WebSocket/LB/gateway)とHTTPS・nginx-proxy・セキュリティヘッダーを押さえれば、個人開発から大規模マイクロサービスまで幅広いユースケースに対応できます。PHP特化はNginx + PHP-FPM、WordPress特化はWordPress Docker、Compose基礎は複数コンテナ連携の各記事と併せてご活用ください。