Thank you for reading this post, don't forget to subscribe!
Довольно часто требуется балансировать нагрузку между несколькими веб-серверами. При этом, как правило, необходимо, чтобы веб-приложения получали реальные IP-адреса клиентов, а не IP балансировщика.
В случае балансировки и терминации HTTP(S)-трафика на HAProxy (Layer 7 [1]), данная задача легко решается добавлением заголовка “X-Real-IP” и его обработкой на Nginx при помощи модуля ngx_http_realip_module [2]. При балансировке TCP-трафика от HTTPS-клиентов и передаче его на веб-сервера напрямую без модификации или терминации (Layer 4 [3]) добавить данный заголовок невозможно, поэтому требуется воспользоваться возможностями, предоставляемыми Proxy Protocol [4, 5, 6].
Рассмотрим оба варианта (балансировка L7 и L4) на примере выдержек из конфигурационных файлов haproxy 1.5.9 и nginx 1.6.2
Балансировка на прикладном уровне (Layer 7): терминация HTTPS-трафика на HAProxy и передача по HTTPS на Nginx
В данном примере HTTPS-трафик от клиента терминируется на HAProxy, модифицируется и передается на Nginx так же по HTTPS.
cat haproxy.cfg
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
global maxconn 4096 chroot /usr/share/haproxy uid 99 gid 99 daemon tune.ssl.default-dh-param 2048 defaults log global option redispatch option tcp-smart-accept option tcp-smart-connect retries 3 maxconn 2000 timeout connect 5000 timeout check 3000 timeout client 50000 timeout server 50000 frontend http_frontend *:80 mode http redirect scheme https code 301 if !{ ssl_fc } frontend https_frontend_ssl_terminate mode http bind *:443 ssl crt /etc/haproxy/ssl/public.example.com.pem option forwardfor header X-Real-IP default_backend web_server_http backend web_server_http mode http balance roundrobin # Отправляем трафик на backend по HTTPS server s1_https 192.168.1.10:443 ssl verify none server s2_https 192.168.1.20:443 ssl verify none |
[/codesyntax]
cat nginx.conf
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
server { server_name localhost; listen 443 ssl default_server; ssl_certificate /etc/nginx/ssl/internal.example.com.pem; ssl_certificate_key /etc/nginx/ssl/internal.example.com.key; # Адрес HAProxy set_real_ip_from 192.168.1.254; real_ip_header X-Real-IP; root /usr/share/nginx/html; index index.html index.htm; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ /\.ht { deny all; } } |
[/codesyntax]
Балансировка на транспортном уровне (Layer 4): передача TCP-трафика с HAProxy на Nginx
В данном примере HTTPS-трафик клиентов не модифицируется (HAProxy вмешивается в транспортный уровень) и его терминация происходит непосредственно на Nginx.
cat haproxy.cfg
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
global maxconn 4096 chroot /usr/share/haproxy uid 99 gid 99 daemon defaults log global option redispatch option tcp-smart-accept option tcp-smart-connect retries 3 maxconn 2000 timeout connect 5000 timeout check 3000 timeout client 50000 timeout server 50000 frontend http_frontend *:80 mode http redirect scheme https code 301 if !{ ssl_fc } frontend https_frontend_ssl_pass mode tcp bind *:443 default_backend web_server_tcp backend web_server_tcp mode tcp balance roundrobin # ВНИМАНИЕ! Работа с send-proxy возможна только, # когда принимающая сторона понимает, что это такое. # Для Nginx необходимо включить в директиву listen # опцию proxy_protocol. server s1_tcp 192.168.1.10:443 send-proxy server s2_tcp 192.168.1.20:443 send-proxy |
[/codesyntax]
cat nginx.conf
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
server { server_name localhost; # ВНИМАНИЕ! Работа с директивой proxy_protocol возможна только в связке с haproxy. # Для прямого доступа данную директиву необходимо отключить. listen 443 ssl default_server proxy_protocol; ssl_certificate /etc/nginx/ssl/public.example.com.pem; ssl_certificate_key /etc/nginx/ssl/public.example.com.key; # Адрес HAProxy set_real_ip_from 192.168.1.254; real_ip_header proxy_protocol; root /usr/share/nginx/html; index index.html index.htm; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ /\.ht { deny all; } } |
[/codesyntax]
Используя описанные выше настройки мы смогли передать веб-серверу Nginx, расположенному за HAProxy, реальные IP-адреса клиентов при работе по HTTPS. Подобным подходом так же можно воспользоваться при работе со сторонними балансировщиками нагрузки, например CloudFlare [7, 8] и AWS ELB [9, 10].