Убедить Apache в первоначальном клиентском протоколе

Итак, у меня есть относительно прямой серверный стек, использующий разгрузку SSL и балансировщик нагрузки HTTP. Настройка выглядит примерно так:

(client) -> (SSL offload - stud) -> (balancer - haproxy) -> (http server - apache)

Мой вопрос не в том, чтобы подключить все это. Он отлично работает, и я честно сдулся о том, как прямо он должен был это сделать. Я также добавлю, что HTTP-клиенты напрямую подключаются к haproxy, тем самым минуя отключенный SSL. И для записи есть избыточные партнеры для каждой из вышеперечисленных частей.

Проблема несколько абстрактная. Я начну с демонстрации. Клиент делает запрос через установку до https://myserver.tld/scp (некоторые заголовки удалены, чтобы все было ясно)

GET /scp HTTP/1.1
Host: myserver.tld
(headers added by haproxy)
X-Forwarded-For: [original::client:ip]
X-Forwarded-Proto: https

И сервер отвечает

HTTP/1.1 301 Moved Permanently
Date: Wed, 03 Jul 2013 03:16:25 GMT
Server: Apache/2.2.15 (CentOS)
Location: http://myserver.tld/scp/
Content-Length: 344
Content-Type: text/html; charset=iso-8859-1

Итак, Apache mod_dir отправляет перенаправление на тот же URL-адрес с завершающей косой чертой. Правильно это сделать. Это не проблема. Проблема в том, что протокол HTTPS был потерян. Опять же, я думаю, что Apache правильно перенаправляется на HTTP-URL, в конце концов, соединение, которое оно получало из вышеупомянутого стека, является обычным HTTP-соединением.

Итак, с точки зрения Apache, клиент запросил регулярное HTTP-соединение. Флаг HTTPS выключен вместе со всей другой информацией SSL, поскольку SSL-часть сеанса обрабатывается шпилем.

Хотя (внутри Apache) у меня есть допустимый заголовок X-Forwarded-Proto, я не могу найти способ сообщить Apache, что исходное клиентское соединение было HTTPS и что перенаправление каталога slash с помощью mod_dir должно использовать протокол https://. Что мне не хватает?

Единственное, что я придумал, это переписать заголовок Location внутри haproxy для перенаправленных соединений HTTPS, чтобы заменить http:// на https://, но я действительно не думаю, что этот подход очень изящный. Я бы предпочел для Apache (и (не навредить мне) PHP дальше по цепочке), чтобы быть в курсе и рассматривать соединение как обычное HTTPS-соединение.

Пожалуйста, помогите!

PS - Я слышал, как это говорилось раньше, если вы должны спросить, тогда вы делаете это неправильно. Возможно, это проблема корня здесь, но это кажется такой простой дилеммой, и я чувствую себя единственной, кто когда-либо приходил сюда.

Ответ 1

Вы можете сделать это, включив протокол в директиву ServerName:

ServerName https://my-server-name

В соответствии с Apache docs:

Иногда сервер работает за устройством, которое обрабатывает SSL, например, обратный прокси-сервер, балансировщик нагрузки или устройство разгрузки SSL. Если это так, укажите схему https://и номер порта, к которому клиенты подключаются в директиве ServerName, чтобы убедиться, что сервер генерирует правильные URL-адреса для ссылок.

Ответ 2

  • Переадресация слэша каталога: то, что вы хотите, - mod_rewrite.

    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} =https
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^(.+[^/])$          https://www.example.com/$1/  [R=301,L,QSA]
    

    Если заголовок установлен в https, а запрошенное имя файла - это каталог (-d), перепишите его (замените example.com на свой собственный домен).

  • Что касается того, чтобы PHP рассматривал соединение как обычное HTTPS-соединение, установите переменную среды https в on:

    SetEnvIf X-Forwarded-Proto https HTTPS=on