web-dev-qa-db-ja.com

Nginxはアップストリームで見つからないホストで起動しません

私はnginxを使用してプロキシを作成し、遠くのサーバーへの永続的な接続を保持しています。

この例のように約15ブロックを構成しました。

upstream rinu-test {
    server test.rinu.test:443;
    keepalive 20;
}
server {
    listen 80;
    server_name test.rinu.test;
    location / {
        proxy_pass https://rinu-test;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $http_Host;
    }
}

問題は、1つ以上のupstreamブロックでホスト名を解決できない場合、nginxは(再)起動しません。静的IPも使用できません。これらのホストの一部は、IPが変更されるため、そうしないと明示的に述べています。このエラーメッセージに対して私が見た他のすべての解決策は、upstreamを取り除き、locationブロックですべてを実行するように言っています。 keepaliveupstreamでのみ使用できるため、ここでは不可能です。

一時的に1台のサーバーを失う余裕はありますが、15台すべてを失うわけではありません。

編集:nginxはこのユースケースには適さないことが判明しました。代替バックエンド(アップストリーム)キープアライブプロキシを使用する必要があります。カスタムNode.jsの代替は my answer にあります。これまでのところ、実際に機能する他の選択肢は見つかりませんでした。

29
rinu

世界で最も訪問された膨大な数のウェブサイトをすでに動かしていた(1.1.4より前の)nginxの以前のバージョンは(そしてサーバーヘッダーが信じられれば今日でもなおそうです)、 keepaliveupstream 側。さまざまなホスト間で非自明な待機時間がない限り、datacentre設定でこれを行うメリットはほとんどないため。 https://serverfault.com/a/883019/11002 を参照してください。

基本的に、アップストリームとフロントエンドの間でキープアライブが特に必要であることがわかっていない限り、アーキテクチャの回復力を低下させ、悪化させるだけの可能性があります。

(現在のソリューションも間違っていることに注意してください。IPアドレスの変更も同様に検出されないためです。configreloadでのみホスト名解決を行うため、nginxが起動しても、IPアドレスがいったん動作しなくなると基本的に停止します。アップストリームサーバーの変更はありません。)

潜在的なソリューションは、1つを選んでください:

  • 最良の解決策は、データセンター環境ではおそらく不要であるとしてupstreamkeepaliveを取り除き、各リクエストの最新のDNS解決に proxy_pass を使用して変数を使用することです(nginxはまだ十分にスマートです)そのような解像度のキャッシュを引き続き行うため)

  • 別のオプションは、resolveコンテキスト内のserverディレクティブの upstream パラメーターを持つ商用サブスクリプションを通じてnginxの有料バージョンを取得することです。

  • 最後に、 set変数 および/または map を使用してupstream内のサーバーを指定することもできます。これは実装されたことが確認も拒否もされません。たとえば、機能する場合と機能しない場合があります。

7
cnst

別の方法は、必要なことだけを行う新しいサービスを作成することです。 Node.jsを使用してhttps接続をプロキシするためのnginxを次のように置き換えます

const http = require('http');
const https = require('https');

const httpsKeepAliveAgent = new https.Agent({ keepAlive: true });

http.createServer(onRequest).listen(3000);

function onRequest(client_req, client_res) {
    https.pipe(
        protocol.request({
            Host: client_req.headers.Host,
            port: 443,
            path: client_req.url,
            method: client_req.method,
            headers: client_req.headers,
            agent: httpsKeepAliveAgent
        }, (res) => {
            res.pipe(client_res);
        }).on('error', (e) => {
            client_res.end();
        })
    );
}

使用例:curl http://localhost:3000/request_uri -H "Host: test.rinu.test"これはcurl https://test.rinu.test/request_uriと同等です

2
rinu

1つの解決策は、ローカルDNSキャッシュを使用することです。 BindやDnsmasqのようなローカルDNSサーバー(巧妙な構成で、nginxはシステムデフォルトの代わりに 指定されたdnsサーバー を使用できることに注意してください)、または単にhostsファイル。

一部のスクリプトでhostsファイルを使用するのは非常に簡単な方法のようです。ホストファイルは、静的部分と動的部分(つまりcat hosts.static hosts.dynamic > hosts)に分割され、動的部分はスクリプトによって自動的に生成(および更新)される必要があります。

おそらく、IPを変更するためにホスト名を時々チェックし、ホストファイルを更新し、変更時にnginxの設定をリロードすることが理にかなっています。一部のホスト名を解決できない場合は、古いIPまたはデフォルトのIP(127.0.1.9など)を使用する必要があります。

Nginx構成ファイルにホスト名が必要ない場合(つまり、IPで十分な場合)、IP(解決されたホスト名)を含むupstreamセクションをスクリプトと included intoで生成できます。 nginx config —この場合、hostsファイルに触れる必要はありません。

2
ruvim

サーバーに解決パラメーターを設定し、nginx.confでNginx Resolverを以下のように設定する必要があります。

/etc/nginx/nginx.conf:

http {
    resolver 192.168.0.2 ipv6=off valid=40s;  # The DNS IP server
} 

Site.conf:

upstream rinu-test {
    server test.rinu.test:443;
    keepalive 20;
}
1
Bruno Paiuca