【完全版】Nginx locationの書き方:優先順位・設定例・動かない時の対処法

その他
記事内に広告が含まれています。

nginxのlocationディレクティブはWebサーバー設定の中でも特に重要な部分ですが、正しい書き方や挙動を理解せずに設定すると、期待通りに動作しなかったり、サービスの停止やトラブルに繋がることがあります。どのマッチングルールを使えばよいか、自分のケースに合った設定例はどう書けばいいのか、といった疑問をお持ちの方も多いでしょう。特に、複数のlocationを使うときの優先順位や正規表現の使い方は難解で、何度も試行錯誤することが少なくありません。

この記事では、nginxのlocationディレクティブの基本構文から、実務でよく使われる設定パターン、静的ファイルとAPIの振り分け、リバースプロキシの構築方法までをわかりやすく解説します。また、設定が意図せず動作しないときのトラブルシューティングや、安全に設定を反映させるためのコマンド操作も丁寧に紹介していますので、初心者から中級者まで役立つ内容です。

この記事を読んでわかること

  • nginxのlocationディレクティブの基本的な書き方とnginx.confでの配置ルール
  • マッチ修飾子(=, ^~, ~, ~*)の意味と適切な使い分け方
  • 静的ファイルやAPIを分けて効率よく配信する具体的なlocation設定例
  • rootaliasの違いと正しい適用方法
  • proxy_passを使ったリバースプロキシ設定のポイント
  • locationがマッチしない場合の原因特定とデバッグ方法
  • 設定ミスを避けるコツと安全に設定をリロードする手順

これらを理解することで、安定したnginxサーバー運用を実現し、設定ミスで悩む時間を大幅に減らせます。ぜひ最後までご覧ください。

格安ドメイン取得サービス─ムームードメイン─

nginxのlocationディレクティブの基本構文と書き方

nginx

locationディレクティブの概要とnginx.confでの配置ルール

locationディレクティブは、nginxがクライアントからのリクエストURLをどのように処理するかを定義する、最も重要な設定要素の一つです。具体的には、リクエストされたURIのパスに応じて、どのファイルを返すか、どのバックエンドサーバーに転送するか、どのような処理を実行するかを制御します。

locationディレクティブは、serverブロック内に記述するのが基本ルールです。nginx.confファイル(またはconf.dディレクトリ内の設定ファイル)における典型的な配置は以下の通りです。

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

        # ここにlocationディレクティブを記述
        location / {
            root /var/www/html;
            index index.html;
        }

        location /api {
            proxy_pass <http://backend:3000>;
        }
    }
}

重要なポイントとして、locationブロックは複数定義可能で、nginxはリクエストされたURIに対して最も適切なlocationブロックを選択して処理を実行します。この「選択の仕組み」こそが、locationディレクティブを理解する上での最大のカギとなります。

また、locationディレクティブはlocationブロック内にネスト(入れ子)することも可能ですが、実務では可読性の観点から避けられることが多く、フラットな構造で記述するのが一般的です。

location /, =, ^~, ~, ~*のマッチ修飾子の意味と使い分け

locationディレクティブには、URIのマッチング方法を指定するための修飾子(modifier)が存在します。修飾子によって、nginxがどのようにリクエストURIと照合するかが大きく変わります。

修飾子の種類と意味

修飾子マッチング方法優先度用途
=完全一致(Exact match)最高特定のURIにのみ適用したい場合
^~前方一致(Prefix match)で正規表現より優先ディレクトリ単位で確実に処理したい場合
~正規表現(大文字小文字を区別)拡張子による振り分けなど
~*正規表現(大文字小文字を区別しない)画像ファイルなど大文字小文字を問わない場合
なし前方一致(Prefix match)一般的なパス指定

各修飾子の具体例

1. = 完全一致

完全に一致するURIにのみマッチします。最も優先度が高く、高速に処理されます。

location = / {
    # <http://example.com/> のみマッチ
    # <http://example.com/index.html> はマッチしない
    return 200 "Welcome to top page";
}

location = /favicon.ico {
    # /favicon.ico のみに対応
    access_log off;
    log_not_found off;
}

2. ^~ 前方一致(正規表現より優先)

指定したパスで始まるURIにマッチし、正規表現のlocationよりも優先されます。

location ^~ /static/ {
    # /static/css/style.css → マッチ
    # /static/js/app.js → マッチ
    # /api/static → マッチしない
    root /var/www;
}

3. ~ 正規表現(大文字小文字区別あり)

正規表現でマッチングします。大文字と小文字を区別します。

location ~ \\.php$ {
    # /index.php → マッチ
    # /admin/login.php → マッチ
    # /index.PHP → マッチしない(大文字Pなので)
    fastcgi_pass unix:/var/run/php-fpm.sock;
}

4. ~* 正規表現(大文字小文字区別なし)

正規表現でマッチングします。大文字と小文字を区別しません。

location ~* \\.(jpg|jpeg|png|gif|webp)$ {
    # /images/photo.jpg → マッチ
    # /uploads/banner.PNG → マッチ
    # /assets/icon.WEBP → マッチ
    expires 30d;
    add_header Cache-Control "public, immutable";
}

5. 修飾子なし(前方一致)

指定したパスで始まるURIにマッチします。最も基本的で汎用的な方法です。

location /api/ {
    # /api/users → マッチ
    # /api/posts/123 → マッチ
    # /api → マッチしない(末尾のスラッシュに注意)
    proxy_pass <http://backend:8080>;
}

使い分けのポイント

  • 特定のファイルやパスだけ特別扱いしたい= を使用
  • ディレクトリ配下を確実に処理し、正規表現に干渉されたくない^~ を使用
  • 拡張子やパターンで振り分けたい~ または ~* を使用
  • シンプルなパス指定で十分 → 修飾子なしを使用
あなたのサイトのURL、そろそろスリムにしませんか?

シンプルで汎用的な最小構成サンプル(コピペOK)

実際のプロジェクトですぐに使える、シンプルかつ実用的な最小構成をご紹介します。この設定は、静的サイトとAPIバックエンドを持つ一般的なWebアプリケーションを想定しています。

server {
    listen 80;
    server_name example.com;

    # ルートディレクトリの設定
    root /var/www/html;
    index index.html index.htm;

    # メインページ(SPAなど)
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静的ファイル(キャッシュ最適化)
    location ~* \\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # APIエンドポイント(バックエンドへプロキシ)
    location /api/ {
        proxy_pass <http://localhost:3000/>;
        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;
    }

    # ヘルスチェック用エンドポイント
    location = /health {
        access_log off;
        return 200 "OK\\n";
        add_header Content-Type text/plain;
    }
}

このサンプル設定のポイント

  1. location / では try_files を使用し、ファイルが存在しなければindex.htmlにフォールバックします。これはReactやVue.jsなどのSPA(Single Page Application)で必須の設定です。
  2. 静的ファイルのlocation では正規表現 ~* を使い、画像やCSS、JavaScriptファイルに長期キャッシュを設定しています。これによりパフォーマンスが大幅に向上します。
  3. location /api/ ではバックエンドサーバー(ポート3000で動作)へのリバースプロキシを設定し、必要なヘッダーを適切に転送しています。
  4. ヘルスチェックエンドポイント は、ロードバランサーやモニタリングツールからの死活監視に使用できます。

この設定をベースに、あなたのプロジェクトに合わせてカスタマイズしていくことで、多くのユースケースに対応できます。次のセクションでは、さらに実践的な設定パターンを詳しく解説していきます。

通信無制限なのに工事不要!【SoftbankAir】

よく使うlocation設定パターンと実践例

静的ファイル・APIを振り分けるlocation設定例(/static, /api)

実務で最も頻繁に遭遇するのが、フロントエンドの静的ファイルとバックエンドAPIを同一ドメインで提供するパターンです。適切にlocationを設定することで、パフォーマンスとセキュリティを両立できます。

基本的な振り分け設定

server {
    listen 80;
    server_name example.com;

    # 静的ファイル用のディレクトリ
    location /static/ {
        alias /var/www/assets/;

        # キャッシュ制御(1年間)
        expires 1y;
        add_header Cache-Control "public, immutable";

        # アクセスログを無効化してパフォーマンス向上
        access_log off;

        # gzip圧縮を有効化
        gzip on;
        gzip_types text/css application/javascript image/svg+xml;
    }

    # API用のリバースプロキシ
    location /api/ {
        # バックエンドサーバーへ転送
        proxy_pass <http://backend:8080/api/>;

        # タイムアウト設定(重い処理に対応)
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # 必須ヘッダーの設定
        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;

        # キャッシュ無効化(動的コンテンツのため)
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";
    }

    # フロントエンドアプリケーション(SPA)
    location / {
        root /var/www/html;
        try_files $uri $uri/ /index.html;

        # HTMLファイルはキャッシュしない
        add_header Cache-Control "no-cache";
    }
}

より高度な振り分け例(複数のバックエンド)

server {
    listen 80;
    server_name example.com;

    # 認証API(別のバックエンド)
    location /api/auth/ {
        proxy_pass <http://auth-service:3001/>;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # ユーザーAPI
    location /api/users/ {
        proxy_pass <http://user-service:3002/>;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # CORS設定(必要に応じて)
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE";
    }

    # 画像アップロード用のエンドポイント(サイズ制限あり)
    location /api/upload/ {
        client_max_body_size 10M;
        proxy_pass <http://upload-service:3003/>;
        proxy_set_header Host $host;

        # タイムアウトを長めに設定
        proxy_read_timeout 300s;
    }

    # 静的な画像ファイル
    location /static/images/ {
        alias /var/www/uploads/;

        # 画像の直リンク防止(リファラーチェック)
        valid_referers none blocked server_names *.example.com;
        if ($invalid_referer) {
            return 403;
        }

        expires 30d;
        access_log off;
    }
}

このような設定により、マイクロサービス構成のバックエンドを1つのnginxで効率的に管理できます。

まずは無料体験・説明会に参加を♪【Winスクール】

rootとaliasの違いと正しい使い方

rootディレクティブaliasディレクティブは、静的ファイルを配信する際に使用しますが、その挙動は大きく異なります。この違いを正しく理解しないと、404エラーの原因になります。

rootの挙動

rootは、locationのパスをそのままディレクトリパスに追加します。

location /static/ {
    root /var/www;
}

この設定の場合、リクエストURIが /static/css/style.css のとき、nginxは以下のファイルを探します:

/var/www/static/css/style.css
↑rootで指定したパス + locationのパス

aliasの挙動

aliasは、locationのパスを置き換えてディレクトリパスを指定します。

location /static/ {
    alias /var/www/assets/;
}

この設定の場合、リクエストURIが /static/css/style.css のとき、nginxは以下のファイルを探します:

/var/www/assets/css/style.css
↑locationのパスが置き換えられる

実際のディレクトリ構造で比較

以下のようなディレクトリ構成を想定します:

/var/www/
├── html/
│   └── index.html
└── assets/
    ├── css/
    │   └── style.css
    └── js/
        └── app.js

rootを使う場合(パスを追加)

location /assets/ {
    root /var/www;
}

# リクエスト: <http://example.com/assets/css/style.css>
# 実際のファイルパス: /var/www/assets/css/style.css ✓ 正しい

aliasを使う場合(パスを置き換え)

location /static/ {
    alias /var/www/assets/;
}

# リクエスト: <http://example.com/static/css/style.css>
# 実際のファイルパス: /var/www/assets/css/style.css ✓ 正しい

よくある間違いと正しい書き方

❌ 間違い:aliasでスラッシュを忘れる

location /static/ {
    alias /var/www/assets;  # 末尾のスラッシュがない
}

# リクエスト: /static/css/style.css
# 実際のファイルパス: /var/www/assetscss/style.css ✗ 404エラー

✓ 正しい:aliasには末尾のスラッシュを付ける

location /static/ {
    alias /var/www/assets/;  # 末尾のスラッシュが必須
}

使い分けのガイドライン

状況推奨理由
URLパスとディレクトリ構造が一致するrootシンプルで直感的
URLパスとディレクトリ名を変えたいalias柔軟な配置が可能
ルートレベルの設定rootserverブロックで一度定義できる
特定のlocationだけ変更alias個別に上書き可能

実践例:組み合わせて使う

server {
    listen 80;
    server_name example.com;

    # サーバー全体のデフォルト
    root /var/www/html;

    # 通常のページ
    location / {
        # rootがサーバーレベルで定義されているので不要
        try_files $uri $uri/ /index.html;
    }

    # 管理画面だけ別のディレクトリ
    location /admin/ {
        alias /var/www/admin-panel/;
        try_files $uri $uri/ /admin/index.html;
    }

    # ユーザーアップロードファイル
    location /uploads/ {
        alias /mnt/storage/user-files/;
        expires 7d;
    }
}
Webデザインコース

proxy_passとの組み合わせでリバースプロキシを構築する方法

nginxの最も強力な機能の一つが、リバースプロキシとしての動作です。proxy_passディレクティブを使うことで、バックエンドサーバーへのリクエストを効率的に転送できます。

基本的なproxy_pass設定

server {
    listen 80;
    server_name example.com;

    location /api/ {
        proxy_pass <http://localhost:3000/>;

        # 基本的なプロキシヘッダー
        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_passのURL末尾スラッシュの重要性

proxy_passのURLに末尾スラッシュがあるかないかで、挙動が大きく変わります。これは最も混乱しやすいポイントです。

パターン1:末尾スラッシュあり(locationパスを削除)

location /api/ {
    proxy_pass <http://backend:3000/>;
}

# クライアントのリクエスト: /api/users
# バックエンドへの転送: <http://backend:3000/users>
#                                          ↑
#                               /api/が削除される

パターン2:末尾スラッシュなし(locationパスを保持)

location /api/ {
    proxy_pass <http://backend:3000>;
}

# クライアントのリクエスト: /api/users
# バックエンドへの転送: <http://backend:3000/api/users>
#                                          ↑
#                               /api/が保持される

パターン3:パスを含むproxy_pass(置き換え)

location /api/ {
    proxy_pass <http://backend:3000/v1/>;
}

# クライアントのリクエスト: /api/users
# バックエンドへの転送: <http://backend:3000/v1/users>
#                                          ↑
#                               /api/が/v1/に置き換えられる

実用的なリバースプロキシ設定例

WebSocketに対応したプロキシ設定

location /ws/ {
    proxy_pass <http://websocket-server:8080/>;

    # WebSocketに必要な設定
    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;
    proxy_send_timeout 86400s;
}

負荷分散(ロードバランシング)設定

upstream backend_servers {
    # ラウンドロビン方式
    server backend1:3000;
    server backend2:3000;
    server backend3:3000;

    # ヘルスチェック用のキープアライブ
    keepalive 32;
}

server {
    listen 80;
    server_name example.com;

    location /api/ {
        proxy_pass http://backend_servers/;

        proxy_http_version 1.1;
        proxy_set_header Connection "";
        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_next_upstream error timeout invalid_header http_500 http_502 http_503;
    }
}

キャッシュを有効にしたプロキシ設定

# キャッシュゾーンの定義(httpブロック内)
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;

server {
    listen 80;
    server_name example.com;

    location /api/public/ {
        proxy_pass <http://backend:3000/>;

        # キャッシュの有効化
        proxy_cache api_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_valid 404 1m;

        # キャッシュキーの設定
        proxy_cache_key "$scheme$request_method$host$request_uri";

        # キャッシュステータスをヘッダーで返す(デバッグ用)
        add_header X-Cache-Status $upstream_cache_status;

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

セキュリティを強化したプロキシ設定

location /api/ {
    # レート制限(後述のlimit_req_zoneが必要)
    limit_req zone=api_limit burst=20 nodelay;

    # 特定のメソッドのみ許可
    limit_except GET POST PUT DELETE {
        deny all;
    }

    proxy_pass <http://backend:3000/>;

    # セキュリティヘッダーの追加
    proxy_hide_header X-Powered-By;
    add_header X-Content-Type-Options "nosniff";
    add_header X-Frame-Options "DENY";
    add_header X-XSS-Protection "1; mode=block";

    # プロキシヘッダー
    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_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 8 4k;
}

よく使うproxy_set_headerの意味

ヘッダー意味重要度
Host $hostオリジナルのホスト名を転送必須
X-Real-IP $remote_addrクライアントの実IPアドレス必須
X-Forwarded-For $proxy_add_x_forwarded_forプロキシチェーン全体のIPリスト必須
X-Forwarded-Proto $schemeHTTPかHTTPSかを通知推奨
X-Forwarded-Host $hostオリジナルのホスト名(冗長だが互換性のため)任意

これらの設定を組み合わせることで、本番環境に耐えうる堅牢なリバースプロキシを構築できます。

◆◇◆ 【衝撃価格】VPS512MBプラン!1時間1.3円【ConoHa】 ◆◇◆

トラブル解決と安全な設定のベストプラクティス

locationがマッチしないときの原因とデバッグ方法

「設定したはずのlocationが動作しない」というトラブルは、nginx初心者が最も頻繁に遭遇する問題です。ここでは、原因の特定方法と解決策を体系的に解説します。

デバッグの基本手順

ステップ1:nginxのエラーログを確認する

まず、nginxのエラーログを確認することが最優先です。多くの場合、ここにヒントが記録されています。

# エラーログの確認(Ubuntuの場合)
sudo tail -f /var/log/nginx/error.log

# アクセスログも同時に確認
sudo tail -f /var/log/nginx/access.log

ステップ2:デバッグログを有効化する

より詳細な情報が必要な場合は、デバッグログを有効化します。

error_log /var/log/nginx/error.log debug;

server {
    listen 80;
    server_name example.com;

    # locationごとにデバッグ情報を出力
    location /api/ {
        error_log /var/log/nginx/api-debug.log debug;
        proxy_pass <http://backend:3000/>;
    }
}

デバッグログには、どのlocationがマッチしたか、リクエストがどのように処理されたかが詳細に記録されます。

ステップ3:curlコマンドで検証する

ブラウザではなくcurlコマンドを使うことで、リダイレクトやキャッシュの影響を排除してテストできます。

# 基本的なリクエスト
curl -i <http://example.com/api/users>

# ヘッダーを含めて詳細表示
curl -v <http://example.com/static/css/style.css>

# 特定のホスト名でテスト(hostsファイル設定前)
curl -H "Host: example.com" <http://192.168.1.100/api/test>

よくある原因と解決策

原因1:locationの優先順位の誤解

nginxは複数のlocationがマッチする場合、特定の優先順位に従って選択します。

server {
    listen 80;
    server_name example.com;

    # 正規表現(優先度:中)
    location ~ ^/api {
        return 200 "Regex match\\n";
    }

    # 前方一致(優先度:低)
    location /api/ {
        return 200 "Prefix match\\n";
    }
}

# リクエスト: /api/users
# 結果: "Regex match" が返される(正規表現が優先)

解決策:^~修飾子を使って正規表現より優先させる

location ^~ /api/ {
    return 200 "Priority prefix match\\n";
}

location ~ ^/api {
    return 200 "Regex match\\n";
}

# リクエスト: /api/users
# 結果: "Priority prefix match" が返される

原因2:スラッシュの有無による不一致

locationパスの末尾スラッシュの有無で挙動が変わります。

# 末尾スラッシュあり
location /api/ {
    proxy_pass <http://backend:3000/>;
}

# /api/users → マッチする ✓
# /api → マッチしない ✗

解決策:両方に対応する設定

# パターン1:完全一致と前方一致を両方定義
location = /api {
    proxy_pass <http://backend:3000/>;
}

location /api/ {
    proxy_pass <http://backend:3000/>;
}

# パターン2:try_filesで内部的に処理
location /api {
    try_files $uri $uri/ @api_backend;
}

location @api_backend {
    proxy_pass <http://backend:3000>;
}

原因3:正規表現の誤り

正規表現location内で特殊文字をエスケープし忘れるとマッチしません。

# ❌ 間違い:ドットをエスケープしていない
location ~ /api/v1.0/ {
    proxy_pass <http://backend:3000/>;
}
# /api/v1X0/ もマッチしてしまう(.は任意の1文字を意味する)

# ✓ 正しい:ドットをエスケープ
location ~ /api/v1\\.0/ {
    proxy_pass <http://backend:3000/>;
}

原因4:rootとaliasの混同

前セクションで解説した通り、rootとaliasを間違えると404エラーになります。

# ❌ 間違い:aliasのつもりでrootを使用
location /static/ {
    root /var/www/assets/;  # /var/www/assets/static/ を探してしまう
}

# ✓ 正しい:aliasを使用
location /static/ {
    alias /var/www/assets/;  # /var/www/assets/ を正しく参照
}

典型的なエラーログの例と対処法

# エラーログ例1:ファイルが見つからない
2025/10/10 10:30:15 [error] 1234#1234: *1 open() "/var/www/html/static/style.css" failed (2: No such file or directory)
→ rootとaliasの設定を確認

# エラーログ例2:ディレクトリインデックスが無効
2025/10/10 10:31:20 [error] 1234#1234: *2 directory index of "/var/www/html/api/" is forbidden
→ autoindex on; を追加するか、locationの設定を見直す

# エラーログ例3:プロキシ先に接続できない
2025/10/10 10:32:45 [error] 1234#1234: *3 connect() failed (111: Connection refused) while connecting to upstream
→ バックエンドサーバーが起動しているか確認

# エラーログ例4:タイムアウト
2025/10/10 10:33:50 [error] 1234#1234: *4 upstream timed out (110: Connection timed out)
→ proxy_read_timeout を増やす

デバッグ用のlocation設定例

トラブルシューティング時に役立つ、デバッグ用のlocation設定です。

server {
    listen 80;
    server_name example.com;

    # どのlocationにマッチしたかを返すテスト用エンドポイント
    location = /debug/test1 {
        return 200 "Matched: exact /debug/test1\\n";
        add_header Content-Type text/plain;
    }

    location ^~ /debug/ {
        return 200 "Matched: priority prefix /debug/\\n";
        add_header Content-Type text/plain;
    }

    location ~ ^/debug {
        return 200 "Matched: regex ^/debug\\n";
        add_header Content-Type text/plain;
    }

    # リクエスト情報を表示
    location /debug/info {
        return 200 "URI: $uri\\nRequest URI: $request_uri\\nHost: $host\\nRemote Addr: $remote_addr\\n";
        add_header Content-Type text/plain;
    }
}
国内シェアNo.1のエックスサーバーが提供するVPSサーバー『XServer VPS』

よくある設定ミス(スラッシュの有無・正規表現の誤り)を避けるコツ

実務で頻発する設定ミスのパターンと、それを回避するためのベストプラクティスをまとめます。

ミス1:proxy_passとlocationの末尾スラッシュ不一致

問題のある設定

location /api {
    proxy_pass <http://backend:3000/>;
}

# リクエスト: /api/users
# 期待: <http://backend:3000/users>
# 実際: <http://backend:3000//users> (スラッシュが重複)

ベストプラクティス

# ルール:locationとproxy_passのスラッシュを揃える

# パターンA:両方ともスラッシュあり
location /api/ {
    proxy_pass <http://backend:3000/>;
}

# パターンB:両方ともスラッシュなし
location /api {
    proxy_pass <http://backend:3000>;
}

ミス2:正規表現のエスケープ忘れ

問題のある設定

# ❌ 間違い:特殊文字をエスケープしていない
location ~ \\.css|\\.js$ {
    expires 1y;
}
# | はORを意味せず、文字クラスとして解釈されてしまう

ベストプラクティス

# ✓ 正しい:括弧でグループ化し、適切にエスケープ
location ~ \\.(css|js)$ {
    expires 1y;
}

# さらに良い:大文字小文字を区別しない
location ~* \\.(css|js)$ {
    expires 1y;
}

ミス3:try_filesとproxy_passの併用

問題のある設定

# ❌ エラーになる:try_filesとproxy_passは同じlocationで使えない
location / {
    try_files $uri $uri/ /index.html;
    proxy_pass <http://backend:3000>;
}

ベストプラクティス

# ✓ 正しい:named locationを使って分離
location / {
    try_files $uri $uri/ @backend;
}

location @backend {
    proxy_pass <http://backend:3000>;
}

# または、条件分岐を使う
location / {
    root /var/www/html;
    try_files $uri $uri/ @proxy;
}

location @proxy {
    proxy_pass <http://backend:3000>;
    proxy_set_header Host $host;
}

ミス4:if文の不適切な使用

nginxのif文は予想外の挙動をすることがあり、「if is evil(ifは邪悪)」と呼ばれています。

問題のある設定

# ❌ 非推奨:ifでファイル存在チェック
location / {
    if (-f $request_filename) {
        expires 30d;
    }
    proxy_pass <http://backend:3000>;
}

ベストプラクティス

# ✓ 推奨:try_filesを使う
location / {
    try_files $uri @backend;
}

location @backend {
    proxy_pass <http://backend:3000>;
}

# if文を使う場合は、returnと組み合わせるのが安全
location / {
    if ($request_method = POST) {
        return 405;
    }
    proxy_pass <http://backend:3000>;
}

ミス5:rewriteとproxy_passの順序問題

# ❌ 問題:rewriteが最後まで実行されない
location /old-api/ {
    rewrite ^/old-api/(.*)$ /new-api/\ break;
    proxy_pass <http://backend:3000>;
}

ベストプラクティス

# ✓ 正しい:rewriteで別のlocationへリダイレクト
location /old-api/ {
    rewrite ^/old-api/(.*)$ /new-api/\ last;
}

location /new-api/ {
    proxy_pass <http://backend:3000/>;
}

# または、proxy_passのURL内で処理
location /old-api/ {
    proxy_pass <http://backend:3000/new-api/>;
}

設定チェックリスト

実装前に確認すべき項目をチェックリストにまとめました。

  • locationとproxy_passの末尾スラッシュは一致しているか
  • 正規表現内の特殊文字は適切にエスケープされているか
  • rootとaliasを正しく使い分けているか(aliasの末尾スラッシュは必須)
  • 複数のlocationで優先順位の競合が起きていないか
  • try_filesとproxy_passを同じlocationで使っていないか
  • if文を使わずに済む方法はないか(try_files、map、returnで代替)
  • proxy_set_headerで必要なヘッダーを転送しているか
  • タイムアウト設定は適切か(重い処理がある場合)
【不要なパソコンを送るだけ】パソコン無料処分サービス『送壊ゼロ』

設定変更を安全に反映する手順(nginx -tとnginx -s reload)

nginx設定を変更する際、誤った設定でサービスを停止させないよう、安全な手順を踏むことが重要です。

基本的な設定反映手順

ステップ1:設定ファイルを編集

# 設定ファイルを編集
sudo vim /etc/nginx/nginx.conf
# または
sudo vim /etc/nginx/sites-available/example.com

ステップ2:構文チェック

設定を反映する前に、必ず構文チェックを実行します。

# 構文チェック
sudo nginx -t

# 成功時の出力例
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

# エラー時の出力例
nginx: [emerg] invalid number of arguments in "proxy_pass" directive in /etc/nginx/nginx.conf:45
nginx: configuration file /etc/nginx/nginx.conf test failed

ステップ3:設定の再読み込み

構文チェックが成功したら、設定を反映します。

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

# または systemctl を使用(推奨)
sudo systemctl reload nginx

reload と restart の違い

コマンド挙動ダウンタイム使用タイミング
nginx -s reload既存接続を維持したまま新設定を適用なし通常の設定変更
systemctl restart nginxnginxを完全に再起動あり(数秒)listenポート変更、モジュール追加時
nginx -s stop即座に停止あり緊急停止時のみ
nginx -s quit既存接続を処理してから停止あり計画停止時

本番環境での安全な設定変更手順(推奨)

# 1. 現在の設定をバックアップ
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup.$(date +%Y%m%d_%H%M%S)

# 2. 設定を編集
sudo vim /etc/nginx/nginx.conf

# 3. 構文チェック
sudo nginx -t

# 4. 構文チェックが成功したら反映
if [ $? -eq 0 ]; then
    sudo systemctl reload nginx
    echo "Nginx configuration reloaded successfully"
else
    echo "Nginx configuration test failed. Not reloading."
    exit 1
fi

# 5. ログでエラーがないか確認
sudo tail -f /var/log/nginx/error.log

スクリプト化した安全な設定反映

実務で使える、エラーハンドリング付きのシェルスクリプト例です。

#!/bin/bash
# nginx-safe-reload.sh

set -e

NGINX_CONF="/etc/nginx/nginx.conf"
BACKUP_DIR="/etc/nginx/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# バックアップディレクトリを作成
mkdir -p "$BACKUP_DIR"

echo "Creating backup..."
cp "$NGINX_CONF" "$BACKUP_DIR/nginx.conf.$TIMESTAMP"

echo "Testing nginx configuration..."
if sudo nginx -t; then
    echo "Configuration test passed. Reloading nginx..."
    sudo systemctl reload nginx

    if [ $? -eq 0 ]; then
        echo "✓ Nginx reloaded successfully"

        # ヘルスチェック
        sleep 2
        if curl -f <http://localhost/> > /dev/null 2>&1; then
            echo "✓ Health check passed"
        else
            echo "✗ Health check failed. Rolling back..."
            sudo cp "$BACKUP_DIR/nginx.conf.$TIMESTAMP" "$NGINX_CONF"
            sudo systemctl reload nginx
            exit 1
        fi
    else
        echo "✗ Reload failed"
        exit 1
    fi
else
    echo "✗ Configuration test failed. Not reloading."
    exit 1
fi

docker環境での設定反映

Dockerコンテナでnginxを運用している場合の手順です。

# 1. コンテナ内で構文チェック
docker exec nginx-container nginx -t

# 2. 設定を反映
docker exec nginx-container nginx -s reload

# または、コンテナごと再作成(設定ファイルをマウントしている場合)
docker-compose restart nginx

# 3. ログ確認
docker logs -f nginx-container

Blue-Green デプロイメント方式(高可用性環境)

ダウンタイムゼロを実現する、より高度な設定変更方法です。

# 1. 新しい設定でテスト用nginxを起動
docker run -d --name nginx-test \\
  -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \\
  -p 8080:80 \\
  nginx:latest

# 2. テスト用nginxでヘルスチェック
curl <http://localhost:8080/health>

# 3. 問題なければ本番に反映
docker stop nginx-prod
docker rm nginx-prod
docker run -d --name nginx-prod \\
  -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \\
  -p 80:80 \\
  nginx:latest

# 4. テスト用コンテナを削除
docker stop nginx-test
docker rm nginx-test

トラブル時のロールバック手順

設定変更後に問題が発生した場合の対処法です。

# 1. バックアップから復元
sudo cp /etc/nginx/nginx.conf.backup.20251010_103000 /etc/nginx/nginx.conf

# 2. 構文チェック
sudo nginx -t

# 3. 反映
sudo systemctl reload nginx

# 4. 動作確認
curl -I <http://localhost/>

CI/CD環境での自動化例(GitHub Actions)

name: Deploy Nginx Config

on:
  push:
    branches: [main]
    paths:
      - 'nginx.conf'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Test Nginx Configuration
        run: |
          docker run --rm -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \\
            nginx:latest nginx -t

      - name: Deploy to Server
        if: success()
        run: |
          scp nginx.conf user@server:/tmp/nginx.conf.new
          ssh user@server "sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup && \\
                           sudo mv /tmp/nginx.conf.new /etc/nginx/nginx.conf && \\
                           sudo nginx -t && \\
                           sudo systemctl reload nginx"

これらの手順を守ることで、nginx設定変更時のトラブルを最小限に抑え、安全に運用できます。

コストパフォーマンスに優れた高性能なレンタルサーバー

【Hostinger】

よくある質問(FAQ)

locationブロックのネスト(入れ子)は可能ですか?

可能です。 serverブロック直下にあるlocationをアウターlocationと呼び、その中にさらにlocationを記述することをネスト(入れ子)と呼びます。

ただし、ネストは主に認証処理エラー処理を特定のlocation内で完結させたい場合など、特殊なケースでのみ利用されます。基本的には、設定の可読性と優先順位の理解を容易にするため、ネウター(入れ子にしない)でserverブロック直下に並べる方がベストプラクティスとされています。ネストしたlocationは、アウターlocationがマッチした後に評価されます。

locationrewriteディレクティブを併用する際の注意点は?

処理順序に注意が必要です。Nginxはリクエストを受け取ると、まずserverブロック直下でrewriteディレクティブを処理し、その後にlocationのマッチングを行います。

もし、locationブロック内でrewriteを使用した場合、そのrewriteが実行されると、Nginxは新しいURIで再度locationのマッチングを最初からやり直します(内部リダイレクト)。

これが無限ループの原因になったり、意図しないlocationにマッチしたりすることがあります。rewriteはなるべくserverブロックの早い段階で使うか、returnディレクティブで恒久的なリダイレクト(301/302)を使うことを検討してください。

WordPressやLaravelなど特定のアプリケーションを動かす際の基本的なlocation設定は?

アプリケーションの動作に必要な全てのURIをindex.php(または対応するエントリーポイント)に集約することが基本です。これは「フロントコントローラー」パターンと呼ばれます。

例えばPHPアプリケーション(Laravel, WordPressなど)では、リクエストされたファイルが存在しない場合にindex.phpに処理を渡すために**try_filesディレクティブ**をlocation /内で利用します。

location / {
    # ファイルやディレクトリが存在すればそれを表示、なければ index.php に渡す
    try_files $uri $uri/ /index.php?$query_string;
}

# PHPファイルを処理する location (ここではfastcgi_passを利用)
location ~ \\.php$ {
    # ここにPHP-FPMへのプロキシ設定などを記述
    fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
}

このように、静的ファイルはNginxが直接処理し、動的なリクエストだけをPHPプロセッサに渡すようにlocationを使い分けるのが一般的です。

現役エンジニアのパーソナルメンターからマンツーマンで学べるテックアカデミー

まとめ

本記事を通して、Nginxの心臓部とも言えるlocationディレクティブ基本の書き方から、実務で必須となる複雑な設定テクニック、トラブルシューティングまで、深く掘り下げてきました。

locationの理解は、単にWebサイトを表示させるだけでなく、リクエストを意図通りに捌き、サーバーのパフォーマンスとセキュリティを最適化するための、エンジニアとして非常に重要なスキルです。

特に、設定が意図通りに動かない時、多くのエンジニアが悩むのはlocationマッチングの優先順位です。=(完全一致)、^~(前方一致)、~~*(正規表現)といった修飾子を理解せずに設定を重ねていくと、予期せぬルーティングが発生し、デバッグに時間を取られてしまいます。しかし、今回学んだように、「完全一致」から先に評価され、「正規表現」は順番に評価されるというルールさえ頭に入れておけば、混乱は大きく減らせます。

また、Webアプリケーション開発において、静的ファイル(画像やCSS)はNginxが高速配信し、動的なAPIリクエストは別のアプリケーションサーバーへリバースプロキシ(proxy_pass)で転送するという構成が主流です。この静動分離を効率的かつ確実に行うためにも、locationの使い分けは欠かせません。rootaliasの違いを意識し、パスの解決方法を明確にすることで、将来的なメンテナンス性も向上します。

重要ポイント

  • 修飾子と優先順位の理解が鍵:
    =, ^~, ~, ~*など、各修飾子の役割と評価の順番を完全に把握することが、設定ミスの防止に繋がります。
  • rootaliasの違いを明確に:
    rootlocationのパスを相対的に継承しますが、aliasはパスの置き換えを行います。静的コンテンツの配信では、この違いを理解することが不可欠です。
  • トラブル回避のためのデバッグ習慣:
    設定変更後は必ずnginx -tで構文チェックを行い、安全にnginx -s reloadで反映させるプロセスを徹底しましょう。
  • リバースプロキシの基本:
    /api/のような特定パスへのリクエストを**proxy_pass*でバックエンドへ確実に転送する設定は、現代的なWebサービスの基礎です。
タイトルとURLをコピーしました