問題の発生proxy_passが静的なURLを指しているときは問題なく動作します。しかし、変数を導入してアップストリームを動的にした途端、Nginxがエラーを吐き出すことがあります。サイトが502エラーを返し、ログにはリゾルバが見つからないという内容が表示されていることに気づくでしょう。
/var/log/nginx/error.logにあるエラーログを確認してください。おそらく以下のようなエントリが表示されているはずです。
2023/10/27 10:45:01 [error] 12345#0: *1 no resolver defined to resolve "api.example.com", client: 1.2.3.4, server: example.com, request: "GET / HTTP/1.1", upstream: "http://api.example.com/"
典型的な失敗例この問題は通常、以下のようなブロックで発生します。
location / {
# 変数を使用すると実行時のDNS解決が必要になる
set $backend_host "api.example.com";
proxy_pass http://$backend_host;
}
なぜ実行時にNginxが失敗するのかNginxは、proxy_passディレクティブの書き方によってDNS解決の処理方法を変えています。
- 静的解決:
proxy_pass http://api.example.com;のように記述した場合、Nginxは起動時またはリロード時に一度だけドメイン名を解決します。そのIPアドレスは、次のリロードまで永久にキャッシュされます。- 動的解決:proxy_pass http://$variable;のように変数を使用すると、ルールが変わります。変数はリクエストごとに変わる可能性があるため、Nginxは実行時にドメインを解決しなければなりません。ここに落とし穴があります。Nginxは、これらの実行時のルックアップに対してシステムの/etc/resolv.confを自動的には使用しません。resolverディレクティブを使用してDNSサーバーを明示的に定義する必要があります。これがないと、Nginxはそのドメイン文字列をIPアドレスに変換する手段がありません。
修正方法: Resolverディレクティブの追加これを修正するには、どのDNSサーバーを信頼するかをNginxに伝える必要があります。このディレクティブはhttp、server、またはlocationブロックに配置できます。
オプション1: パブリックDNSサーバーサーバーがパブリックなエンドポイントにアクセスする必要がある場合、GoogleやCloudflareは信頼できる選択肢です。serverブロックに以下を追加します。
server {
listen 80;
server_name example.com;
# GoogleとCloudflareのDNSを使用
resolver 8.8.8.8 1.1.1.1 valid=30s;
location / {
set $upstream_endpoint "api.example.com";
proxy_pass http://$upstream_endpoint;
}
}
オプション2: 内部/クラウドDNSクラウド環境では、ローカルのVPCリゾルバを使用すべきです。AWSの場合、これは通常VPCネットワーク範囲のベースアドレスに2を足したものです。例えば10.0.0.0/16ネットワークの場合、リゾルバは10.0.0.2になります。systemd-resolvedを使用している現代のUbuntuシステムでは、ローカルスタブを使用します。
# ローカルのsystemd-resolved用
resolver 127.0.0.53 valid=10s;
# AWS VPC用(例)
resolver 10.0.0.2 valid=10s;
オプション3: IPv6の無効化ネットワークがIPv6をサポートしていない場合、NginxがAAAAレコードの解決を試みて時間を無駄にすることがあります。IPv4に固定するように強制してレスポンスを速めることができます。
resolver 8.8.8.8 ipv6=off;
変更の適用設定をテストせずにNginxを再起動してはいけません。小さなタイポ一つでサイト全体がダウンする可能性があります。
- 構文の検証:
sudo nginx -t出力にsyntax is okが含まれていることを確認してください。- 正常にリロード:sudo systemctl reload nginx- **結果の監視:**アプリケーションにアクセスしながら、リアルタイムでログを監視します。tail -f /var/log/nginx/error.log## エキスパートのアドバイス- TTLに注意: AWS Load Balancerのような動的バックエンドは頻繁にIPアドレスが変わります。Nginxが古いIPアドレスを保持し続けないよう、valid=10sまたは30sを設定してください。- 冗長性: 常に少なくとも2つのDNSサーバーをリストアップしてください。一方がダウンしても、プロキシ機能は維持されます。- グローバルスコープ: 多くのサイトで動的変数を使用する場合は、nginx.confのhttpブロックにresolverを記述して設定の重複を避けましょう。

