Nginx Перенаправлення через проксі, переписати та зберегти URL


71

У 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веб-сервера). Однак із цим все ще є дві проблеми:

  • Він не виконує перезапис належним чином, оскільки URL-адреса запиту, отримана веб-сервером, http://192.168.1.24включає /some/pathі, отже, не обслуговує потрібну сторінку.
  • Коли ви переходите на посилання, коли сторінка розміщена, /some/pathїї немає в URL-адресі

    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. Ми можемо змінити конфігурацію на 192.168.1.24(також Nginx), проте ми хочемо спробувати уникнути цього, тому що нам потрібно буде повторити цю установку для сотень різних серверів, доступ яких проксі через example.com.

Відповіді:


59

По-перше, вам не слід використовувати rootдирективу всередині блоку розташування, це погана практика. У цьому випадку це не має значення.

Спробуйте додати другий блок місцезнаходження:

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. Ви можете зробити регулярний вираз більш конкретним, якщо вам потрібно.


1
Вибачення за пізню відповідь - це так близько до досягнення того, що ми шукаємо. Єдиним недоліком є ​​те, що після розміщення цільової сторінки URL-адреси посилань у веб-переглядачі не включають у них "/ some / path /", тобто вони не працюють, якщо користувач натискає на них. Якщо нам вдасться розібратися, як це подолати, я оновлю і прийму цю відповідь, оскільки її майже немає.
robjohncox

8
Посилання, які бачать браузер, генеруються програмним забезпеченням, що працює на сервері 192.168.1.24. Вам слід змінити це програмне забезпечення, щоб досягти того, що ви хочете.
Tero Kilkanen

не впевнений, що я дотримуюся вашого попередження про корінь всередині блоку місцезнаходження. читання документації nginx - це правильний спосіб робити речі. вони лише попереджають про погану практику від відсутності кореня за замовчуванням за межами всіх локацій. nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/…
хлопець mograbi

Що ж, простіше мати правило не використовувати rootвсередині locationблоку, тоді ви не отримаєте жодної несподіваної поведінки для стандартних місць. Тільки якщо вам потрібно змінити типовий rootдля кожного місця розташування, ви можете використовувати його.
Теро Кілканен

1
Що ви маєте на увазі під отриманням $ хоста як імені ? Що таке точний заголовок HTTP, який було надіслано, і що саме ви хочете його надіслати?
Теро Кілканен

65

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

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

@robjohncox що саме ти спробував?
Олексій Десять

9
коса риса зробила для мене трюк. Тепер mydomain.com/some/path/* вірно вказано на 192.168.1.24/*, а не на 192.168.1.24/some/path/*
Vadimo

7
Чи можу я відповісти на коментар "# відмітити цю косу рису" у цій відповіді? Три ура за цей коментар!
8one6

Не впевнений, як це працює для всіх вас. Цього я намагаюся досягти. Однак, коли користувач натискає посилання, яке перенаправить, наприклад, на 192.168.1.24/login на локальній службі, він переадресовується на mydomain.com/login замість mydomain.com/some/path/login
mueslo

4

Ви можете використовувати таку конфігурацію, щоб мати 100% безшовне відображення між /some/path/передньою стороною та /резервним.

Зауважте, що це єдина відповідь на даний момент, яка б також безперешкодно піклуватися про абсолютні шляхи, що генерують 404 Not Foundпомилки, за умови, що Refererбраузер надсилає правильний HTTP- заголовок, тому всі ці 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 сховищі.

Ось тестовий цикл, щоб підтвердити, що всі крайові випадки, здається, працюють:

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

PS Якщо у вас є багато різних шляхів до карти, то замість того , щоб робити регулярні вирази порівняння в $http_refererмежах в ifмежах location @404, ви можете захотіти використовувати глобальний основі mapдирективи замість цього.

Також зауважте, що кінцеві косої риски як у proxy_pass, так і в тому, що locationвони містяться, є досить важливими відповідно до відповідної відповіді .

Список літератури:


2

Коли ця косою рискою додається до nnkx проксі-сервісних джинкінів, ви отримуєте помилку "Здається, що ваш зворотний проксі-сервер порушений".

proxy_pass          http://localhost:8080/;

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

Це слід прочитати

proxy_pass          http://localhost:8080;

Я не думаю, що саме з цим питанням ОП було пов'язано і не вирішує жодне із згаданих питань.
Кори Робінсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.