SJ blog
devops
A

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

nginxのよくある設定ミスとトラブルシューティング

nginxの設定でハマりやすいポイントを解説。502 Bad Gateway・CORS問題・SSL設定ミス・WebSocketプロキシ・レート制限などの問題と解決策をまとめます。

一言結論

nginxのトラブルの大半は502はupstreamタイムアウト、CORSはadd_headerの二重設定、WebSocketはUpgradeヘッダーの欠落が原因であり、nginx -tとerror.logの確認を最初のステップにすれば原因特定が格段に速い。

デバッグの基本コマンド

# 設定ファイルの文法チェック
nginx -t

# 設定を再読み込み(ダウンタイムなし)
nginx -s reload

# エラーログをリアルタイム確認
tail -f /var/log/nginx/error.log

# アクセスログ確認
tail -f /var/log/nginx/access.log

よくあるエラーとその原因

502 Bad Gateway

上流サーバー(アプリ)への接続失敗。

# まず上流サーバーが動いているか確認
curl http://localhost:3000/health

# nginx エラーログを確認
grep "502\|upstream" /var/log/nginx/error.log
# ❌ よくある設定ミス(上流の URL が間違っている)
upstream app {
    server 127.0.0.1:3000;
}

# ✅ タイムアウトを適切に設定
upstream app {
    server 127.0.0.1:3000;
    keepalive 32;
}

server {
    location / {
        proxy_pass http://app;
        proxy_read_timeout 60s;
        proxy_connect_timeout 10s;
        proxy_send_timeout 60s;
    }
}

CORS エラー

# ✅ CORS ヘッダーを nginx で追加
location /api/ {
    proxy_pass http://app;

    # プリフライトリクエスト
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' 'https://frontend.example.com';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
        add_header 'Access-Control-Max-Age' 1728000;
        return 204;
    }

    add_header 'Access-Control-Allow-Origin' 'https://frontend.example.com';
}

WebSocket プロキシ

# ✅ WebSocket に必要なヘッダー
location /ws/ {
    proxy_pass http://app;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 86400s;  # 長時間接続のためタイムアウトを延長
}

SSL / HTTPS の設定

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # ✅ 推奨 SSL 設定
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # HSTS(6ヶ月間 HTTPS を強制)
    add_header Strict-Transport-Security "max-age=15768000" always;
}

# HTTP → HTTPS リダイレクト
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

413 Request Entity Too Large

# ✅ アップロードサイズの制限を変更
http {
    client_max_body_size 50M;  # デフォルトは 1MB
}

レート制限

http {
    # IP ごとに 10req/s を制限
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_req_status 429;
            proxy_pass http://app;
        }
    }
}

静的ファイルのキャッシュ最適化

location ~* \.(js|css|png|jpg|webp|svg|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Vary Accept-Encoding;

    # gzip 圧縮
    gzip on;
    gzip_types text/css application/javascript image/svg+xml;
    gzip_min_length 1024;
}

セキュリティヘッダーの追加

server {
    # クリックジャッキング防止
    add_header X-Frame-Options "SAMEORIGIN" always;

    # MIME スニッフィング防止
    add_header X-Content-Type-Options "nosniff" always;

    # XSS 保護
    add_header X-XSS-Protection "1; mode=block" always;

    # リファラーポリシー
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # nginx のバージョン情報を隠す
    server_tokens off;
}

まとめ

問題確認ポイント
502 Bad Gateway上流サーバーが動いているか・タイムアウト設定
CORS エラーadd_header Access-Control-* の設定
WebSocket 切断UpgradeConnection ヘッダー・タイムアウト
SSL エラー証明書パス・TLS バージョン
アップロード失敗client_max_body_size

まず nginx -t で文法チェック、次に tail -f /var/log/nginx/error.log でエラーを確認するのが基本フローです。


参考: nginx 公式ドキュメント