web-dev-qa-db-ja.com

Nginx Redirect via Proxy、Rewrite and Preserve URL

Nginxでは、次のようにURLをリダイレクトしようとしています。

http://example.com/some/path -> http://192.168.1.24

ユーザーはブラウザに元のURLを表示します。ユーザーがリダイレクトされた後、/section/index.htmlへのリンクをクリックすると、リダイレクトにつながるリクエストを実行します

http://example.com/some/path/section/index.html -> http://192.168.1.24/section/index.html

再び元のURLを保持します。

私たちの試みには、プロキシと書き換えルールを使用したさまざまなソリューションが含まれています。以下は、ソリューションに最も近い構成を示しています(これはexample.com WebサーバーのWebサーバー構成です)。ただし、これにはまだ2つの問題があります。

  • Webサーバーが受信したリクエストURL http://192.168.1.24/some/pathが含まれているため、必要なページを提供できないため、正しく書き換えられません。
  • ページが提供された後にリンクにカーソルを合わせると、URLに/some/pathがありません

    server {
        listen          80;
        server_name     www.example.com;
    
        location /some/path/ {
            proxy_pass http://192.168.1.24;
            proxy_redirect http://www.example.com/some/path http://192.168.1.24;
            proxy_set_header Host $Host;
        }
    
        location / {
            index index.html;
            root  /var/www/example.com/htdocs;
        }
    }
    

example.comのWebサーバー構成を変更するだけのソリューションを探しています。 192.168.1.24(Nginxも)の構成を変更できますが、example.comを介してアクセスがプロキシされる数百の異なるサーバーに対してこの設定を繰り返す必要があるため、これを避けたいと思います。

77
robjohncox

まず、ロケーションブロック内でrootディレクティブを使用しないでください。これは悪い習慣です。この場合は問題ではありません。

2番目のロケーションブロックを追加してみてください。

location ~ /some/path/(?<section>.+)/index.html {
    proxy_pass http://192.168.1.24/$section/index.html;
    proxy_set_header Host $Host;
}

これは、/ some/path /の後のindex.htmlの前の部分を$ section変数にキャプチャし、proxy_pass宛先を設定するために使用されます。必要に応じて、正規表現をより具体的にすることができます。

62
Tero Kilkanen

proxy_pass ディレクティブではURI部分を使用する必要があります。また、proxy_redirectディレクティブの順序引数を混同しているため、おそらくまったく必要ありません。 Nginxには、このディレクティブの適切なデフォルトがあります。

この場合、あなたのlocationブロックは本当に簡単です:

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # note this slash  -----------^
    proxy_set_header Host $Host;
}
67
Alexey Ten

次の設定を使用して、フロントエンドの/some/path/とバックエンドの/を100%シームレスにマッピングできます。

これがこれまでの唯一の回答であり、ブラウザから正しいHTTP Refererヘッダーが送信された場合、404 Not Foundエラーを生成する絶対パスもシームレスに処理するので、これらのgifはすべてロードせずに引き続きロードする必要があります。基になるHTMLを変更する必要があります(コストがかかるだけでなく、デフォルトでコンパイルされていない追加のモジュールがないとサポートされません)。

location /some/path/ {
    proxy_pass http://192.168.1.24/; # note the trailing slash!
}
location / {
    error_page 404 = @404;
    return 404; # this would normally be `try_files` first
}
location @404 {
    add_header Vary Referer; # sadly, no effect on 404
    if ($http_referer ~ ://[^/]*(/some/path|/the/other)/) {
        return 302 $1$uri;
    }
    return 404 "Not Found\n";
}

https://github.com/cnst/StackOverflow.cnst.nginx.conf リポジトリ内で コンセプトの完全な証明とminimal-viable-product を見つけることができます。

以下は、すべてのEdgeケースが機能しているように見えることを確認するためのテスト実行です。

curl -v -H 'Referer: http://example.su/some/path/page.html' localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
> Referer: http://example.su/some/path/page.html
< HTTP/1.1 302 Moved Temporarily
< Location: http://localhost:6586/some/path/and/more.gif
< Vary: Referer

curl -v localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
< HTTP/1.1 404 Not Found

curl -v localhost:6586/some/path/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location -e uri
> GET /some/path/and/more.gif HTTP/1.1
< HTTP/1.1 200 OK
request_uri:    /and/more.gif

追伸マップするさまざまなパスがたくさんある場合は、$http_referer内のif内でlocation @404の正規表現比較を行う代わりに、グローバルベースのmapディレクティブを使用することをお勧めします。

また、proxy_passと、それが含まれるlocationの両方の末尾のスラッシュにも注意してください 関連する回答によると非常に重要です

参照:

5
cnst

そのスラッシュがnginxプロキシジェンキンに追加されると、「リバースプロキシの設定が壊れているようです」というエラーが表示されます。

proxy_pass          http://localhost:8080/;

Remove this -----------------------------^

読むべき

proxy_pass          http://localhost:8080;
2
tomdunn