Port forwarding with docker and ssl apps

Hey there,

I'm considering using traefik as a reverse proxy for 2 main purposes :

  • Avoid port in URL
  • Having multiple hosts for the same container

Simplified context : I actually have an https app containing a node server (could be dotnet app) and listening on https://domain:port. There is an enpoint that print "ok" if the server is reached.
I set up traefik to be able to access "https:domain" and be forwarded on the right container.

docker-compose

version: '2.2'

services:

  reverse:
    image: traefik:v2.5
    hostname: traefik.domain
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./configuration/:/configuration/
      - ./certs/:/tools/certs/:ro
    command:
      - --log.level=debug
      - --api.dashboard=true
      - --pilot.dashboard=false

      - --providers.docker.exposedbydefault=false
      - --providers.file.directory=/configuration/
      - --providers.file.watch=true
      
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.web.http.redirections.entrypoint.permanent=true

      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.forwardedHeaders.insecure=true
    labels:
      traefik.enable: 'true'

      # Dashboard
      traefik.http.routers.traefik.rule: Host(`traefik.domain`)
      traefik.http.routers.traefik.service: api@internal
      traefik.http.routers.traefik.entrypoints: websecure

myservice:
    image: myserver/myimage
    hostname: myhostname
    environment:
      - ...
    volumes:
      - ...   
    labels:
      traefik.enable: true
      traefik.http.routers.myservice.rule: Host(`myhostname`)
      traefik.http.routers.myservice.tls: true
      traefik.http.services.myservice.loadbalancer.server.port: 443
      # traefik.http.routers.myservice.entrypoints: websecure <= Tried this.
   
     # Also try this following configuration =>
     # traefik.http.routers.myservice.middlewares: myserviceredirect
     # traefik.http.middlewares.myserviceredirect.redirectscheme.scheme: https
     # traefik.http.middlewares.myserviceredirect.redirectscheme.permanent: true
     # traefik.http.services.myservice.loadbalancer.passHostHeader: true

configuration/certificates.yml

tls:
  options:
    default:
      sniStrict: true
  certificates:
    - certFile: /tools/certs/cert1.io.crt
      keyFile: /tools/certs/cert1.key
    - ...

When I try to reach the following endpoint : https://myhostname/check, I have a gateway timeout.
When I check logs on the reverse proxy, I see that the forward URL is "http" instead of "https".

time="2021-10-29T12:33:11Z" level=debug msg="vulcand/oxy/roundrobin/rr: Forwarding this request to URL" ForwardURL="http://XXX.XX.XX.XXX:443" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/check\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"fr-FR,fr;q=0.9\"],\"Sec-Ch-Ua\":[\"\\\"Google Chrome\\\";v=\\\"95\\\", \\\"Chromium\\\";v=\\\"95\\\", \\\";Not A Brand\\\";v=\\\"99\\\"\"],\"Sec-Ch-Ua-Mobile\":[\"?0\"],\"Sec-Ch-Ua-Platform\":[\"\\\"Windows\\\"\"],\"Sec-Fetch-Dest\":[\"document\"],\"Sec-Fetch-Mode\":[\"navigate\"],\"Sec-Fetch-Site\":[\"none\"],\"Sec-Fetch-User\":[\"?1\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36\"],\"X-Forwarded-Host\":[\"myhostname\"],\"X-Forwarded-Port\":[\"443\"],\"X-Forwarded-Proto\":[\"https\"],\"X-Forwarded-Server\":[\"traefik.domain\"],\"X-Real-Ip\":[\"XXX.XX.XXX.X\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"myhostname\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"XXX.XX.XXX.X:62259\",\"RequestURI\":\"/check\",\"TLS\":null}"

What am I missing?

Note : If I set the node server listening http://myhostname:80 and set port 80 for the loadbalancer, the forware url is ok and I can reach the endpoint.
I really need the forward url scheme to be https and not http.

Thanks in advance.

Hello @Sheevouille and thanks for your interest in Traefik,

Have you tried to add the traefik.http.services.myservice.loadbalancer.server.scheme=https label to the container? (see Docker - Traefik)

By the way, if you need to configure the secure connection between Traefik and the backend, you will have to configure a ServersTransport with the file provider and to reference it with the traefik.http.services.myserviceloadbalancer.serverstransport=serversTransportName@file" label.

Hope this helps!

Thanks a lot for your help @kevinpollet
The scheme on the loadbalancer has fixed the scheme redirection issue in the forwarded Url.

I also check your link about server transport and it seems to be what I need to have a forward Url on a domain instead of the docker container's IP address.

I added the following configuration file in /configuration folder :

http:
  serversTransports:
    mytransport:
      serverName: "myhostname"
      certificates:
        - certFile: /tools/certs/production/myhostname.crt
          keyFile: /tools/certs/production/myhostname.key
      rootCAs:
        - /tools/certs/CA.crt

And I referenced it on the loadbalancer :

traefik.http.services.myservice.loadbalancer.passHostHeader: true
traefik.http.services.myservice.loadbalancer.serverstransport: mytransport@file

The forward Url seems to keep the docker container's IP address instead of using the server name.
And I have the foloowing error on the certificate :

time="2021-11-17T11:43:32Z" level=debug msg="vulcand/oxy/roundrobin/rr: Forwarding this request to URL" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/favicon.ico\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"fr-FR,fr;q=0.9\"],\"Referer\":[\"https://myhostname/check\"],\"Sec-Ch-Ua\":[\"\\\"Google Chrome\\\";v=\\\"95\\\", \\\"Chromium\\\";v=\\\"95\\\", \\\";Not A Brand\\\";v=\\\"99\\\"\"],\"Sec-Ch-Ua-Mobile\":[\"?0\"],\"Sec-Ch-Ua-Platform\":[\"\\\"Windows\\\"\"],\"Sec-Fetch-Dest\":[\"image\"],\"Sec-Fetch-Mode\":[\"no-cors\"],\"Sec-Fetch-Site\":[\"same-origin\"],\"User-Agent\":[\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36\"],\"X-Forwarded-Host\":[\"myhostname\"],\"X-Forwarded-Port\":[\"443\"],\"X-Forwarded-Proto\":[\"https\"],\"X-Forwarded-Server\":[\"traefik.domain\"],\"X-Real-Ip\":[\"X.X.X.X\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"myhostname\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"X.X.X.X:59486\",\"RequestURI\":\"/favicon.ico\",\"TLS\":null}" ForwardURL="https://X.X.X.X:443"
time="2021-11-17T11:43:32Z" level=debug msg="'500 Internal Server Error' caused by: x509: certificate signed by unknown authority"
time="2021-11-17T11:43:32Z" level=debug msg="vulcand/oxy/roundrobin/rr: completed ServeHttp on request"

Yes, I have secured my traefik dashboard with a basic authentication following the documentation.

Thanks again for your help

The forward Url seems to keep the docker container's IP address instead of using the server name.

The serverName configuration does not mean that the ForwardURL will use it. The serverName configuration is used to send the TLS SNI during the handshake and to verify that the server TLS certificate contains the configured value as a SAN (this means that your certificate must be valid for the myhostname domain).

time="2021-11-17T11:43:32Z" level=debug msg="'500 Internal Server Error' caused by: x509: certificate signed by unknown authority"

This error means that the server certificate has been signed by an unknown authority (the CA root certificate is not available in the system trustore). To fix that, the rootCAs config option should reference the CA certificate which has been used to sign/issue the myhostname certificate.

Does it make sense?

Yes totally.
Thanks for the explaination.

I put the ".crt" root certificate instead of the ".pem" used to sign the hostname.
All is ok now.

Thanks for your quick reply and your help.

1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.