Ostatnio trafiłem na ciekawy problem, który wielokrotnie rozwiązywałem w nginx’ie ale tym razem musiałem zrobić to w Apache. Pewna stronka działa sobie na HTTPS’ie i chciałem by wszystkie powiązane z nią pliki były serwowane z jej adresu szyfrowanym połączeniem by nie pojawiały się w przeglądarce monity że “część ruchu nie jest szyfrowana”. Tyle że część potrzebnych plików była już obecnie serwowana na innym serwerze (w innej domenie) poprzez HTTP.

Mogłem albo skopiować te pliki i wykombinować jakiś mechanizm synchronizujący albo wykorzystać proxy + cache. Drugie rozwiązanie wydało mi się prostsze i ładniejsze 😃

Na początek włączamy w Apache’m odpowiednie moduły:

a2enmod proxy
a2enmod proxy_http

Teraz przykładowa konfiguracja vhosta:

<VirtualHost *:80>
#podstawowa konfiguracja vhosta
ServerAdmin webmaster@example.com
ServerName www.example.com
ServerAlias example.com

# wyłącza działanie Apache'go jako przekazującego proxy (forwarding proxy)
ProxyRequests Off

# nie chciałem by błędy HTTP z backendowego serwera były przekazywane
# zamiast nich będą błędy Apache'go
ProxyErrorOverride On

# przykład prostego reverse proxy - wystarczą dwa poniższe polecenia
# ProxyPass proxuje ruch do danego serwera pod wskazanym URL'em
ProxyPass /stats/ http://google-anal.com/
# ProxyPassReverse modyfikuje nagłówki odpowiedzi ze zdalnego serwera
# tak by odpowiedź wyglądała na wysłaną z lokalnego serwera
ProxyPassReverse /stats/ http://google-anal.com/

# ciekawszy przykład proxowania z dodatkowymi ustawieniami cachowania
# najpierw konfiguracja cache'u dyskowego
<IfModule mod_disk_cache.c>
 # CacheRoot to wymagany parametr - ścieżka w której znajduje się cache
 CacheRoot /var/cache/apache2/mod_disk_cache/example

 # ponieważ przewidywałem że cache'owanych będzie kilka GB małych plików
 # to by listowanie ich w cache'u było efektywne warto wykorzystać wielo
 # poziomowe zagłębienie katalogów - wtedy na każdym poziomie, w danym
 # katalogu będzie stosunkowo mało plików, indeksy mniejsze, listowanie
 # szybsze
 CacheDirLevels 5
 CacheDirLength 2

 # teraz czas na konfiguracje cache'u
 <IfModule mod_cache.c>
  # pozwolę sobie na zignorowanie nagłówków Expires/Cache-Control
  # z aplikacji sam lepiej wiem że te pliki nie zmieniają się
  # zbyt często
  CacheIgnoreCacheControl On
  # pliki stracą ważność w cache'u po tygodniu
  CacheDefaultExpire 604800

  # ponieważ zasoby nie różnią się dla różnych zalogowanych użytkowników
  # zignoruję cookies'y
  CacheIgnoreHeaders Set-Cookie

  # nie chcę by proxy weryfikowało czy pojawiła się nowa wersja obrazka
  # bo raczej rzadko pojawiają się zmiany
  CacheIgnoreNoLastMod On

  # cache uruchamiany dla dwóch "subkatalogów"
  # http://example.com/images oraz http://example.com/files
  CacheEnable disk /images
  CacheEnable disk /files
 </IfModule>
</IfModule>

# włączamy mod_rewrite - będzie za chwilkę potrzebny
RewriteEngine on

# poprzednio do uruchomienia proxy wykorzystałem opcję ProxyPass,
# ale często potrzebujemy bardziej zaawansowanego przekierowania
# i wtedy warto wykorzystać mod_rewrite do modyfikacji URL'i w locie
# koniecznie z flagą [P]
RewriteRule ^/images/(.+)/(.+) http://10.0.0.100:8080/example-images/get.php?id=$1&width=$2 [P]
<Location /images>
 # jak powyżej - modyfikacja zwrotnych nagłówków
 ProxyPassReverse /example-images/

 # kilka nagłówków z backendu ukrywam by nie były przekazywane dalej
 Header unset Server
 Header unset Expires
 Header unset ETag
 # akurat nagłówek Via można wyłączyć w konfiguracji modułu proxy
 # ale ponieważ bywa przydatny przy debugowaniu to w niektórych miejscach
 # wolę gdy jest ustawiony - a w innych nie
 Header unset Via

 # ręczne ustawienie nagłówka Cache-Control i zezwolenie
 # na cachowanie przez inne proxy lub przeglądarki
 Header set Cache-Control "max-age=604800, public"
</Location>

# i drugie przekierowanie
RewriteRule ^/files/(.+)/(.+) http://10.0.0.100:8080/example-files/$1/$2 [P]
<Location /files>
 ProxyPassReverse /example-files/
 Header unset Server
 Header unset Via
 Header unset ETag
 Header unset Expires
 Header set Cache-Control "max-age=604800, public"
</Location>

# standardowa konfiguracja
DocumentRoot /var/www/example
<Directory /var/www/example>
 Options -Indexes FollowSymLinks Includes
 AllowOverride None
 Order allow,deny
 Allow from all
</Directory>

LogLevel warn
CustomLog /var/log/apache2/example_access.log combined
</VirtualHost>