Я пытаюсь настроить HAProxy для использования как для HTTPS-трафика, так и для OpenVPN-соединений через порт 443. Конфигурация проста (домен первого уровня заменен на example.com
ради анонимности):
frontend www_ssl
mode tcp
bind *:443
acl host_vpn hdr(host) -i vpn.example.com
use_backend vpn_backend if host_vpn
default_backend nginx_pool_ssl
backend nginx_pool_ssl
balance first
mode tcp
server web1 192.168.1.2:443 send-proxy check
server web2 192.168.1.3:443 send-proxy check
backend vpn_backend
mode tcp
server vpn1 192.168.1.4:443
При установке OpenVPN-соединения выдается следующее сообщение:
ПРЕДУПРЕЖДЕНИЕ: неверная длина инкапсулированного пакета от однорангового узла (18516), которая должна быть> 0 и <= 1547 - убедитесь, что --tun-mtu или --link-mtu равны на обоих узлах - это условие также может указывать на возможная активная атака на канал TCP - [Попытка перезапуска ...]
Что происходит, так это то, что вместо перенаправления трафика на 192.168.1.4 HAProxy переходит на 192.168.1.2, который пытается обработать его как запрос HTTPS. То же самое происходит, когда я открываю vpn.example.com
в браузере: я просто получаю веб-сайт, обслуживаемый 192.168.1.2.
Если я заменю приведенную выше конфигурацию на это:
frontend www_ssl
mode tcp
bind *:443
default_backend host_vpn
backend vpn_backend
mode tcp
server vpn1 192.168.1.4:443
тогда соединение OpenVPN установлено правильно, и браузер не может ничего показать, что означает, что проблема связана с конфигурацией HAProxy.
Что здесь происходит? Есть ли ошибка в исходной конфигурации?
Нашел.
Очевидная проблема заключается в том, что директива ACL полагается на заголовки HTTP: учитывая, что HAProxy не сможет извлекать заголовки из трафика HTTPS, а OpenVPN их не имеет, ACL не имеет никакого эффекта, и использование default_backend
здесь ожидается.
Моей первой мыслью было использовать req.ssl_sni
вместо того hdr(host)
. Я подумал, что это позволит определить, является ли трафик HTTPS или нет:
acl host_non_vpn req.ssl_sni -m sub -i example.com
use_backend vpn_backend if !host_non_vpn
use_backend nginx_pool_ssl if host_non_vpn
Хотя он хорошо работал с запросами браузера, у меня возникла проблема, когда часть трафика из svn
в WebDAV через HTTPS был перенаправлен на сервер OpenVPN. Я не уверен, что здесь происходит, и без отслеживания сетевого трафика было трудно найти проблему, ни какие именно запросы не выполнялись и почему.
В итоге я переместил OpenVPN на порт 80. Используя предопределенный HTTP
ACL, конфигурация теперь выглядит так:
frontend www_http
mode tcp
bind *:80
use_backend nginx_pool_http if HTTP
use_backend vpn_backend if !HTTP