Option passthrough hands out default certificate

Hi,
my setup: Synology NAS running service X behind gateway GW running traefik
the Synology NAS has a letsencrypt certificate for the domain x.examle.com (I've replaced my domain by example.com in the text)

goal: traefik passthrough HTTPS requests targeting x.examle.com to the NAS without delivering a self signed, default certificate by itself. The certificate the client gets should be the letsencrypt certificate from the NAS

problem: traefik hands out its own certificate. The SSL Test from Qualys outputs for x.example.com:

"Certificate name mismatch - b5cb5...14e4ee.traefik.default)"

traefik logs:

level=debug msg="Serving default certificate for request: "x.example.com""
level=debug msg="http: TLS handshake error from <IPv4>:22243: remote error: tls: bad certificate"

(that's all no more messages ...)

traefik's dynamic.yml (only for testing, not final version):

serversTransport:
  insecureSkipVerify: true

tcp:
  routers:
    router-x:
      entryPoints:
        - websecure
      rule: "HostSNI(`*`)" # catch all
      service: service-x
      tls:
        passthrough: true

  services:
    service-x:
      loadBalancer:
        servers:
          - url: "https://x.example.com" # 'x.example.com' is resolved to the internal IPv4 address of the NAS by an self-host DNS server

traefik.yml:

api:
  dashboard: true
  insecure: true

entryPoints:
  websecure:
    address: ':443'

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: mynet
  file:
    filename: "./dynamic.yml"
    watch: true

serversTransport:
    insecureSkipVerify: true

log:
  level: "DEBUG"
  filePath: "/logs/traefik.log"

accessLog:
  filePath: "/logs/access.log"
  bufferingSize: 100

How do I get traefik passthrough the letsencrypt certificate from the NAS?

Which component should create the LE cert?

If Traefik is not involved in cert creation, then you can use HostSNI(`*`) and just pass on the TCP stream. Use a matching TCP service with address, see doc:

tcp:
  services:
    my-service:
      loadBalancer:
        servers:
        - address: "xx.xx.xx.xx:xx"
        - address: "xx.xx.xx.xx:xx"

The reverse proxy on the Synology NAS (nginx) create the letsencrypt certificate (ngix listens to port 443 and dispatches domain 'x.examle.com' to the desired service).

I chanded the dynamic.yml to:

tcp:
  routers:
    router-x:
      entryPoints:
        - websecure
      rule: "HostSNI(`*`)"
      service: service-x
  services:
    service-x:
      loadBalancer:
        servers:
          - address: "192.168.199.77;443" # address of NAS

This works.

HostSNI(*.example.com) or HostSNI(x.example.com) do not work.

Is there a possibility to specify a special domain so that only reuest to this domain are passed through?

For Traefik to be able to match requests with HostSNI() other than *, it needs to read the LE certs from nginx to decrypt the TLS requests.

OK, reading the ngix certificate seams not a good solution .

I'd like to reformulate my problem:
My network is reached by domain abc.com. A traefik instance running on the gateway GW already manages letsencrypt certificates for the domain abc.com. On the NAS at the backend ngix is running (default from Synology). The ngix manages the letsenrcytp certificates for domain example.com.

Is it possible that traefik on GW terminates a incomming TLS connection for x.abc.com and transforms this request so that it is forwarded to the ngix via HTTPS? So that the client that requested for x.abc.com gets a response form the NAS throught the GW?

In other words: how to get following scenario working ...

client C wants to use service X over HTTPS that is behind traefik on gateway GW and ngix on Synology NAS (service X is running as docker image on the NAS). client C uses domain x.abc.com in order to access the service.

the constraints are:

  • client X should use domain x.abc.com (I don't like to expose example.com)
  • service X uses verified or self-signed certificates
  • client X does not accept self-signed certificates

What would be the best solution?

thank you in advance

Yes, you should be able to set the scheme for a Traefik service to use https for the forward (or loadBalancer: servers: - url: https://...). If the target service has a valid TLS cert it just works, otherwise you would need to use insecureSkipVerify.

Could you give some advice what the correct syntax is?
my dynamic.yml looks like this:

http:
  routers:
    router-y:
      entryPoints:
        - websecure
      rule: "Host(`y.abc.com`)"
      service: service-y
      tls:
        certResolver: tls_resolver

    router-z:
      entryPoints:
        - websecure
      rule: "Host(`z.abc.com`)"
      service: service-z
      tls:
        certResolver: tls_resolver

    router-x:
      entryPoints:
        - websecure
      rule: "Host(`x.abc.com`)"
      service: service-x
  
  services:
    service-y:
      loadBalancer:
        passHostHeader: true
        servers:
        -  url: "https://192.168.199.77:17001"

    service-z:
      loadBalancer:
        passHostHeader: true
        servers:
        - url: "https://192.168.199.77:17002"

    service-x:
      loadBalancer:
        passHostHeader: true
        servers:
        - url: "https://192.168.199.77:17003" # this needs to use the cert of x.example.com

How would the config look like for router-x and service-x that runs on 192.168.199.77:17003 using the https scheme and forwarding the request?

Well, the scheme is more for auto-discovery, you have it already, looks good.

You can place the TLS globally on the entrypoint, then you don't need to repeat it on every router, see simple Traefik example.

I found a solution that works for me. A client can access services Y and Z via y.abc.com and z.abc.com from the INet. For service X URL x.example.com must be used:

http:
  routers:
    router-y:
      entryPoints:
        - websecure
      rule: "Host(`y.abc.com`)"
      service: service-y
      tls:
        certResolver: tls_resolver

    router-z:
      entryPoints:
        - websecure
      rule: "Host(`z.abc.com`)"
      service: service-z
      tls:
        certResolver: tls_resolver

  services:
    service-y:
      loadBalancer:
        passHostHeader: true
        servers:
        -  url: "https://192.168.199.77:17001"

    service-z:
      loadBalancer:
        passHostHeader: true
        servers:
        - url: "https://192.168.199.77:17002"

tcp:
  router-x:
      entryPoints:
        - websecure
      rule: "HostSNI(`*`)"
      service: service-x
      priority: 1

    service-x:
      loadBalancer:
        passHostHeader: true
        servers:
        - address: "192.168.199.77:443" # address and port of ngnix servicing service X

I'm unhappy that I've to use a catch-all HostSNI(*) (seams to me a security risc).
I prefer to leave all that to traefik since it is the public facing proxy (with its abc.com certificates).

So I'd like to terminate TLS on traefik and then establish another TLS connection to nginx on the NAS (only listening on HTTPS).

What are you complaining about? :slight_smile:

If Traefik should use HostSNI(), then Traefik needs access to the cert, otherwise Traefik can not decrypt the request and can not read the target domain.

Using HostSNI(x.example.com) on the GW I've to mount the ngnix certificates (created on the NAS) via NFS so that traefik can use them (via certFile, keyFile I think) - that's better than the catch-all-HostSNI but also not so nice (I'd like to keep the certificates on the host).

Could you give me blueprint that doesn't require the tcp-rules? My previously posted version without the tcp-rule doesn't work.

I've imported the privkey from the NAS (used for the x.exmple.com certificate) now I'm able to filter for HostSNI(x.example.com)