Как переписать 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?

IanG
источник

Ответы:

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;
}

По сути, строка, которую вы хотите заменить, и строка замены

Dayo
источник
2
Спасибо, это очень помогает. Думаю, sub_filter это сделает.
IanG
2
Мне любопытно, до какой степени nginx уже переписывает вывод, разве ему не нужно как минимум переписывать хост / имя хоста в ссылках? Так, например, не могли бы выsub_filter "http://localhost/" "http://localhost/admin/"
ThorSummoner
1
Чтобы разрешить переписывание, отличное от text/htmlmimetype, мне также пришлось добавить 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'.
Prachi
Вам также может потребоваться добавить proxy_redirectдирективу, чтобы Locationзаголовок, отправленный ответом, также изменялся в соответствии с URL-адресом. Ознакомьтесь с этим руководством: cyberciti.biz/faq/…
vivanov
21

Вам также может потребоваться установка следующей директивы перед первым "sub_filter" для backend-серверов со сжатием данных:

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