HAProxy + RabbitMQ + Websocket

Há duas formas de usar o HAProxy como proxy para o RabbitMQ, seja para conexões WebSocket, HTTP, AMQP e MQTT.

A forma mais tradicional, e funciona apenas para conexões HTTP é usando o cabeçalho X-Forwarded-For. A cada mensagem que chega no servidor de proxy, ele preencherá este cabeçalho com o endereço real do remetente da mensagem.

A forma alternativa e mais genérica (funciona também para TCP puro) é usando o padrão Proxy Protocol.

Para o Proxy Protocol funcionar, o software que receberá o proxy precisa ser compatível. O RabbitMQ possui essa compatibilidade.

Proxy com X-Forwarded-For

Só funciona para conexões HTTP e WS (web socket). Não consegui fazer funcionar ela no HAProxy, consegui apenas com o Nginx.

Referências para HAProxy com WebSocket via HTTP (cabeçalho X-Forwarded-For)

Discussão de erro de WebSocket com o HAProxy
https://stackoverflow.com/questions/4360221/haproxy-websocket-disconnection

Exemplo de configuração HAProxy + WebSocket
1) https://gist.github.com/sourcec0de/0834e50e0470e573419f979597c701c8 (testei e não funcionou)
2) https://gist.github.com/lackac/3767467 (testei e não funcionou)
3) https://discourse.haproxy.org/t/using-reverse-proxy-with-secured-web-sockets-wss/2917 (testei e não funcionou)

Proxy com Proxy Protocol

O Proxy Protocol funciona adicionando um cabeçalho no pacote de camada 7 (camada de aplicação), por isso funciona para todos os tipos de protocolos do RabbitMQ, AMQP, MQTT, HTTP, WS (web socket), STOMP.

O HAProxy precisa escutar em TCP, já que o cabeçalho inserido pelo proxy protocol é genérico e funciona para todos protocolos TCP além do HTTP.

A melhor configuração de exemplo que encontrei foi esta:

No exemplo de configuração abaixo, abrimos 3 portas diferentes no HAProxy:
A primeira sem criptografia, apenas repassando as conexões para o RabbitMQ
A segunda com criptografia, mas apenas entre o cliente e o HAProxy. Do HAProxy até o RabbitMQ a conexão ocorre sem criptografia.
A terceira com criptografia, em ambas as partes, do cliente até o HAProxy e do HAProxy até o RabbitMQ.

# Entrando Websocket MQTT (WS), saindo Websocket MQTT (WS)listen web_mqtt_front_plain        bind :15676        mode tcp        balance roundrobin        server rabbit 127.0.0.1:15675 send-proxy# Entrando Secure Websocket MQTT (WSS), saindo Websocket MQTT (WS)# TLS/SSL Offloadinglisten web_mqtt_front_tls_termination        bind :15677 ssl crt /tmp/haproxy-1.8.14/haproxy-secure.crt        mode tcp        balance roundrobin        server rabbit 127.0.0.1:15675 send-proxy# Entrando Secure Websocket MQTT (WSS), saindo Secure Websocket MQTT (WSS)# SSL/TLS bridging or re-encryptionlisten web_mqtt_front_tls        bind :15678 ssl crt /tmp/haproxy-1.8.14/haproxy-secure.crt        mode tcp        balance roundrobin        server rabbit 127.0.0.1:15673 send-proxy ssl verify none

Este exemplo utiliza o proxy protocol v1. Para usar o proxy protocol v2, trocar send-proxy por send-proxy-v2

Exemplo de configuração do /etc/rabbitmq/rabbitmq.conf

log.connection.level = infoloopback_users.guest = falselisteners.tcp.default = 5672#proxy_protocol = true# Para liberar o Web MQTTweb_mqtt.tcp.port = 15675web_mqtt.proxy_protocol = true# Para liberar o Web Stompweb_stomp.tcp.port = 15674web_stomp.proxy_protocol = true

Referências

Discussão sobre o uso do Proxy Protocol com o HAProxy
https://serverfault.com/questions/839965/send-proxy-protocol-header-from-haproxy

You should also read:

NGINX + RabbitMQ + Websocket

Fazendo proxy reverso websocket com nginx, sem TLS server { listen 3000; server_name ws.ubivis.io; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host;…

TLS com o RabbitMQ

sudo sh -c 'echo "loopback_users.guest = falselisteners.tcp.default = 5672" > /home/tiago/docker-volumes/rabbitmq/rabbitmq.conf' docker run -d --hostname rabbitmq --log-driver=journald --name rabbitmq --restart unless-stopped --network host…

Web MQTT com RabbitMQ

Arquivo de configuração rabbitmq.conf loopback_users.guest = falselisteners.tcp.default = 5672management.listener.port = 15672# management.listener.ssl = truemanagement.ssl.port = 15671management.ssl.cacertfile = /etc/rabbitmq/cacert.pemmanagement.ssl.certfile = /etc/rabbitmq/cert.pemmanagement.ssl.keyfile = /etc/rabbitmq/key.pem# Certificados…