Назад | Перейти на главную страницу

Как перенаправить трафик на разные серверы на основе доменного имени?

Я пытаюсь настроить 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