Настройка HAProxy (standalone)#

Общая информация HAProxy#

HAProxy — это высокопроизводительный прокси-сервер и балансировщик нагрузки для протоколов TCP (L4) и HTTP/HTTPS ( L7). Он используется для:

  • распределения трафика между несколькими приложениями (балансировка нагрузки);

  • проверки работоспособности целевых серверов (health checks);

  • добавления служебных заголовков (например, X-Forwarded-For, X-Forwarded-Proto);

  • ограничения скорости, защиты от атак и пр.

В режиме standalone HAProxy работает на одном сервере и проксирует трафик к локальным или удалённым backend-службам, повышая отказоустойчивость и безопасность.

Перед началом работ#

  • Получите права администратора (root) или возможность использовать sudo.

  • Запустите приложение на порту 8080.

Подготовка системы и брандмауэра (UFW)#

Обновление индексов пакетов и базовой системы#

sudo apt update && sudo apt upgrade

Установка и включение Firewall#

sudo apt install ufw
sudo systemctl enable ufw --now

Базовая политика firewall#

sudo ufw default deny incoming
sudo ufw allow ssh
sudo ufw enable
  • default deny incoming - по умолчанию запрещаем все входящие подключения (подход «deny by default»).

  • allow ssh - разрешаем доступ по SSH (обычно порт 22), чтобы не потерять удалённый доступ.

  • enable - активируем правила файрвола.

Разрешение нужных портов#

sudo ufw allow 443/tcp
sudo ufw allow from 127.0.0.1 to any port 8080
sudo ufw allow 5000/tcp
sudo ufw allow 8405/tcp
sudo ufw allow 9090/tcp
sudo ufw allow 3000/tcp
  • 443/tcp - входящий HTTPS-трафик к HAProxy.

  • Разрешение доступа к локальному backend на 8080 (только с 127.0.0.1).

  • 5000/tcp - входящий трафик для статистики HAProxy (включить при необходимости).

  • 8405/tcp - входящий трафик для статистики Prometheus (включить при необходимости).

  • 9090/tcp - входящий трафик для статистики Web Prometheus (включить при необходимости).

  • 3000/tcp - входящий трафик для статистики Web Grafana (включить при необходимости).

Важно

Показан пример для тестового стенда. В продакшене рекоменндуется не открывать порты мониторинга для любых подключений.

Проверка правил#

sudo ufw status verbose

Установка HAProxy#

sudo apt install haproxy -y
sudo systemctl enable haproxy --now

Инструкции для других версий/ОС размещены на официальном сайте HAProxy для Debian: https://haproxy.debian.net/

TLS/SSL: самоподписанный сертификат для теста#

Важно

В продакшене используйте сертификаты от доверенного CA. Самоподписанный сертификат подходит для тестов/внутренних стендов.

openssl genrsa -out cert.key 2048
openssl req -new -key cert.key -out cert.csr
openssl x509 -req -days 365 -in cert.csr -signkey cert.key -out cert.crt
mkdir /etc/ssl/globalerp/
cat cert.key cert.crt > /etc/ssl/globalerp/haproxy_ssl.pem
  • Генерируем приватный ключ RSA 2048 бит.

  • Формируем CSR.

  • Выпускаем самоподписанный сертификат на 365 дней.

  • Сливаем ключ и сертификат в единый PEM-файл haproxy_ssl.pem, который удобно указывать в haproxy.cfg.

Рекомендуемое расположение PEM: /etc/ssl/globalerp/haproxy_ssl.pem
Права: chmod 640, владелец/группа: haproxy:haproxy, чтобы процесс haproxy мог читать файл.

Базовая конфигурация HAProxy#

Откройте конфигурацию:

sudo nano /etc/haproxy/haproxy.cfg
Пример конфигурации
global
        # Логи отправляются в системный syslog (rsyslog/journald)
        log /dev/log    local0 info
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 300s
        user haproxy
        group haproxy
        daemon

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

        # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

frontend stats
        mode http
        bind :5000
        stats enable
        stats refresh 10s
        stats uri /stats
        stats show-modules
        stats admin if TRUE
        stats auth admin:a1d2m3i4n5 # Login:Password
        timeout client 10s

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option  log-health-checks
        option  abortonclose
        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

frontend haproxynode
        bind *:80
        bind *:443 ssl crt /etc/ssl/globalerp/haproxy_ssl.pem
        # Редирект на HTTPS
        redirect scheme https code 301 if !{ ssl_fc }
        timeout client 300s
        mode http
        default_backend backendnodes

backend backendnodes
        balance roundrobin # равномерное распределение
        option forwardfor # Включает X-Forwarded-For для передачи IP-адреса клиента обслуживающему серверу
        cookie GS_BALANCER_SERVER_NAME insert #  добавлять куки. Для режима липких сессий, когда один ip подключается к одному backend-ду
        timeout tunnel 600s
        acl has_x_forwarded_port req.hdr(X-Forwarded-Port) -m found
        http-request set-header X-Forwarded-Port %[req.hdr(X-Forwarded-Port)] if has_x_forwarded_port
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
        server global-server-01 localhost:8080 check cookie global-server-01

Разбор конфигурации#

Уровни логирования#

Строки log /dev/log local0 info и log /dev/log local1 notice задают отправку логов в системный syslog с различным уровнем. Это позволит разнести рабочие логи и, например, административные сообщения.

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

Уровень лога

Описание

emerg

Ошибки, такие как исчерпание файловых дескрипторов операционной системы.

alert

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

err

Ошибки, такие как невозможность анализа файла карты, невозможность анализа файла конфигурации HAProxy и сбой операции с таблицей Stick.

warning

Некоторые важные, но некритические ошибки, такие как невозможность установить заголовок запроса или невозможность подключения к DNS-серверу имён.

notification

Изменения состояния сервера, например, «UP» (включен) или «DOWN» (отключён). Также учитываются другие события при запуске, такие как запуск прокси-серверов и загрузка модулей. Журнал проверки работоспособности, если он включен, также использует этот уровень.

info

Подробности и ошибки TCP-подключения и HTTP-запросов.

debug

Вы можете написать собственный код Lua, который будет регистрировать отладочные сообщения.

Статистика#

Доступ к странице мониторинга: http://IP_ADDRESS:5000/stats (логин/пароль из stats auth).

IP_ADDRESS - ip адрес вашего сервера с HAProxy

После авторизации на странице мониторинга, открывается доступ к различным действиям. Подробнее о каждом, в таблице ниже.

Действия

Действие

Описание

Set state to READY

Выбранный сервер будет получать трафик. Окончательное состояние сервера будет определено на основе настроенной проверки работоспособности.

Set state to DRAIN

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

Set state to MAINT

Выбранный сервер не будет принимать никаких новых подключений, а проверки работоспособности будут остановлены.

Health: disable checks

Отключить проверки работоспособности сервера.

Health: enable checks

Включить проверки работоспособности сервера.

Health: force UP

Немедленно перевести проверку работоспособности сервера в состояние UP.

Health: force NOLB

Принудительно перевести проверку работоспособности сервера в состояние NOLB. Это останавливает сервер от приема новых непостоянных подключений.

Health: force DOWN

Немедленно перевести проверку работоспособности сервера в состояние DOWN.

Agent: disable checks

Отключить проверки агента сервера.

Agent: enable checks

Включить проверки агента сервера.

Frontend часть#

Принимает HTTP на :80 и HTTPS на :443. HTTP трафик перенаправляет на HTTPS.

frontend haproxynode
bind *:80
bind *:443 ssl crt /etc/ssl/globalerp/haproxy_ssl.pem
redirect scheme https code 301 if !{ ssl_fc }
timeout client 300s
mode http
default_backend backendnodes
  • bind :80 - приём HTTP (для редиректа).

  • bind :443 ssl crt ... - приём HTTPS с указанным PEM-сертификатом.

  • http-request redirect ... unless { ssl_fc } - перевод всего трафика на HTTPS.

  • default_backend backendnodes - выбор backend по умолчанию.

Backend часть#

Перенаправляет запросы от frontend части на сервера приложений.

backend backendnodes
balance roundrobin #leastconn #roundrobin
option forwardfor # Включает X-Forwarded-For для передачи IP-адреса клиента обслуживающему серверу
cookie GS_BALANCER_SERVER_NAME insert #  добавлять куки. Для режима липких сессий, когда один ip подключается к одному backend-ду
timeout tunnel 600s
acl has_x_forwarded_port req.hdr(X-Forwarded-Port) -m found
http-request set-header X-Forwarded-Port %[req.hdr(X-Forwarded-Port)] if has_x_forwarded_port
http-request add-header X-Forwarded-Proto https if { ssl_fc }
server global-server-01 localhost:8080 check cookie global-server-01
  • balance roundrobin — равномерная балансировка по списку server.

  • option forwardfor — добавляет X-Forwarded-For с IP клиента.

  • cookie ... insert + server ... cookie ... — липкие сессии (sticky) для привязки клиента к одному серверу.

  • server <name> <ip:port> check — сервер backend; check включает health-check. Добавляйте столько строк server, сколько у вас целевых инстансов.

Проверка конфигурации и перезапуск#

sudo haproxy -f /etc/haproxy/haproxy.cfg -c
sudo systemctl restart haproxy
  • -c - проверяет синтаксис и базовую корректность конфигурации без запуска.

  • restart - перезапускает службу с разрывом соединений клиентов.

Проверка статуса работы:

sudo systemctl status haproxy
journalctl -u haproxy -e

Включение логирования HAProxy#

По умолчанию HAProxy пишет лог в /dev/log. Настроим rsyslog для работы с логами HAProxy.

Rsyslog — это быстрый, расширяемый сервис для управления логами.

Установка Syslog server:

sudo apt install -y rsyslog

Конфигурация rsyslog для HAProxy:

sudo nano /etc/logrotate.d/haproxy

Пример конфигурации файла

/var/log/haproxy/haproxy.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 haproxy adm
    postrotate
        invoke-rc.d rsyslog reload > /dev/null
    endscript
}

Безопасная аутентификация к странице статистики#

В избежании хранения пароля для входа на страницу в открытом виде, используйте userlist с хэшированным паролем.

Подробнее в документации

Для шифрования паролей в HAProxy используется функция crypt(3). Это библиотечная функция, которая используется для создания и проверки хешей паролей. Она генерирует специальную строку, содержащую хеш, «соль» (случайная строка, добавленная для усиления безопасности) и информацию об алгоритме, которая хранится в файлах пользователей, например, /etc/shadow. Эта строка затем сравнивается с введённым паролем при входе пользователя для аутентификации

Наиболее простой способ использовать данную функцию, воспользоваться утилитой mkpasswd, входящей в состав whois.

Установите утилиту и сгенерируйте хеш:

sudo apt install -y whois
mkpasswd -m sha-256
# Введите пароль → получите строку $2...

Замените секцию frontend stats и добавьте userlist:

userlist stats_users
    user admin password <hash> # Вставьте сгенириуемый ранее хэш

frontend stats
    mode http
    bind :5000
    stats enable
    stats refresh 10s
    stats uri /stats
    stats show-modules
    stats admin if TRUE
    http-request auth unless { http_auth(stats_users) }

Подключение HAProxy к телеметрии#

Предполагается что у вас развернута ВМ с Prometheus и Grafana. Подробнее об установке в руководстве.

Интеграция HAProxy с Prometheus#

Включим встроенный Prometheus-экспортёр HAProxy и настроим сбор метрик Prometheus. Подробнее о конфигурировании в документации

** Включить экспорт метрик в HAProxy**

Добавьте во frontend отдельный блок для выдачи метрик:

frontend prometheus
bind :8405
mode http
http-request use-service prometheus-exporter

Конфигурирование Prometheus

Отредактируйте /opt/prometheus/prometheus.yml и добавьте job c HAProxy:

scrape_configs:
- job_name: "haproxy"
  static_configs:
    - targets: ["<IP_ADDRESS HAPROXY>:8405"]

Подключение Prometheus как источника данных

  1. В Grafana откройте меню Connections → Data sources → Add new data source.

  2. Выберите Prometheus.

  3. В поле Prometheus server URL укажите адрес Prometheus (http://<IP_ADDRESS>:9090).

  4. Нажмите Save & test.

Сервер Prometheus в Grafana

Импорт готового дашборда HAProxy в Grafana

Существуют готовые дашборды. В этом примере используем JSON из репозитория, рекомендованного Grafana: rfmoz/grafana-dashboards

Шаги импорта:

  1. В Grafana: Dashboards → New → Import.

  2. Загрузите файл haproxy.json (предварительно скачайте его с GitHub).

  3. В поле Select a data source выберите ранее добавленный источник Prometheus.

  4. Нажмите Import — дашборд появится в списке и станет доступен к просмотру.

Дашборд HAProxy в Grafana