nginx proxy_passでパスを削除する方法

nginx proxy_passでパスを削除する方法

で実行中の Web アプリケーションがありhttp://example.com/、 の別のサーバーに別のアプリケーションを「マウント」したいと考えていますhttp://example.com/en。アップストリーム サーバーと はproxy_pass動作しているように見えますが、1 つの問題があります。

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

を開くとexample.com/en、アップストリーム アプリケーションは を返します404 not found /en。アップストリームにはパス がないため、これは当然のことです/en

proxy_path正しい解決策でしょうか?/en代わりにルート パスとしてリッスンするように「upstream」を書き換えるべきでしょうか? または、upstream に渡されるパスを書き換えることができるディレクティブはありますか?

答え1

これは、正規表現を使用せずに目的を達成するための最も効率的な方法である可能性があります。

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}

答え2

人気が高まっている、新しい正規表現ベースの回答について説明したいと思います。

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

この解決策は一見するとより魅力的に見えるかもしれませんが、いくつかの理由から間違っています。

  • 上記の正規表現は、 のリクエスト URI に一致し/enjoy、アップストリームにリダイレクトします/joy。これは本当に意図されたものなのでしょうか?

  • をリクエストしても/enリダイレクトは発生せず、/アップストリームから が直接提供されます(/en/代わりに をリクエストした場合とほとんど同じですが、完全には異なります)。ルート ページ アップストリーム内で相対 URI を使用する場合(そうでなければ、/en/アップストリーム URI 内にプレフィックスを配置しないのはなぜでしょうか?)、たとえば(これは、たとえばsrc="style.css"言語固有の を参照する可能性があります)、ブラウザーはではなくを要求します。(または、すべての場所で絶対 URI を使用している場合でも、誰かがあいまいな半オプションのリソースを相対的に参照するとどうなるでしょうか?)おっと、突然サイトが機能しなくなる可能性がありますが、それは時々、またはエッジ ケースのみです。url("menu.png")/style.css/en/style.css

  • 私のOP自身の回答で既に言及されている別の質問に対する以前のアドバイス正規表現を使用すると、proxy_redirectディレクティブのデフォルト値を から にdefault下げますoff。つまり、Location: http://127.0.0.1:8080/en/dir/のリクエストに対してアップストリームが で応答した場合/en/dir、クライアントはそれを見ることになり、明らかに正しく動作しません。(そもそも/en正規表現の使用を促すリクエストの場合、これは特に皮肉なことですが、この特定の実装では、すでに上で述べたように別の問題が発生します。) さらに、すでに を使用している場合は、upstreamディレクティブを使用する場合、カスタム ディレクティブを使用しようとすると、特に複数のアップストリーム サーバーがある場合に、proxy_redirectそれぞれに個別の ディレクティブを用意するにはどうすればよいでしょうか。 内で正規表現を使用してproxy_redirect、任意のホストに一致させることもできますが、将来的にクロスドメイン リダイレクトを行うことにした場合はどうなるでしょうか。

上記の点のいくつかを単一の正規表現ベースの場所で解決するには、次の操作を実行します (よりわかりやすくするために、 では、 ベースのディレクティブproxy_passからサーバーへの参照を削除する必要があったことに注意してください)。upstreamproxy_redirect

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

だから、私に言わせれば、2つの兄弟トップレベルの場所を使用したオリジナルのソリューション正規表現ルートを使用して自分自身をウサギの穴に掘るよりも、それでもまだ良いアイデアです。

答え3

そこで私はstackoverflowの回答:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

基本的には、正規表現を場所に渡し、backref を proxy_pass URL に渡します。

答え4

私は上記の受け入れられた解決策を試してみましたが、すべてのCSSとJSアセットで不正なリダイレクトを引き起こしていることがわかりました。最終的には、LinuxServer SWAG Nginx構成の実行方法からインスピレーションを得ました。ここ。 を見てみましょうpihole.subfolder.conf.sample

したがって、私の解決策は次のようになります。

location /en {
    return 302 $scheme://$host/en/;
}

location ^~ /en/ {
    set $upstream_app lixxxx.members.linode.com;
    set $upstream_port 9001;
    set $upstream_proto http;
    proxy_pass $upstream_proto://$upstream_app:$upstream_port;

    rewrite /en(.*) $1 break;
}

関連情報