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

HAProxy возвращает неверный запрос (недействительный хост), казалось бы, без причины

Я пытался протестировать установку, которая выглядит так:

Веб-сайт: Http GET Request -> Nginx -> HAProxy -> .Net приложение

Я разместил Nginx и HAProxy на одной машине Debian. Однако HAProxy постоянно возвращает «Bad Request (Invalid Host)». Я определил, что HAProxy виноват, сначала отправив запрос прямо с веб-сайта в приложение .Net, которое работает. Ссылка Nginx на приложение .Net также работает. Однако, когда я пытаюсь проверить это с установленным HAProxy, я получаю сообщение об ошибке. Неважно, работает ли приложение .Net за HAProxy, я всегда получаю сообщение об ошибке.

Пример сообщения, которое я пытаюсь отправить: http://192.168.7.119:81/a:diff1. Ожидаемый ответ - изображение в формате JPG. Кажется, это нормально работает при отправке на что-либо, кроме HAProxy (Apache, Nginx, приложение), но HAProxy просто говорит «Плохой запрос». Как ни странно, я не вижу ошибок в моем файле журнала.

Вот пример из файла журнала:

Feb  2 15:10:08 companyDebian haproxy[5566]: 192.168.7.114:51105 [02/Feb/2015:15:10:08.415] renderfarm renderfarm/renderA 0/0/0/1/1 400 212 - - ---- 1/1/0/1/0 0/0 "GET /a:diff1 HTTP/1.1"
Feb  2 15:10:08 companyDebian haproxy[5566]: 192.168.7.114:51105 [02/Feb/2015:15:10:08.417] renderfarm renderfarm/renderA 73/0/0/4/77 400 212 - - ---- 1/1/0/1/0 0/0 "GET /favicon.ico HTTP/1.1"

Мой файл конфигурации выглядит так:

global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # Default ciphers to use on SSL-enabled listening sockets.
    # For more information, see ciphers(1SSL).
    ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL
    ssl-default-bind-options no-sslv3

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

listen renderfarm
    bind 192.168.7.119:81
    mode http
    balance roundrobin     
    server renderA 192.168.7.114:40000 maxconn 1

У меня нет предыдущего опыта работы с HAProxy, и я использую его, потому что он мне был рекомендован. Таким образом, я не знаю, какие еще шаги я могу предпринять, чтобы решить эту проблему. В руководстве по настройке упоминаются различные параметры, которые вы можете установить, такие как tune.bufsize и option accept-invalid-http-request, но они не действуют.

Заметка: Идея состоит в том, чтобы добавить больше серверов, на которых запущено приложение, когда эта установка заработает. Каждый сервер действительно может обрабатывать только 1 запрос за раз.

Я столкнулся с той же проблемой, и мне потребовалось время, чтобы понять, почему это происходит.

Моя среда состоит из 1 HAproxy и 2 nginx в качестве бэкэнда с nodejs в качестве CGI-подобного.

Основная причина зависит от того, как HAproxy создает HTTP-запрос. По умолчанию HAproxy не включает заголовок хоста в запрос, поэтому вам нужно добавить его вручную, иначе nginx вернет 400 по умолчанию, а HAproxy отметит его как неработоспособный.

Пример ниже:

  • Конфигурация проверки работоспособности HAproxy:

    option httpchk HEAD / HTTP/1.1
    
  • Эквивалентный HTTP-запрос:

    tony@calderona:~ $ telnet A.B.C.D 80
    Trying A.B.C.D...
    Connected to A.B.C.D.
    Escape character is '^]'.
    HEAD / HTTP/1.1
    
    HTTP/1.1 400 Bad Request
    Server: nginx/1.10.3
    Date: Sun, 10 Dec 2017 09:52:12 GMT
    Content-Type: text/html
    Content-Length: 173
    Connection: close 
    
  • Конфигурация проверки работоспособности HAproxy:

    option httpchk HEAD / HTTP/1.1\r\nHost:\ www.temporaryworkaround.org
    
  • Эквивалентный HTTP-запрос:

    tony@calderona:~ $ telnet A.B.C.D 80
    Trying A.B.C.D...
    Connected to A.B.C.D.
    Escape character is '^]'.
    HEAD / HTTP/1.1
    host: www.temporaryworkaround.org
    
    HTTP/1.1 200 OK
    Server: nginx/1.10.3
    Date: Sun, 10 Dec 2017 09:52:24 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 10282
    Connection: keep-alive
    

Ура

Если вы хотите увидеть точную ошибку, с которой сталкивается HAproxy, вы можете сделать это, используя socat для подключения к разъему администратора. Установить socat через apt-get install socat, затем запустите следующее:

echo "show errors" | socat unix-connect:/run/haproxy/admin.sock stdio

Если вы запустите это сразу после получения ошибки «Плохой запрос», он должен показать вам, что именно HAproxy не понравилось в HTTP-запросе, сделанном клиентом.

НОТА: Вышеуказанное работает, только если вы включили Unix Socket commands для HAProxy. Вам нужно будет добавить однострочную конфигурацию под global раздел, чтобы включить это.

global
     stats socket /var/run/haproxy.sock mode 600 level admin

Официальная документация

Размещение HAProxy за Nginx кажется несерьезным, поскольку как Nginx, так и HAProxy могут единолично обеспечить функциональность, которая вам кажется необходимой.

Рассмотрите возможность разделения раздела прослушивания на frontend и backend разделы с host или path_beg acls и упрощайте настройку, пока не получите ответ. Также рассмотрите возможность использования исключительно forwardfor с одним сервером или добавление другого сервера для roundrobin. Некоторые примеры-

frontend http-in
     bind 0.0.0.0:80
     acl host_1 hdr(host) -i firstsite.com
     acl host_nginx hdr(host) -i secondsite.com

Сопряжение передней и задней части-

use_backend firstsite_redirect if host_1
use_backend nginx if host_nginx

Конфигурация бэкэнда

backend firstsite_redirect
    mode http
    option forwardfor
    server firstserver 192.168.0.2:8080

backend nginx
    mode http
    balance roundrobin
    option httpclose
    option forwardfor
    cookie SRVNAME insert
    server nginx01 192.168.0.3:8080 cookie s1 check
    server nginx02 192.168.0.4:8080 cookie s2 check

Если вы хотите перенаправить на основе URL, рассмотрите возможность использования path_beg в frontend config вместо этого

frontend http-in 0.0.0.0:80
    acl docs path_beg /docs
    acl phpmyadmin path_beg /phpmyadmin

Возможно, стоит попробовать изменить конфигурацию HAProxy на TCP вместо HTTP. Вы теряете некоторые расширенные параметры балансировки нагрузки, которые предоставляет HTTP (установка файлов cookie для сохранения и т. Д.), Но все равно не похоже, что вы их используете прямо сейчас.

Вот пример конфигурации, которую я использую с HAProxy для балансировки нагрузки MySQL:

listen mysql-failover
    bind 10.10.10.210:3306
    mode tcp
    option  tcplog
    option mysql-check user haproxy
    server db1 10.10.10.13:3306 check fall 2 inter 1000
    server backup 10.10.10.11:3306 check

Обратите внимание, что если вы переключитесь на TCP, вы потеряете доступ к встроенной странице статистики HTTP, которую вы можете определить в отдельном операторе listen. Например:

listen stats
    bind 10.10.10.200:80
    mode http
    stats enable
    stats hide-version
    stats uri /
    option httpclose
    stats auth username:password