TCP Router Priority

I have a TLS passthrough service up and running, and it works great. However, it is the catchall, and so uses HostSNI(*) to catch all domains. I have another service that is a website (let's call it example.company.com), which also needs to server over HTTPS. Is there a way to configure the TCP router to route https://example.company.com to my website service, and all other domains to the catch all HostSNI(*) service?

Basically need the priority functionality from HTTP routers to be available with TCP routers that are using SNI.

1 Like

Hi @piurafunk , if you specify HostSNI(*), then it means that you expect any incoming request on the associated entrypoint(s) of this router to be intercepted.

Is there something forbidding you to bind the TCP router only to the entrypoint corresponding to your TCP protocol, and your HTTP router(s) only on the entrypoints for hte 80 and 443 ports?

1 Like

Yes, my TCP catchall is an HTTPS passthrough, so it is also listening on 443.

Oh, good. Then, since HTTP+TLS are supporting SNI and doing proper handshake, then you can specify the expected Host to your HostSNI() rule instead of *. Let us know if there is anything preventing you to specify this domain?

You have an example here (with MongoDB but it's the same idea): https://github.com/containous/slides/blob/oss-summit-lyon-2019/demo/traefik-v2/mongo/04-tcp-and-http-routing-mongo/docker-compose.yml .

Yes, if I knew the expected host it would be easy. Unfortunately, my catchall is just that: an HTTPS catchall. Any hosts can go through it. There are just a few hosts that I do not want to go through it, as they have their own services (also HTTPS).

I believe I could get this to work if HostSNI had a RegExp version of it, like Host as its counterpart HostRegExp, but I don't believe that rule exists.

Hi @piurafunk, after checking with other maintainers, your initial case should work, as they told me that HostSNI(*) should behave as a fallback in this case.

Could you share your configuration so we can check and reproduce?

Thanks a lot

This is my docker-compose.yml, I trimmed out unhelpful bits (like source volume mounts and what not).

version: "3.7"

services:
  traefik:
    # The official v2.0 Traefik docker image
    image: traefik:v2.0
    # Enables the web UI and tells Traefik to listen to docker
    command: [
      "--api.insecure=true",
      "--providers.docker",
      "--entryPoints.websecure.address=:443",
      "--entryPoints.web.address=:80",
      "--certificatesResolvers.api.acme.email=<REDACTED>",
      "--certificatesResolvers.api.acme.storage=acme.json",
      "--certificatesResolvers.api.acme.httpChallenge.entryPoint=web"
      ]
    ports:
      # The HTTP port
      - "80:80"
      # The HTTPS port
      - "443:443"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock:ro
  sni:
    image: lancachenet/sniproxy
    expose:
      - 443
    labels:
      - "traefik.tcp.routers.cache-sni.tls.passthrough=true"
      - "traefik.tcp.routers.cache-sni.entryPoints=websecure"
      - "traefik.tcp.routers.cache-sni.rule=HostSNI(`*`)"
    environment:
      - "UPSTREAM_DNS=1.1.1.1 1.0.0.1"
  api:
    image: php:7.3-apache
    labels:
      - "traefik.http.routers.api-https.rule=Host(`example.company.com`)"
      - "traefik.http.routers.api-https.tls"
      - "traefik.http.routers.api-https.tls.certResolver=api"
      - "traefik.http.routers.api-http.rule=Host(`example.company.com`)"
      - "traefik.http.routers.api-https.priority=2"
      - "traefik.http.routers.api-http.priority=2"
      - "traefik.entryPoints.web.address=:80"
      - "traefik.entryPoints.web-secure.address=:443"

I have tried it in this manner, but the catchall HTTPS rule grabs the inbound request before Traefik can terminate TLS for the API container (note: API is TLS terminated, SNI is TLS passthrough). Using HTTPie, I can make a request and watch it show up in the SNI container:

$> http https://example.company.com
...
$> docker-compose logs sni
Attaching to sni_1_c8423c510e54
sni_1_c8423c510e54 | 2019-10-31 15:42:52 172.18.0.6:41916 -> 172.18.0.7:443 -> NONE [example.company.com] 0/0 bytes tx 517/1034 bytes rx 0.002 seconds

This is why I was looking for a priority system with TLS and HostSNI. I could then prioritize the API container over the catchall, and it should work.

I have the same challange as need priority so defined hastnames can take priority over * in TCP

Hello friends,

I recently opened a ticket in github ( ingressRouteTCP: unknown field "priority" #9290 ), however it got closed, so I hope, that I have more luck here. This thread seems to fit the topic.

I tried to configure a priority (Link) for an ingressRouteTCP router within kubernetes. The CRD defines the priority field, however, when trying to define it, I recieve an error:

error validating data: ValidationError(IngressRouteTCP.spec.routes[0]): unknown field "priority" in us.containo.traefik.v1alpha1.IngressRouteTCP.spec.routes; if you choose to ignore these errors, turn validation off with --validate=false

I used traefik version 2.8.3 and 2.9-rc3 for my test. This is the configuration I used:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: c2ss
  namespace: xmpp
spec:
  entryPoints:
    - websecure
  routes:
  - match: HostSNI(`example.net`, `example.com`)
    priority: 50
    services:
    - name: ejabberd
      port: 5223
      proxyProtocol:
        version: 2
  tls:
    passthrough: true

It would be great, if you can give me a hint, if I oversee something.

thanks and best regards!
sando

My question was answered here: