Nginxリバースプロキシ+ URL書き換え


149

Nginxはポート80で実行されており、この方法で/fooポートへのパスを持つプロキシURLをリバースするために使用しています3200

location /foo {
                proxy_pass http://localhost:3200;
                proxy_redirect     off;
                proxy_set_header   Host $host;
}

これは正常に機能しますが3200、port にアプリケーションがあり、そのためにイニシャル/fooを送信したくありません。つまりhttp://localhost/foo/bar、アクセスするときに/bar、アプリが受信したパスになりたいだけです。そこで、上記のロケーションブロックにこの行を追加してみました。

rewrite ^(.*)foo(.*)$ http://localhost:3200/$2 permanent;

これにより302リダイレクト(URLの変更)が発生しますが、301が必要です。どうすればよいですか?


あなたはGrafanaケースに問題がある場合は、これらのレシピを使用する必要があります。docs.grafana.org/installation/behind_proxy/...
saeediモフセン・

回答:


168

localhostへのリダイレクトは、リモートシステム(クライアントのWebブラウザーなど)からは意味がありません。したがって、書き換えフラグのパーマネント(301)またはリダイレクト(302)は使用できません。

透過的な書き換えルールを使用して次のセットアップを試してください。

location  /foo {
  rewrite /foo/(.*) /$1  break;
  proxy_pass         http://localhost:3200;
  proxy_redirect     off;
  proxy_set_header   Host $host;
}

curl -i書き換えのテストに使用します。ルールを微妙に変更すると、nginxがリダイレクトを実行する可能性があります。


1
URLパスは、アプリで/ fooで始まりますが、それを行うと
...-jeffreyveon

別の問題があるはずです。ほんの数分前に、このシナリオをうまく再現しました。元のURL:http:// development / foo / testme / 1234-プロキシバックエンドとして接続されたApacheで実行されているPHPスクリプトのREQUEST_URI: '/ testme / 1234'
Jens Bradler

9
正規表現はおそらくである必要があり/foo(.*)、そうでなけれexample.com/fooば一致しません。(おそらくジェフリーベオンが経験したことです)
ベンノ14年

この種の作品は、私がproxy_set_bodyで設定している私の体は削除されています。
ジャスティントーマス

rewrite /(.*)/socket.io/ break;
SOCKET.IOの1

123

proxy_passディレクティブでURIを指定している限り、書き換えルールを使用せずに、このために単純な場所プレフィックスマッチングが機能します。

location /foo {
  proxy_pass http://localhost:3200/;
}

ディレクティブ/の最後の追加に注意してくださいproxy_pass。NGINXは一致したプレフィックスを削除し/foo、残りをURIのバックエンドサーバーに渡します/。したがって、http://myserver:80/foo/barバックエンドにに投稿しhttp://localhost:3200/barます。

proxy_passのNGINXドキュメントから:

proxy_passディレクティブがURIで指定されている場合、リクエストがサーバーに渡されると、場所に一致する正規化されたリクエストURIの一部がディレクティブで指定されたURIに置き換えられます。


12
/ foo /に/を追加したよりも私にとってはうまくいく{
Andrei N

これはまさに私が探していたものでした!
アンビニヤール

6
これは非常にクリーンなソリューションです。質問に対する正解であることが望ましいです。
ラリアン

2
末尾のスラッシュを保持または削除することの重要性を理解するには時間がかかりすぎました。
パルベス

5
これを行うと、実際に//xyzホストに渡されます。
アルキメデストラハノ

60

絶対的な最も正しい方法とベストプラクティスは、通常次のとおりです。

location /foo/ {
    proxy_pass http://localhost:3200/; # note the trailing slash!
}

  • 末尾のスラッシュがproxy_pass非常に重要であることに注意してください。これにより、$uri変数が自動的に変更さ/foo/れ、フロント/エンドとバックエンドが対応するようになります。明示的なrewriteディレクティブは必要ありません。

  • さらに、の末尾/locationも非常に重要であることに注意してください。これがないと、サイトに奇妙なURLが一時的に表示される危険があります(例:/fooenに加えて動作する/foo/en)。

    また、末尾/にあるlocationとは、proxy_passまた、いくつか確実に特別な処理をするドキュメントごとに、location効果的に暗黙のを引き起こすことが、ディレクティブlocation = /foo {return 301 /foo/;}にも。

    したがって、location上記のように末尾のスラッシュを使用してa を定義すると、スラッシュのない接尾辞URL /fooenが有効にならないだけで/fooなく、末尾のスラッシュのないa も有効になります。


参照ドキュメント:


$args失われたように見えます:http://frontend/foo?bar=bazにプロキシされhttp://backend/ます。引数はURLの一部ではないことに注意してください
-Vanuan

@バヌアン、あなたはそれについて確かですか?で明示的な変数を使用している場合を除き、$args上記のコードを使用する場合は適切に処理する$uri必要がありますproxy_pass
cnst

@cnstああ、なるほど。ホスト変数を使用しています。それは直感的ではありません。
バヌアン

1
@ArchimedesTrajano、/fooにリダイレクトするための特別な処理があるため、あなたは間違っ/foo/ています。したがって、バックエンドで何かおかしなことをしていなければ、/fooリクエストでも上記のコードで動作します。(これは実際には既に答えの一部です、ところで。)
cnst

3
このソリューションはこれらのすべてのフォーラムで勝つように見えますが、答え自体にNginxがURLをURLデコードし、デコードされたURLをプロキシサーバーに渡すことに注意する必要があります。そのため、URLにURLエンコードされた部分が含まれている場合、このソリューションは機能しません。
コーディング

1

試してみる

location /foo {
    proxy_pass http://localhost:3200/;
    ....

または

location ^~ /foo {
    proxy_pass http://localhost:3200/;
    ....

13
上記のように構成する必要がある理由を説明すると、この回答は良いでしょう。
マセガロー

これを行うと、実際に//xyzホストに渡されます。
アルキメデストラハノ

1

@Terabuckまだ返事がないのでごめんなさい。

localhostを使用しないでください。これは、hostsファイルがあるサーバーでアプリケーションが実行されているという事実に依存しているためです。ローカルホストは、127.0.0.1へのデフォルトの変換のみです。このhostsファイルを用意する必要があることを示すものは何もありません。持っているのはごく一般的なことです。

ループバックインターフェイスを使用することも、依存する一般的なものですが、ネットワークスタックのループバックインターフェイスに依存していることに変わりはありません。これらの2つがないことはまれです。これについて心配するなら。少なくともunix / linuxでは、ソケットのオプションがあります。これにより、ネットワークスタックがローカルホストに到達する必要がなくなります。ホストOSにはいくつかの要因があるため、このアプローチには注意が必要です。開いているファイルの数など。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.