web-dev-qa-db-ja.com

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

http://example.com/で実行中のWebアプリケーションがあり、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をリッスンするように、「アップストリーム」を書き換える必要がありますか?または、上流に渡されるパスを書き換えることができるディレクティブはありますか?

93
berkes

これは、正規表現を使用せずに、必要なことを行う最も効率的な方法です。

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

私は、人気が高まっている、より新しい正規表現ベースの回答に取り組みたいと思います。

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

ソリューションは一見するとよりかわいく見えるかもしれませんが、いくつかの理由で間違っています。

  • 上記の正規表現は_/enjoy_のリクエストURIに一致し、それを_/joy_アップストリームにリダイレクトします。これは本当に意図されているのですか?

  • _/en_のリクエストはリダイレクトされず、上流から_/_を直接提供します(代わりに_/en/_のリクエストが行われたかのように、完全ではありません)。上流のルートページ内で相対URIを使用する場合(そうでない場合、上流のURI内に_/en/_プレフィックスが付いていないのはなぜですか?)、たとえば_src="style.css"_(たとえば、言語固有のurl("menu.png")を参照する場合があります)の場合、ブラウザは_/style.css_ではなく_/en/style.css_として要求します。 (または、どこでも絶対URIを使用している場合でも、誰かがあいまいなセミオプションリソースを相対的に参照している場合はどうなりますか?).

  • 私の OP自身の回答ですでに言及されている別の質問での以前のアドバイス のように、正規表現を使用すると _proxy_redirect_ ディレクティブがdefault、代わりにoffに下げます。これは、_Location: http://127.0.0.1:8080/en/dir/_の要求が行われたときにアップストリームが_/en/dir_で応答した場合、クライアントがそれを表示し、明らかに正しく動作しないことを意味します。 (これは、最初に正規表現の使用を促す_/en_要求に対して特に皮肉なことでしたが、この特定の実装は、前述のように別の問題に悩まされています。)さらに、すでに-を使用している場合 upstream ディレクティブ。カスタムサーバーを使用しようとすると、特に複数の上流サーバーがある場合は、さらに醜くなる可能性があります。別の_proxy_redirect_それらのそれぞれについて? _proxy_redirect_内で正規表現を使用して、任意のホストに一致させることもできますが、将来的にクロスドメインリダイレクトを指定する場合はどうでしょうか。

単一の正規表現ベースの場所で上記のポイントのいくつかに対処するには、次のようにします(_proxy_pass_では、upstreamからサーバーへの参照も削除する必要があることに注意してください)ベースのディレクティブ、_proxy_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つの兄弟の最上位の場所を含む元のソリューション は、代わりに正規表現のルートを使用してウサギの穴を掘り下げるよりも優れたアイデアです。

12
cnst

だから、私は 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に渡します。

6
berkes

会計 Nginxドキュメント

リクエストをHTTPプロキシサーバーに渡すには、場所内にproxy_passディレクティブを指定します。例えば:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

この構成例では、この場所で処理されたすべての要求を、指定されたアドレスのプロキシサーバーに渡します。このアドレスは、ドメイン名またはIPアドレスとして指定できます。アドレスにはポートが含まれる場合もあります。

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

上記の最初の例では、プロキシされたサーバーのアドレスの後にURI/link /が続いていることに注意してください。 URIがアドレスとともに指定されている場合、それは、locationパラメーターと一致する要求URIの一部を置き換えます。たとえば、ここでは/some/path/page.html URIを含むリクエストは http://www.example.com/link/page.html にプロキシされます。 URIなしでアドレスが指定されている場合、または置き換えられるURIの部分を判別できない場合は、完全な要求URIが渡されます(おそらく変更されます)。

0
Jeff