Co się stanie gdy wywołamy taki adres?
http://adres.pl/katalogObsługując taki adres serwer Apache spróbuję udostępnić plik o nazwie /katalog (względem DocumentRoot). Gdy się okaże, że pod tą nazwą w systemie plików znajduję się katalog serwer wykona przekierowanie (HTTP 301) na adres:
http://adres.pl/katalog/W przekierowaniu jest podany adres bezwzględny (pełny URL). Przy tworzeniu pełnego adresu Apache ustawia rodzaj protokołu (scheme). Domyślna wartość dla scheme to http. Gdy aktywny jest jakiś moduł SSL/TLS (np. mod_ssl) dla vhostów z obsługą SSL-a zwracana jest wartość https.
Na problem możemy natrafić gdy terminacja SSL/TLS obywa się w innym miejscu niż Apache (przykład terminacji na serwerze Nginx). W takiej sytuacji komunikacja serwera proxy z serwerem Apache odbywa się najczęściej po "czystym" protokole HTTP i Apache wygeneruję przekierowanie bezwzględne zawierające http://.
Najprostszym rozwiązaniem tego problemu w przypadku Nginx jest wykorzystanie dyrektywy proxy_redirect. Pozwala ona na podmianę w odpowiedzi z backendu np. http:// na https://. Wykorzystując to rozwiązanie może być trudno wykonać celowe przekierowanie z poziomu backendu (np. aplikacji php) na adres http:// - może ono zostać zamienione na https://.
Poniższy bardzo prosty moduł dla Apache (dla wersji 2.2.x) rozwiązuję ten problem. Rozwiązanie opiera się na przekazaniu przez serwer proxy nagłówka (X-Forwarded-Proto) informującego jaki protokół został użyty przy połączeniu. Poniższy moduł po wykryciu takiego nagłówka "informuję" serwer Apache o odpowiednim typie protokołu (zmienia nazwę dla scheme) dla danego requesta.
Moduł jest bardzo prosty. Posiada zaszyte informacje o nazwie nagłówka i dopuszcza tylko zmianę jeśli request został wywołany z adresu 127.0.0.1. Moduł celowo nie obsługuję żadnych parametrów konfiguracyjnych - jeśli moduł zostanie wyłączony konfiguracja serwera Apache będzie dalej prawidłowa (nie będzie nieznanych dyrektyw konfiguracyjnych).
Poniżej kod źródłowy modułu (w języku C) i pakiety RPM.
Pakiet RPM dla CentOS 6.x x86_64
Pakiet SRPMS
/* * mod_rpsm.c (Reverse Proxy Scheme Module) * Version: 1.0 * License: Public Domain * * Author: Robert Socha * EMail: socha@socha.it * * Simple module to set Apache scheme (https or http) when request are coming from * reverse proxy/ssl terminator (eg. Nginx) * No configuration directives - pass X-Forwarded-Proto header from proxy * (and set it to https) * * Compile: apxs -c mod_rpsm.c * */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" module AP_MODULE_DECLARE_DATA rpsm_module; static const char *rpsm_http_scheme(const request_rec *r) { const char *xfproto; if( (strcmp(r->connection->remote_ip,"127.0.0.1")==0) && (xfproto = apr_table_get(r->headers_in, "X-Forwarded-Proto")) && (strcmp(xfproto,"https") == 0)) { return "https"; } return NULL; } static void rpsm_register_hooks(apr_pool_t *p) { ap_hook_http_scheme(rpsm_http_scheme, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA rpsm_module = { STANDARD20_MODULE_STUFF, NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server configs */ NULL, /* command apr_table_t */ rpsm_register_hooks, /* register hooks */ };