У меня следующая установка:
(internet) ---> [ pfSense Box ] /-> [ Apache / PHP server ]
[running HAproxy] --+--> [ Apache / PHP server ]
+--> [ Apache / PHP server ]
\-> [ Apache / PHP server ]
Для HTTP-запросов это работает здоровозапросы распределяются на мои серверы Apache нормально. Для SSL-запросов у меня был HAproxy, распределяющий запросы с использованием балансировки нагрузки TCP, и он работал, однако, поскольку HAproxy не действовал как прокси, он не добавлял X-Forwarded-For
HTTP-заголовок, и серверы Apache / PHP не знали реального IP-адреса клиента.
Итак, я добавил stunnel
перед HAproxy, чтение этого stunnel может добавить X-Forwarded-For
Заголовок HTTP. Однако пакет, который я мог установить в pfSense, не добавляет этот заголовок ... также это явно убивает мою способность использовать запросы KeepAlive, который мне бы очень хотелось сохранить. Но самая большая проблема, которая убила эту идею, заключалась в том, что stunnel преобразовывал запросы HTTPS в простые запросы HTTP, поэтому PHP не знал, что SSL включен, и пытался перенаправить на сайт SSL.
Как я могу использовать HAproxy для балансировки нагрузки на нескольких серверах SSL, чтобы оба эти сервера знали IP-адрес клиента и знаете, что SSL используется? И если возможно, как это сделать на моем сервере pfSense?
Или мне все это бросить и просто использовать nginx?
Для записи, поскольку этот поток часто упоминается в отношении HAProxy + SSL, HAProxy поддерживает собственный SSL с обеих сторон, начиная с версии 1.5-dev12. Таким образом, наличие X-Forwarded-For, HTTP keep-alive, а также заголовок, сообщающий серверу, что соединение было выполнено через SSL, очень просты:
listen front
bind :80
bind :443 ssl crt /etc/haproxy/haproxy.pem
mode http
option http-server-close
option forwardfor
http-request set-header X-Forwarded-Proto https if { ssl_fc }
server srv1 1.1.1.1:80 check ...
...
Я уверен, что к тому времени вы придумаете что-то другое, но, по крайней мере, новые посетители теперь получат простое решение :-)
Вам не нужно отказываться от всего этого, вы можете просто использовать nginx перед haproxy для поддержки SSL, сохраняя всю свою конфигурацию балансировки нагрузки. Вам даже не нужно использовать nginx для HTTP, если вы не хотите. Nginx может передавать как X-Forwarded-For, так и настраиваемый заголовок, указывающий на использование SSL (и информацию о сертификате клиента, если хотите). Фрагмент конфигурации Nginx, который отправляет необходимую информацию:
proxy_set_header SCHEME $scheme; # http/https
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header CLIENT_CERT $ssl_client_raw_cert;
Для всех, кто нашел этот вопрос, я последовал совету Охото и использовал nginx. Вот конкретные шаги, которые я использовал, чтобы заставить эту работу на моем роутере pfSense:
Используя веб-интерфейс pfsense, я установил pfsense Пакет PfJailctl и пакет "jail_template" в Система> Пакеты так что я мог создать тюрьму FreeBSD для компиляции и установки nginx в системе pfsense.
Я настроил джейл для своего сервера nginx под Услуги> Тюрьмы, давая новой тюрьме то же имя хоста и IP-адрес виртуального IP-псевдонима, на котором у меня был запущен HAproxy. Привязал джейл к WAN интерфейсу. Я использовал шаблон тюрьмы по умолчанию и включил unionfs, а не nullfs.
Как только тюрьма была запущена, я SSH вошел в ящик pfsense и запустил jls
чтобы узнать номер тюрьмы. Я тогда побежал jexec 1 sh
чтобы получить оболочку внутри тюрьмы. Оттуда я настроил порты BSD и установил nginx, используя:
portsnap extract
portsnap fetch update
cd /usr/ports/www/nginx
make install clean
Затем я настроил nginx для прослушивания порта 443 и передачи всех запросов HAproxy на порт 80, включая реальный IP-адрес и статус SSL внутри заголовков HTTP. Мой usr/local/etc/nginx/nginx.conf
выглядит как:
worker_processes 1;
events {
worker_connections 2048;
}
http {
upstream haproxy {
server 209.59.186.35:80;
}
server {
listen 443;
server_name my.host.name default_server;
ssl on;
ssl_certificate my.crt;
ssl_certificate_key my.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://haproxy;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
}
Затем я изменил свое приложение PHP, чтобы обнаружить X-Forwarded-Proto
Заголовок HTTP:
function usingSSL()
{
return (
(isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' )
|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' ));
}
Итак, окончательная настройка:
(internet) ---> [ -> nginx -> haproxy -]--> (pool of apache servers)
[ (pfSense server) ]
Моя конфигурация для версии haproxy 1.5-dev-17:
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
#log loghost local0 info
maxconn 4096
#chroot /usr/share/haproxy
user haproxy
group haproxy
daemon
#debug
#quiet
defaults
log global
mode http
option httplog
option dontlognull
option http-server-close
retries 3
option redispatch
fullconn 1000
maxconn 1000
timeout queue 600s
timeout connect 5s
timeout client 600s
timeout server 600s
frontend http-in
bind *:80
bind *:443 ssl crt /usr/local/etc/ssl/certs
reqadd X-Forwarded-Proto:\ https if { ssl_fc }
default_backend varnish-ha
option forwardfor
backend varnish-ha
server hafront1 10.1.69.1:6081 minconn 100 maxqueue 10000
Он использует ssl_fc
ACL. Обратите внимание, что option http-server-close
часть очень важна.
HAProxy не может поразить серверную часть SSL без использования режима raw TCP, теряя X-Forwarded-For
, но вы потенциально можете повторно зашифровать трафик с помощью stunnel для внутреннего транзита. Хотя некрасиво.
Мне больше нравится подход Ochoto, но с одной оговоркой: nginx - отлично работающий балансировщик нагрузки; если вы его используете, я бы сказал, используйте его для всего. Прокси-сервер вашего входящего HTTPS для загрузки сбалансированных HTTPS-серверов - и таким образом нет необходимости в настраиваемых заголовках для информации SSL (если вам не нужен сертификат клиента).
В прошлом году я реализовал решение для интегрировать HAProxy с pfSense таким образом, что он использует все функции HAProxy и поддерживает хорошую изоляцию с помощью pfSense. Так что это жизнеспособный вариант для производственная среда. SSL отключен на HAProxy. Я установил HAProxy внутри тюрьмы в pfSense с использованием ezjail и коллекции портов. Таким образом, очень легко поддерживать оба компонента независимо друг от друга. И вы можете установить любую версию, которую хотите. Я начал с 1.5-dev13. И с тех пор у меня он отлично работает. Я все это задокументировал.
Кстати, Вилли, большое спасибо за такой отличный продукт.