Jak poprawnie obsługiwać względne adresy URL za pomocą zwrotnego serwera proxy

51

W Apache mam odwrotną konfigurację proxy:

Serwer A z adresem www.example.com/folder to serwer odwrotnego proxy.

Mapuje na: Serwer B z adresem test.madeupurl.com

Ten rodzaj działa. Ale moim problemem jest to, że na www.example.com/folder wszystkie linki względne mają postać www.example.com/css/examplefilename.css, a nie www.example.com/folder/css/examplefilename. css

Jak to naprawić?

Jak dotąd mój zwrotny serwer proxy ma to na serwerze A (www.example.com):

<Location /folder>
    ProxyPass  http://test.madeupurl.com
    ProxyPassReverse http://test.madeupurl.com
</Location>
Ciężko pracujący
źródło
Które z poniższych rozwiązań działało dla Ciebie w odpowiedzi HBruijn, jeśli pamiętasz?
Kimberly W

Odpowiedzi:

81

Apache ProxyPassRewrite nie przepisuje treści odpowiedzi otrzymanych ze strony http://test.example.com , a jedynie nagłówki (takie jak przekierowania do strony 404 itp.).

Szereg alternatyw:

Jeden ) Przepisz aplikację wewnętrzną, aby używała ścieżek względnych zamiast bezwzględnych. tj. ../css/style.csszamiast/css/style.css

Dwa ) Wdróż ponownie aplikację wewnętrzną w tym samym podkatalogu, /foldera nie w katalogu głównym test.example.com.

Trzy ) Raz i dwa często się nie zdarzają ... Jeśli masz szczęście, wewnętrzna aplikacja używa tylko dwóch lub trzech podkatalogów i nie są one używane w Twojej głównej witrynie , po prostu napisz kilka wierszy ProxyPass:

# Expose Internal App to the internet.
ProxyPass /externalpath/  http://test.example.com/
ProxyPassReverse /externalpath/  http://test.example.com/
# Internal app uses a bunch of absolute paths. 
ProxyPass /css/  http://test.example.com/css/
ProxyPassReverse /css/  http://test.example.com/css/
ProxyPass /icons/  http://test.example.com/icons/
ProxyPassReverse /icons/  http://test.example.com/icons/

Cztery ) Utwórz osobną subdomenę dla wewnętrznej aplikacji i po prostu odwróć wszystko proxy:

<VirtualHost *:80>
   ServerName app.example.com/
   # Expose Internal App to the internet.
   ProxyPass /  http://test.internal.example.com/
   ProxyPassReverse /  http://test.internal.example.com/
</VirtualHost>

Pięć ) Czasami deweloperzy są całkowicie nieświadomi i mają swoje aplikacje generują nie tylko absolutny URL, ale nawet to część nazwy w ich URL i otrzymany kod HTML wygląda następująco: <img src=http://test.example.com/icons/logo.png>.

Odp. ) Możesz użyć rozwiązania kombi DNS DNS z podziałem horyzontu i scenariusza 4. Zarówno użytkownicy wewnętrzni, jak i zewnętrzni korzystają z witryny test.example.com, ale wewnętrzny serwer DNS wskazuje bezpośrednio adres IP serwera test.example.com. W przypadku użytkowników zewnętrznych rekord publiczny dla test.example.com wskazuje adres IP publicznego serwera internetowego www.example.com, a następnie można użyć rozwiązania 4.

B ) W rzeczywistości można uzyskać apache do nie tylko żądań proxy do test.example.com, ale także przepisać treść odpowiedzi, zanim zostanie ona przesłana do użytkowników. (Zwykle serwer proxy przepisuje tylko nagłówki / odpowiedzi HTTP). mod_substitute w apache 2.2. Nie testowałem, czy dobrze układa się z mod_proxy, ale może następujące działa:

<Location /folder/>
  ProxyPass http://test.example.com/
  ProxyPassReverse http://test.example.com/ 
  AddOutputFilterByType SUBSTITUTE text/html
  Substitute "s|test.example.com/|www.example.com/folder/|i" 
</Location>
HBruijn
źródło
4
Święta krowa dobra odpowiedź. Jeszcze nie próbowałem żadnego z nich, ale chciałem tylko podziękować za napisanie! Pomaga milionowi. Zamierzam teraz przetestować niektóre z tych pomysłów i wkrótce zdam relację :)
Ciężki pracownik
Szybkie pytanie, proszę, w punkcie 2, jeśli dobrze rozumiem, proszę pana, sugeruję ponowne wdrożenie programu adpp na test.madeupurl.com/folder? Czy wymagałoby to zmian w moim pliku konfiguracyjnym Apache? To wygląda na najszybsze rozwiązanie
pracowity robotnik
Dodatkowo przepraszam, że przeszkadzam, ale w punkcie 1, gdy próbuję zaproponować problem, który opisuję w moim pytaniu, nadal występuje. Na przykład użyłem tutaj: <link rel = "stylesheet" type = "text / css" href = "../ css / custom.css" /> i dla adresu linku w przeglądarce wyświetla test.madeupurl.com /css/bootstrap.css zamiast test.madeupurl.com/folder/css/bootstrap.css . Czy miałbyś jakieś sugestie na ten temat, byłoby to najbardziej pomocne
pracowity robotnik
Często po ponownym wdrożeniu aplikacji, która jest teraz zainstalowana w DocumentRoot, w podkatalogu, takim jak / folder, arkusze stylów, ikony itp. Zostaną wdrożone w / folder / css i / folder / ikony itp. Następnie linki w danych wyjściowych HTML staną się takie, <img src=/folder/icons/button.png>które w kolej zostanie złapana przez ProxyPass /folder/ http://test.madeupurl.com/folder/dyrektywę.
HBruijn,
Strona test.madeupurl.com/content/index.html chce dołączyć test.madeupurl.com/css/custom.css. W tej lokalizacji powinieneś używać względnego adresu URL, href="../css/custom.css"a nie href="/css/custom.css". Gdy użytkownik Internetu pobierze stronę, adres URL będzie wynosić www.example.com/folder/content/index.html. Adres URL css będzie wtedy: www.example.com/folder/content/../css/custom.cssktóry faktycznie www.example.com/folder/css/custom.csszostanie przekazany test.madeupurl.com/css/custom.css.
HBruijn,
8

Jako uzupełnienie odpowiedzi HBruijn , jeśli zdecydujesz się na rozwiązanie (3) „ProxyPass”, być może będziesz musiał użyć mod_proxy_html do przepisania niektórych adresów URL na twoich stronach HTML.

por. Jak poprawnie obsługiwać względne adresy URL z odwrotnym proxy dla niektórych przykładów.

Jako zastosowany przykład, oto jak możesz skonfigurować Apache przy użyciu ProxyHTMLURLMapreguły, aby przekazywać wszystko z twoja-domena-nazwa.com/pad do instancji Etherpad działającej lokalnie na porcie 9001:

<Location /pad> ProxyPass http://localhost:9001 retry=0 # retry=0 => avoid 503's when restarting etherpad-lite ProxyPassReverse http://localhost:9001 SetOutputFilter proxy-html ProxyHTMLURLMap http://localhost:9001 </Location> RewriteRule ^/pad$ /pad/ [R]

Lucas Cimon
źródło
2
Pamiętaj jednak, że mod_proxy_html jest dołączany tylko z Apache 2.4 i nowszych, gdzie powyższe oryginalne pytanie dotyczy Apache 2.2
HBruijn 10.10.14
Twoja odpowiedź jest nienaganna. Spotkałem jednak przypadek, w którym treść nie jest w formacie HTML, a raczej w formacie pdf. Korzystanie z ProxyHTMLURLMap nie działało dla mnie. Jakieś inne sugestie?
Mohamed Ennahdi El Idrissi
2
Jeśli twoja treść jest plikiem PDF, nie musisz przepisywać w niej adresów URL! Chyba że chcesz, aby użytkownicy klikali łącza w pliku PDF, aby uzyskać dostęp do innych stron Twojej witryny, ale wydaje się to trudne. Aby wyłączyć przepisywanie adresów URL, po prostu pomiń 2 ostatnie dyrektywy: SetOutputFilter& ProxyHTMLURLMap.
Lucas Cimon,
Być może trzeba dodać RequestHeader niezaszyfrowane Accept-Encoding, aby uniknąć błędów kodowania
zar3bski
5

Aby utworzyć odwrotne proxy, możesz użyć następującego sposobu:
1. Zainstaluj mod_proxy_html

    yum install mod_proxy_html
  1. Załaduj moduł mod_proxy_html

    LoadModule proxy_html_module modules/mod_proxy_html.so
    
  2. I użyj następującego ustawienia

    ProxyRequests off  
    ProxyPass /folder/  http://test.madeupurl.com  
    ProxyHTMLURLMap http://test.madeupurl.com  /folder  
    
    <Location /folder/>  
        ProxyPassReverse /  
        ProxyHTMLEnable On  
        ProxyHTMLURLMap  /  /folder/  
        RequestHeader    unset  Accept-Encoding  
    </Location>  
    

Mam nadzieję, że to pomoże.

ThanhHH
źródło