Forum Discussion
Azure SDK python client to Azure iothub over HAproxy (SSL handshake failure)
I am trying to fix an IP address for Azure Iothub via Load Balencer and HAproxy as suggested in this https://medium.com/cloudzone/azure-iot-hub-how-to-expose-it-using-fixed-ip-and-create-a-more-secure-environment-along-the-way-988661a8f67a: https://i.stack.imgur.com/gyQ9j.png I have configured the HAproxy as suggested to pass the SSL handshake to the server:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
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). This list is from:
# https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
# An alternative list with additional directives can be obtained from
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
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 frontend haproxy_iothub
bind *:8883
bind *:443
bind *:5671
mode tcp
default_backend iothub
backend iothub
mode tcp
server iothub [Server URL]:8883 check
server iothub [Server URL]:443 check
server iothub [Server URL]:5671 check
To simulate the device, I used Azure V2 SDK (azure-iot-device) and defined a proxy option and created a client from a connection string.
proxy_opts = ProxyOptions(proxy_type=socks.HTTP, proxy_addr="Proxy_ IP", proxy_port=8883)
device_client = IoTHubDeviceClient.create_from_connection_string("IOTHUB_DEVICE_CONNECTION_STRING", websockets=True, proxy_options=proxy_opts )
I was not able to reach the iothub, I tried debugging the library to get more information and it turned out that the blocking occurs due to a general proxy error ("connection closed unexpectedly") in _negotiate_HTTP. socks.HTTPError :504 : Gateway Time-out (in socks.py)
HAproxy logging showes :
Oct 18 08:48:37 vmss2xigg000000 haproxy[27470]: *..:59000 [18/Oct/2021:08:48:37.451] haproxy_iothub iothub/iothub1 1/1/38 0 -- 1/1/0/0/0 0/0
Any help much appreciated
HA-Proxy version 1.8.8-1ubuntu0.11
Azure-iot-device Version 2.8.0
1 Reply
Take this:
1. Use TCP Mode Only (No SSL Termination)
Azure IoT Hub expects TLS to be terminated only at its endpoint. Your HAProxy config must forward raw TCP traffic without interpreting or modifying SSL.
- Ensure frontend and backend are in mode tcp (Done).
✅ 2. Avoid Port Multiplexing
Each port (443, 8883, 5671) serves a different protocol:
- 8883 → MQTT over TLS
- 443 → HTTPS/WebSockets
- 5671 → AMQP over TLS
Instead of binding all ports in one frontend, create separate frontends per port:
frontend iothub_mqtt bind *:8883 mode tcp default_backend iothub_mqtt_backend backend iothub_mqtt_backend mode tcp server iothub_mqtt <iot-hub-hostname>:8883 check frontend iothub_websockets bind *:443 mode tcp default_backend iothub_websockets_backend backend iothub_websockets_backend mode tcp server iothub_ws <iot-hub-hostname>:443 check3. Use Correct SDK Protocol
Your SDK call uses websockets=True, which means it connects via port 443 using WebSockets. Ensure:
- HAProxy frontend for port 443 is active.
- Backend points to Azure IoT Hub’s FQDN on port 443.
- No SSL termination or inspection is done.
4. Proxy Configuration in SDK
The SDK’s ProxyOptions is intended for HTTP proxies, not TCP-level proxies like HAProxy. If you’re using HAProxy as a TCP passthrough, you don’t need to set proxy_options.
Instead:
device_client = IoTHubDeviceClient.create_from_connection_string( "IOTHUB_DEVICE_CONNECTION_STRING", websockets=True )And configure your system-level routing to direct traffic to HAProxy’s fixed IP.