Вопрос или проблема
Я пытаюсь создать кластер SMTP с балансировкой нагрузки. Почтовые серверы уже существуют и работают на Exim 4. Изначально я рассмотрел возможность использования Nginx для балансировки нагрузки, однако на тестовой системе все почтовые серверы видят входящие соединения как исходящие от IP балансировщика, а не от фактического удаленного отправителя. После обширного поиска в Google не оказалось способа обойти это. Поскольку это фактически превращает кластер почты в открытый релей, это, очевидно, не подходит, что жаль, так как Nginx в остальном работает прекрасно.
Поэтому я рассматриваю возможность использования HAProxy, так как, судя по дальнейшему поиску в Google, у него есть возможность передавать соединения с их оригинальным исходным IP, так что списки разрешенных реле и ACL будут работать корректно.
Однако, настроив HAProxy согласно нескольким онлайн-примером, я либо получаю “Ошибка синхронизации SMTP” (и 500-ю ошибку, поэтому почта будет отклонена) с немедленным разрывом соединения, либо просто разрыв соединения без каких-либо сообщений SMTP.
Вот haproxy.conf, который используется:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user nobody
group nobody
daemon
stats socket /var/lib/haproxy/stats
defaults
log global
option redispatch
retries 3
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout check 10s
maxconn 3000
listen smtp
bind 0.0.0.0:25
mode tcp
no option http-server-close
balance roundrobin
# option smtpchk HELO smtp-in.example.com
server smtp01 10.0.0.141:25 send-proxy check
server smtp02 10.0.0.143:25 send-proxy check
Несмотря на наличие команды send-proxy, которая, как я понимаю, указывает haproxy передавать исходный IP, логи Exim выглядят так:
016-12-26 07:06:48 Ошибка синхронизации протокола SMTP (входные данные отправлены без ожидания приветствия): отклоненное соединение от H=[10.0.0.150] input=”PROXY TCP4 10.0.0.150 10.0.0.143 40334 25\r\nHELO smtp-in.example.com\r\n”
В этом случае .150 — это IP балансировщика, а .143 — это SMTP сервер Exim.
Вопросы:
-
Возможно ли действительно заставить Nginx представлять SMTP соединения для почтовых серверов с исходным IP от реального удаленного источника, а не от балансировщика?
-
Кроме того, возможно ли это в HAProxy и как это делается?
В данном случае текущая производственная система работает на LVS, однако она зависит от того, чтобы и балансировщик нагрузки, и интерфейсы обратной связи на всех почтовых серверах имели один и тот же IP-адрес. Новый балансировщик нагрузки будет на OpenSUSE 42.2, и, среди прочего, если он обнаруживает IP, который уже используется в сети, он кажется, с благодарностью удаляет его с себя, чтобы избежать конфликта. Поэтому LVS не подходит для новейшей сборки.
Другие решения проблемы, которые я рассматриваю, включают полное разделение входящего и исходящего SMTP-трафика (в настоящее время все проходит через один и тот же балансировщик нагрузки), установку простого реле (возможно, qmail) на IP-адрес балансировщика нагрузки, настроенного только на разрешенные диапазоны согласно стандартной практике реле, и использование простого DNS раунд-робина в записях MX для отправки входящих SMTP напрямую на почтовые серверы. Но решение с балансировкой нагрузки будет более элегантным.
Я использовал пользовательскую проверку tcp следующим образом
backend smtp-back
mode tcp
no option http-server-close
balance roundrobin
tcp-check expect string 220
tcp-check send HELO\ test\r\n
tcp-check expect string 250
tcp-check send QUIT\r\n
tcp-check expect string 221
server mail01 mail01:25 check inter 60s rise 3 fall 3 backup
server mail02 mail02:25 check inter 60s rise 3 fall 3 backup
(переведено из комментария):
Совсем не нужно запускать балансировщик нагрузки перед вашим кластером SMTP. Балансировка нагрузки и возврат из недоступных MX — это неотъемлемая часть SMTP. См. RFC 2821 пункт 5. Разрешение адресов и обработка почты для подробностей.
Просто введите все имена хостов в вашу запись MX с одинаковым приоритетом или используйте единственную запись MX с раунд-робин DNS за ней.
Ответ или решение
Для создания кластера SMTP с балансировкой нагрузки, который корректно передает исходный IP-адрес удаленных отправителей, необходимо учесть несколько ключевых моментов и правильно настроить используемое ПО. Я рассмотрю оба вопроса в вашем запросе.
1. Использование Nginx для передачи исходного IP
На данный момент Nginx не предоставляет функционала для корректной работы с SMTP, как это может сделать HAProxy, так как Nginx в основном ориентирован на HTTP/HTTPS-трафик. Хотя в Nginx есть поддержка TCP-соединений, она не всегда надежна для работы с протоколами, отличными от HTTP, особенно в SMTP. Таким образом, использование Nginx в вашем случае не рекомендуется, так как он не сможет правильно передать исходный адрес отправителя.
2. Настройка HAProxy для работы с SMTP
HAProxy предлагает зрелую и проверенную методику балансировки нагрузки для таких приложений, как SMTP. Ваша конфигурация HAProxy включает команду send-proxy
, что правильно, так как именно она позволяет передавать исходный IP-адрес клиента. Однако вы столкнулись с ошибкой "SMTP protocol synchronization error".
Вот несколько шагов и корректировок для решения вашей проблемы:
Исправленная конфигурация HAProxy:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user nobody
group nobody
daemon
stats socket /var/lib/haproxy/stats
defaults
log global
option redispatch
retries 3
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
maxconn 3000
frontend smtp_front
bind 0.0.0.0:25
mode tcp
option tcplog
default_backend smtp_back
backend smtp_back
mode tcp
option tcp-check
balance roundrobin
server smtp01 10.0.0.141:25 send-proxy check
server smtp02 10.0.0.143:25 send-proxy check
Объяснение изменений:
-
Разделение frontend и backend: Используйте секцию
frontend
для настройки точки входа (в данном случае SMTP на порту 25) иbackend
для управления серверами SMTP. -
Опция
option tcplog
: Это необходимо для логирования TCP-трафика, что упростит отладку. -
Удалённый
smtpchk
: Заменитеsmtpchk
наtcp-check
, чтобы правильно проверять работоспособность серверов в бэкенде.
Проверка конфигурации Exim
Убедитесь, что Exim на каждом из ваших SMTP-серверов настроен правильно для работы с "PROXY" заголовком, который используется HAProxy для передачи IP-адресов. Обычно это связывается с настройкой "daemon_options" и "acl".
Пример настройки в Exim:
acl_smtp_connect = acl_smtp_connect
acl_smtp_connect = acl_check_connect
acl_check_connect:
accept hosts = 0.0.0.0/0 # Разрешить все IP для тестирования
deny !hosts = 0.0.0.0/0
Заключение
Если все настроено правильно, вы должны получить балансировку нагрузки между вашими серверами SMTP с корректной передачей исходного IP-адреса. Если возникают дополнительные ошибки, смотрите журналы HAProxy и Exim для более детального анализа. В случае если часть инфраструктуры меняется, стоит подумать о доменной балансировке через DNS, что также может упростить задачу, однако использование HAProxy обеспечивает более надежную и контролируемую среду.