Як мені переписати URL-адреси у відповіді проксі-сервера в NGINX


86

Я звик використовувати Apache з mod_proxy_html і намагаюся домогтися чогось подібного з NGINX. Конкретний випадок використання полягає в тому, що у мене є інтерфейс адміністратора, запущений у Tomcat на порту 8080 на сервері в кореневому контексті:

http://localhost:8080/

Мені потрібно показати це на порту 80, але у мене є інші контексти на сервері NGINX, запущеному на цьому хості, тому хочу спробувати отримати доступ до цього за адресою:

http://localhost:80/admin/

Я сподівався, що це зробить наступний надпростий серверний блок, але це не зовсім так:

server {
    listen  80;
    server_name screenly.local.akana.com;

    location /admin/ {
        proxy_pass http://localhost:8080/;
    }
}

Проблема полягає в тому, що повернутий вміст (html) містить URL-адреси сценаріїв та інформацію про стиль, до якої можна отримати доступ у кореневому контексті, тому мені потрібно перезаписати ці URL-адреси, щоб почати з / admin / замість /.

Як це зробити в NGINX?

Відповіді:


121

Спочатку слід уважно та повно прочитати документацію щодо proxy_pass .

URI, що передається вихідному серверу, визначається залежно від того, використовується директива "proxy_pass" з URI чи ні. Кінцева коса риса в директиві proxy_pass означає, що URI присутній і дорівнює /. Відсутність косої риски означає, що URI капелюха відсутній.

Proxy_pass з URI :

location /some_dir/ {
    proxy_pass http://some_server/;
}

З урахуванням вищесказаного, є такий проксі:

http:// your_server/some_dir/ some_subdir/some_file ->
http:// some_server/          some_subdir/some_file

В основному, /some_dir/замінюється на, /щоб змінити шлях запиту з /some_dir/some_subdir/some_fileна /some_subdir/some_file.

Proxy_pass без URI :

location /some_dir/ {
    proxy_pass http://some_server;
}

З другим (без кінцевої риски): проксі працює так:

http:// your_server /some_dir/some_subdir/some_file ->
http:// some_server /some_dir/some_subdir/some_file

По суті, повний вихідний шлях запиту передається без змін.


Отже, у вашому випадку, здається, вам слід просто скинути кінцеву риску, щоб отримати те, що ви хочете.


Застереження

Зверніть увагу, що автоматичний перезапис працює, лише якщо ви не використовуєте змінні в proxy_pass. Якщо ви використовуєте змінні, вам слід переписати себе:

location /some_dir/ {
  rewrite    /some_dir/(.*) /$1 break;
  proxy_pass $upstream_server;
}

Бувають інші випадки, коли перезапис не спрацьовував, тому читання документації є обов’язковим.


Редагувати

Читаючи ваше запитання ще раз, здається, я, можливо, пропустив, що ви просто хочете відредагувати висновок html.

Для цього ви можете використовувати директиву sub_filter . Щось на зразок ...

location /admin/ {
    proxy_pass http://localhost:8080/;
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

В основному, рядок, який ви хочете замінити, і рядок заміни


2
Дякую, це дуже допомагає. Я думаю, що sub_filter це зробить.
IanG

2
Мені цікаво, наскільки nginx вже переписує вихідні дані, чи не потрібно буде перезаписувати хост / ім'я хосту у посиланнях як мінімум? Так, наприклад, чи не такsub_filter "http://localhost/" "http://localhost/admin/"
ThorSummoner

1
Щоб дозволити перезапис, крім text/htmlmimeype, мені довелося також додати sub_filter_types *;.
anttikoo

Щось дивне відбувається для мене з цим рішенням. Ресурси (* .js, * .css тощо отримуються), але сторінка не завантажується. я мав би розраховувати http://your_server/admin/на вирішення проблеми http://your_serverпід час proxy_pass, але це не так, і я отримую помилку react-router /admin/ location did not match any routesв моїй програмі, оскільки моя програма нічого не знає про '/ admin'.
Прачі,

Можливо, вам також доведеться додати proxy_redirectдирективу, щоб Locationзаголовок, надісланий відповіддю, також був змінений відповідно до URL-адреси. Ознайомтесь із цим посібником: cyberciti.biz/faq/…
vivanov

21

Вам також може знадобитися встановити наступну директиву перед першим "sub_filter" для серверних серверів із стисненням даних:

proxy_set_header Accept-Encoding "";

Інакше це може не спрацювати. Для вашого прикладу це буде виглядати так:

location /admin/ {
    proxy_pass http://localhost:8080/;
    proxy_set_header Accept-Encoding "";
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

-2

Ви можете використовувати наступний приклад конфігурації nginx:

upstream adminhost {
  server adminhostname:8080;
}

server {
  listen 80;

  location ~ ^/admin/(.*)$ {
    proxy_pass http://adminhost/$1$is_args$args;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
  }
}

1
Чому це проти? Будь-яка проблема з кодом? Мені здається приємним і складним рішенням, вирішення деяких застережень проксірування програми, які з’являються пізніше. Не знаю, чому proxy_redirect off;. Також я б додав proxy_set_header X-Forwarded-Proto $scheme;.
LuH
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.