HAProxy community

TCP proxy with SNI support


I have a single server with one Public IP and 10 domains. For each domain I’d like to have a separate docker container as an email server (Postfix + Dovecot). I’d like to achieve this with transparent TCP proxy with SNI support.

I’d like to route traffic from example.com on ports 587 & 143 to one container and traffic for acme.com on ports 587 & 143 to a different container, etc.

Can I achieve this by using host:port? Does anyone know of an example?

I found some information on http://www.haproxy.org/download/1.6/doc/configuration.txt about this, but not enough to achieve my desired setup.

Thank you.

This will not work, in short: SNI can only be used in protocols that implicitly use SSL (like HTTPS), not in protocols with explicit SSL via STARTTLS:

Please see the following thread for more details:


Thank you for your reply. If so, why does wiki state this …?

The “use-server” statement works both in HTTP and TCP mode. This makes it
suitable for use with content-based inspection. For instance, a server could
be selected in a farm according to the TLS SNI field. And if these servers
have their weight set to zero, they will not be used for other traffic.

Example :
# intercept incoming TLS requests based on the SNI field
use-server www if { req_ssl_sni -i www.example.com }
server www weight 0
use-server mail if { req_ssl_sni -i mail.example.com }
server mail weight 0
use-server imap if { req_ssl_sni -i imap.example.com }
server imap weight 0
# all the rest is forwarded to this server
server default check

You’re right, that’s a documentation error. 993 is implicit TLS, which will work (if client send SNI), 587 is explicit TLS which will not work.

But it doesn’t make sense to show an example SNI routing traffic for mailservers, given that a full setup (with all protocols a mail-server needs) is not possible and something is always missing. So this needs to be fixed in the documentation.

I’ve tried the following config within HAProxy and traffic still doesn’t get through to docker containers?

    timeout client 30s
    timeout server 30s
    timeout connect 5s

    option tcplog
    log global

frontend smtp_submission

    mode tcp
    bind *:465

    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    use_backend smtp_submission

frontend imap

    mode tcp
    bind *:993

    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    use_backend imap

backend smtp_submission

    mode tcp

    acl mail_domain1_match req_ssl_sni -i smtp.domain1.com
    acl mail_domain2_match req_ssl_sni -i smtp.domain2.com

    use-server mail_domain1_smtp_submission if mail_domain1_match
    use-server mail_domain2_smtp_submission if mail_domain2_match

    option ssl-hello-chk

    server mail_domain1_smtp_submission weight 0
    server mail_domain2_smtp_submission weight 0

backend imap

    mode tcp

    acl mail_domain1_match req_ssl_sni -i imap.domain1.com
    acl mail_domain2_match req_ssl_sni -i imap.domain2.com

    use-server mail_domain1_imap if mail_domain1_match
    use-server mail_domain2_imap if mail_domain2_match

    option ssl-hello-chk

    server mail_domain1_imap weight 0
    server mail_domain2_imap weight 0

Check if your requests actually contain SNI (don’t just assume that) by capturing ssl client_hello and opening it in wireshark. Also check haproxy logging for those requests.