# TCP TLS server with non-TLS TCP router

**URL:** <https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539>\
**Category:** Traefik v2\
**Tags:** file, tcp\
**Created:** [September 10, 2019, 8:06pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539 "2019-09-10T20:06:30Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![mason-mcglothlin](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/mason-mcglothlin/32/657_2.png) [@mason-mcglothlin](https://community.traefik.io/u/mason-mcglothlin)\
**Post date:** [September 10, 2019, 8:06pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539/1 "2019-09-10T20:06:30Z")

</div>

I have an older application that has no TLS support that needs to make TLS TCP connections to a certain IP. I was hoping to use Traefik v2 for this. Can Traefik listen for TCP connections that don't use TLS, and then make a TLS connection to a backend service? Here's how I was envisioning the configuration:

```auto
[tcp]
  [tcp.routers]
    [tcp.routers.FrontendTCPRouter]
      entryPoints = ["EntryPoint0"]
      # Catch every request (only available rule for non-tls routers. See below.)
      rule = "HostSNI(`*`)"
      service = "BackendTCPService"
  [tcp.services]
    [tcp.services.BackendTCPService.loadBalancer]
       [[tcp.services.BackendTCPService.loadBalancer.servers]]
         address = "localhost:8050"
         tls = true

```

---

<div class="post-metadata">

**Author:** ![mumie](https://avatars.discourse-cdn.com/v4/letter/m/94ad74/32.png) [@mumie](https://community.traefik.io/u/mumie)\
**Post date:** [November 7, 2019, 2:55pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539/2 "2019-11-07T14:55:21Z")

</div>

looking for a similar solution! is it possible to have a TCP SSL/TLS Backend-service? or is this not supported yet?  
Best Regards

---

<div class="post-metadata">

**Author:** ![mason-mcglothlin](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/mason-mcglothlin/32/657_2.png) [@mason-mcglothlin](https://community.traefik.io/u/mason-mcglothlin)\
**Post date:** [November 7, 2019, 3:08pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539/3 "2019-11-07T15:08:31Z")

</div>

I ended up not using Traefik to solve this. I used Stunnel. It's not Dockerized and the documentation is a little clunky, but I got it working.  
[https://www.stunnel.org](https://www.stunnel.org/)

---

<div class="post-metadata">

**Author:** ![d21d3q](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/d21d3q/32/1381_2.png) [@d21d3q](https://community.traefik.io/u/d21d3q)\
**Post date:** [January 4, 2020, 1:45pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539/4 "2020-01-04T13:45:41Z")

</div>

I managed to achieve this. My goal was to placing mqtt broker (rabbitmq) behind traefik, so that for single container I am exposing 3 endpoints `https` for management, `mqtt` for unencrypted TCP traffic and `mqtts` for encrypted TCP traffic.

part of `traefik.toml`:

```auto
[entryPoints]
  [entryPoints.http]
    address = ":80"
  [entryPoints.https]
    address = ":443"
  [entryPoints.mqtt]
    address = ":1883"
  [entryPoints.mqtts]
    address = ":8883"

```

and part of `docker-compose.yml`:

```auto
  rabbitmq:
    image: rabbitmq:management
    restart: always

    volumes:
      - ./config/rabbitmq/advanced.config:/etc/rabbitmq/advanced.config:ro
      - ./config/rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins:ro
      - rabbitmq_data:/var/lib/rabbitmq

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.router-broker-mgmt.rule=Host(`broker.${PROXY_BASE_DOMAIN}`)"
      - "traefik.http.routers.router-broker-mgmt.tls=true"
      - "traefik.http.routers.router-broker-mgmt.tls.certresolver=le"
      - "traefik.http.routers.router-broker-mgmt.entrypoints=https"
      - "traefik.http.routers.router-broker-mgmt.service=service-broker-mgmt"
      - "traefik.http.services.service-broker-mgmt.loadbalancer.server.port=15672"

      - "traefik.tcp.routers.router-broker-mqtts.rule=HostSNI(`broker.${PROXY_BASE_DOMAIN}`)"
      - "traefik.tcp.routers.router-broker-mqtts.tls=true"
      - "traefik.tcp.routers.router-broker-mqtts.tls.certresolver=le"
      - "traefik.tcp.routers.router-broker-mqtts.entrypoints=mqtts"
      - "traefik.tcp.routers.router-broker-mqtts.service=service-broker-mqtts"
      - "traefik.tcp.services.service-broker-mqtts.loadbalancer.server.port=1883"

      - "traefik.tcp.routers.router-broker-mqtt.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.router-broker-mqtt.entrypoints=mqtt"
      - "traefik.tcp.routers.router-broker-mqtt.service=service-broker-mqtt"
      - "traefik.tcp.services.service-broker-mqtt.loadbalancer.server.port=1883"

```

you have to play with converting labels into toml.

---

<div class="post-metadata">

**Author:** ![bmeneg](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/bmeneg/32/7223_2.png) [@bmeneg](https://community.traefik.io/u/bmeneg)\
**Post date:** [June 9, 2023, 3:42pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539/5 "2023-06-09T15:42:27Z")

</div>

Ok, that's interesting: when using the wildcard '\*' it works just fine with no TLS options at all, but when using an explicit HostSNI Traefik complains about the lack of TLS option. For instance (using file provider):

```auto
tcp:
  routers:
    system-db:
      entrypoints:
        - "postgres"
      rule: "HostSNI(`system-db.example.com`)"
      service: "system-db"
      tls: {}
    gnucash-db:
      entrypoints:
        - "postgres"
      rule: "HostSNI(`*`)"
      service: "gnucash-db"

  services:
    system-db:
      loadBalancer:
        servers:
          - address: "10.0.0.33:8086"
    gnucash-db:
      loadBalancer:
        servers:
          - address: "10.0.0.33:8085"

```

The above just works and Traefik's monitor dashboard correctly states the first route (system-db) has TLS enabled while the second (gnucash-db) is non-TLS. However, if I change the second to use "HostSNI(`gnucash-db.example.com`)", instead of the wildcard, I get the following error:

> invalid rule: "HostSNI(`gnucash-db.example.com`)" , has HostSNI matcher, but no TLS on router

Why is TLS enforced in such cases?

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [June 9, 2023, 4:29pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539/6 "2023-06-09T16:29:46Z")

</div>

Traefik can only read HostSNI when TLS is enabled and the certs are present.

TLS is used to encrypt the traffic, it is doing this even for the Host, so no one can see during transit what is happening.

---

<div class="post-metadata">

**Author:** ![bmeneg](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/bmeneg/32/7223_2.png) [@bmeneg](https://community.traefik.io/u/bmeneg)\
**Post date:** [June 9, 2023, 4:37pm UTC](https://community.traefik.io/t/tcp-tls-server-with-non-tls-tcp-router/1539/7 "2023-06-09T16:37:14Z")

</div>

Ah ok! I completely missed the fact that SNI is an extension of TLS!  
In the docs, there even is a specific note about that:

> It is important to note that the Server Name Indication is an extension of the TLS protocol.  
> Hence, only TLS routers will be able to specify a domain name with that rule. However, there  
> is one special use case for HostSNI with non-TLS routers: when one wants a non-TLS router  
> that matches all (non-TLS) requests, one should use the specific HostSNI(`*`) syntax.
