# How to get HAProxy to route TCP based on SNI (using openssl s\_client to test)?

**URL:** <https://discourse.haproxy.org/t/how-to-get-haproxy-to-route-tcp-based-on-sni-using-openssl-s-client-to-test/4625>\
**Category:** Help!\
**Created:** [December 13, 2019, 3:36pm UTC](https://discourse.haproxy.org/t/how-to-get-haproxy-to-route-tcp-based-on-sni-using-openssl-s-client-to-test/4625 "2019-12-13T15:36:24Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![johnlondon](https://avatars.discourse-cdn.com/v4/letter/j/3ab097/32.png) [@johnlondon](https://discourse.haproxy.org/u/johnlondon)\
**Post date:** [December 13, 2019, 3:36pm UTC](https://discourse.haproxy.org/t/how-to-get-haproxy-to-route-tcp-based-on-sni-using-openssl-s-client-to-test/4625/1 "2019-12-13T15:36:24Z")

</div>

I want to use HAProxy to terminate TLS-encrypted TCP connnections and to pass the unencrypted TCP traffic to various backends based on the Server Name Indication used to initiate the TLS connection.

I have 3 services running on a backend server, each on a different port (5001, 5002, 5003). HAProxy binds to port 5000. I’d like to route connections to the first 2 servies by name or to the third if there is not a match. I am initiating the connecton to HAProxy using `openssl s_client`. However, in the logs I can see that the connections are only ever routed to the default server, i.e. the SNI seems to be ignored.

**DNS:**

```
A record demo.sni.example.com 1.2.3.4
CNAME 1.sni.example.com pointing to demo.sni.example.com   
CNAME 2.sni.example.com pointing to demo.sni.example.com   

```

i.e. I’d like the following routing to occur:

```
SNI = 1.sni.example.com:5000 -> 1.2.3.4:5001
SNI = 2.sni.example.com:5000 -> 1.2.3.4:5002
anything else on port 5000 -> 1.2.3.4:5003

```

**haproxy.cfg:**

```
global
  log stdout format raw local0 info

defaults
  timeout client 30s
  timeout server 30s
  timeout connect 5s
  option tcplog

frontend tcp-proxy
  bind :5000 ssl crt combined-cert-key.pem
  mode tcp
  log global
  tcp-request inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 }

  use_backend bk_sni_1 if { req.ssl_sni -i 1.sni.example.com }
  use_backend bk_sni_2 if { req.ssl_sni -i 2.sni.example.com }
  default_backend bk_default

backend bk_sni_1
  mode tcp
  log global
  balance roundrobin
  server server1 1.2.3.4:5001 check

backend bk_sni_2
  mode tcp
  log global
  balance roundrobin
  server server1 1.2.3.4:5002 check

backend bk_default
  mode tcp
  log global
  balance roundrobin
  server server1 1.2.3.4:5003 check

```

`combined-cert-key.pem` is a self-signed certificate file plus key where the CN is the IP of the server (`1.2.3.4`) and there are SANs of all DNS values and the IP.

**Connections initiated using `openssl s_client`:**

I have tried connecting via DNS (A & CNAME records, as well as IP):

```
echo test | openssl s_client -connect demo.sni.example.com:5000 -servername 1.sni.example.com
echo test | openssl s_client -connect 1.sni.example.com:5000 -servername 1.sni.example.com
echo test | openssl s_client -connect 1.2.3.4:5000 -servername 1.sni.example.com

```

However, all connections are routed to the default backend `bk_default`.

What is causing HAProxy to not recognise the SNI servername? (I am using the latest HAProxy docker image: [https://hub.docker.com/\_/haproxy](https://hub.docker.com/_/haproxy))

---

<div class="post-metadata">

**Author:** ![johnlondon](https://avatars.discourse-cdn.com/v4/letter/j/3ab097/32.png) [@johnlondon](https://discourse.haproxy.org/u/johnlondon)\
**Post date:** [December 13, 2019, 3:50pm UTC](https://discourse.haproxy.org/t/how-to-get-haproxy-to-route-tcp-based-on-sni-using-openssl-s-client-to-test/4625/2 "2019-12-13T15:50:58Z")

</div>

The answer is to use [ssl\_fc-sni](https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#7.3.4-ssl_fc_sni), instead of `req.ssl_sni`. The former is for SSL-terminated sessions, whereas the latter is for sessions where TCP is passed straight through.

---

<div class="post-metadata">

**Author:** ![lukastribus](https://avatars.discourse-cdn.com/v4/letter/l/7ea924/32.png) [@lukastribus](https://discourse.haproxy.org/u/lukastribus)\
**Post date:** [December 13, 2019, 5:19pm UTC](https://discourse.haproxy.org/t/how-to-get-haproxy-to-route-tcp-based-on-sni-using-openssl-s-client-to-test/4625/3 "2019-12-13T17:19:01Z")

</div>

Correct, also please remove tcp-request rules and make sure you have dedicated certificates for each of those names, otherwise - if this is HTTP and browsers are the clients - you will continue to route to wrong backends when browser keepalive HTTP within the TLS sessions (there is only one SNI value in the client hello - if your TLS sessions covers multiple transactions they may intent do go to different backends if the certificate permits that).
