How to setup Traefik as reverse proxy for ASP.NET Core app with kestrel?

Hello everybody, I am quite new at this and already a problem)

I took an example of a simple ASP.NET Core application from the Microsoft site, which, after deployment, is available at localhost:8443 using https, because earlier I released a self-signed (aspnetapp.pfx), ok.

Then I unfolded the traefik and configured the dashboard I see that traefik gets information about the aspnet_demo container, but at web app addresses, or webapp.mydomen.com/ or localhost nothing is available - maximum I get the error ERR_TOO_MANY_REDIRECTS in browser.

In logs traefik when referring to webapp.mydomen.com I get "RequestURI ": "/ "

What did you forget to point out?

I understand that the content aspnet_demo get on 443 port, so I tell Traefik where to look, but nothing...

Help me please understanding this. Thank you

My docker compose ASP.NET Core app looks like this:

version: "3.8"  
services:   
  aspnet_demo:     
    image: mcr.microsoft.com/dotnet/core/samples:aspnetapp
    container_name: aspnet_sample     
    ports:
      - 8080:80
      - 8443:443
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:443;http://+:80
      - ASPNETCORE_Kestrel__Certificates__Default__Password=password
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
    volumes:
      - ~/.aspnet/https:/https:ro
    networks: 
      - traefik-reverse-proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.aspnet.entrypoints=web
      - traefik.http.routers.aspnet.rule=Host(`webapp`)
      - traefik.http.routers.aspnet_secure.entrypoints=web-secure
      - traefik.http.routers.aspnet_secure.rule=Host(`webapp.mydomen.com`)
      - traefik.http.routers.aspnet_secure.tls=true
      - traefik.http.services.aspnet.loadbalancer.server.port=443

networks:
  traefik-reverse-proxy:
    external: true 

My docker compose Traefik looks like this:

version: "3.8"
services:
  traefik:
    image: traefik:v2.9
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    networks:
      - traefik-reverse-proxy
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./configuration/dynamic.yaml:/traefik_conf/dynamic.yaml"
      - "./configuration/traefik.yml:/traefik.yml:ro"
      - "./cert/:/traefik_conf/cert/"
    labels: 
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.entrypoints=web-secure"
      - "traefik.http.routers.traefik.rule=Host(`traefiklocal.mydomen.com`)"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.tls.certresolver=tls"
      - "traefik.http.routers.traefik.middlewares=traefik-auth"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=unixhost:$apr1$vqyMX723$6nZ1lC3/2JN6QJyeEhJB8/"      
   
networks:
  traefik-reverse-proxy:
    external: true 

My static config Traefik looks like this:

api:
  dashboard: true
  insecure: true

log:
  level: DEBUG

entryPoints:
  web:
    address: ":80"
    forwardedHeaders:
      insecure: true
    http:
      redirections:
        entryPoint:
          to: web-secure
  web-secure:
    address: ":443"

providers:   
  docker:
    watch: true
    exposedbydefault: false 
  file:
    directory: /traefik_conf/
    watch: true
    filename: dynamic.yaml

My dynamic config Traefik:

tls:
  certificates:
      # first certificate
    - certFile: "/traefik_conf/cert/pem_com_2022.pem"
      keyfile: "/traefik_conf/cert/star_com_2022.key"
      # second certificate
    - certFile: "/traefik_conf/cert/aspnetapp.pem"
      keyfile: "/traefik_conf/cert/aspnetapp.key"
      stores:
        - default

When using Traefik as reverse proxy, you usually do not expose ports of your app service. Instead you attach Traefik and your app service to the same network. Furthermore you tell Traefik via the app service label ...loadbalancer... which port it should use.

I would enable debug log and access log to be able to see incoming requests.

Your Traefik config is already redirecting all http to https, so you don't need entrypoint web on your app service labels.

Why do you use https on your internal service? I think it's standard to terminate TLS/SSL at the entrance to your network with Traefik.

1 Like

Thank you very much for the response, I really did not try to close the port 443 aspnet app. If leave only 80 port, then traefik works perfectly, gives the content of the page at the request of the host, but

In my case, I have 4 services in docker containers, 1 GRPC server and 3 GRPC client that communicate via GRPC protocol, among themselves, and by GRPC requirement, the connection between containers should be protected by SSL/TLS certificate.

To do this, it was decided to form an aspnet.pfx development certificate certified by CA.cert (with the service names specified as DNS-name), which were placed in each container and installed by the command.

ADD .docker/cert/CAroot.cer /usr/local/share/ca-certificates/CAroot.cer
RUN openssl x509 -inform PEM -in /usr/local/share/ca-certificates/CAroot.cer -out /usr/local/share/ca-certificates/certificate.crt
RUN chmod 644 /usr/local/share/ca-certificates/certificate.crt && update-ca-certificates

COPY ./.docker/aspapp.pfx /app/cert/certificat.pfx
ENV    ASPNETCORE_URLS=https://+;http://+ \
       ASPNETCORE_Kestrel__Certificates__Default__Path=/app/cert/certificat.pfx 

In this way, containers are connected via GRPC using this sertificate to create a secure tunnel (without certificates did not work, received SSL errors)

But now after i turn on 443 port i get Bad Gateway in browser

NGINX as reverse proxy had its own *.mydomen.com certificate and routed traffic coming from the https://test.mydome.com address on GRPC service https://NameOfContainerInClusterSwarm

This functionality I wanted to build in traefik but not yet possible

did you manage to get this working? In the same scenario ... using Traefik as reverse proxy into my docker network, hosting multiple ASP.NET | Open-source web framework for .NET containers that /must/ communicate inside the docker network over TLS/443

Check insecureskipverify, see other comment.

Thanks for sharing, @bluepuma77 !

Do you know if this should work for calls originating from one docker container to another? Or does this only apply to calls proxied in through Traefik from the outside? I tried throwing this in my static configuration but am still getting certificate validation errors with insecureskipverify set to true. Maybe there is another step im missing :sweat_smile:

This should work for all outgoing requests from Traefik to its configured services.

Try the global insecureskipverify setting in static config (traefik.yml or command:), watch letter capitalization.

Check Traefik debug logs.

If it still doesn’t work, post your full config again.

I did some testing, and I still can't seem to get it right. Thanks for your patience with me, I'm pretty new to Traefik :slight_smile:

I'm not sure if maybe my config is ineffective. I have tried a bunch of things to get TLS appropriately set up for the container, but almost everything fails for me. Any advice or pointers would be deeply appreciated!

Traefik.yml

global:
  sendAnonymousUsage: false

api:
  dashboard: true
  insecure: true

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    watch: true
    exposedByDefault: false

  file:
    filename: /etc/traefik/config.yml
    watch: true

log:
  level: DEBUG
  format: common

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

config.yml

http:
  serversTransports:
      insecureSkipVerify: true
  routers:
    traefik:
      rule: "Host(`traefik.docker.localhost`)"
      service: "api@internal"
      tls:
        domains:
          - main: "docker.localhost"
            sans:
              - "*.docker.localhost"
          - main: "domain.local"
            sans:
              - "*.domain.local"

tls:
  certificates:
    - certFile: "/etc/certs/_wildcard.docker.localhost.pem"
      keyFile: "/etc/certs/_wildcard.docker.localhost-key.pem"

docker-compose.yml (example 2 services):

version: "3.9"
services:
  iam:
    build:
      context: .
      dockerfile: ./Dockerfile.iam
    restart: "always"
    environment:
      ENABLE_CORS: false
      ASPNETCORE_ENVIRONMENT: local
      ASPNETCORE_URLS: http://+:80;https://+:443
      ASPNETCORE_HTTPS_PORT: 443
      ASPNETCORE_Kestrel__Certificates__Default__Password: "redacted"
      ASPNETCORE_Kestrel__Certificates__Default__Path: "/https/aspnetapp.pfx"
    volumes:
      - ./dev/certs:/https:ro
    labels:
      - traefik.enable=true
      - traefik.http.routers.iam.tls=true
      - traefik.http.routers.iam.rule=Host(`iam.docker.localhost`)
      - traefik.http.routers.iam2.tls=false
      - traefik.http.routers.iam2.rule=Host(`iam.docker.localhost`)
    user: root
    depends_on:
      - db
    networks:
      net:
        aliases:
          - iam.docker.localhost
api:
    build:
      context: .
      dockerfile: ./Dockerfile.api
    restart: "always"
    environment:
      ASPNETCORE_ENVIRONMENT: local
      ASPNETCORE_URLS: http://+:80;https://+:443
      ASPNETCORE_HTTPS_PORT: 443
      ASPNETCORE_Kestrel__Certificates__Default__Password: "redacted"
      ASPNETCORE_Kestrel__Certificates__Default__Path: "/https/aspnetapp.pfx"
    volumes:
      - ./dev/certs:/https:ro
    labels:
      - traefik.enable=true
      - traefik.http.routers.api.tls=true
      - traefik.http.routers.api.rule=Host(`api.docker.localhost`)
      - traefik.http.routers.api2.tls=false
      - traefik.http.routers.api2.rule=Host(`api.docker.localhost`)
    depends_on:
      - db
    networks:
      net:
        aliases:
          - api.docker.localhost
traefik:
    image: "traefik:v2.9"
    restart: always
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik=true"
    ports:
      # HTTPS / SSL port
      - "80:80"
      - "443:443"
      # The Traefik Web UI port (enabled by api:insecure: true in traefik.yml)
      - "8080:8080"
    volumes:
      - ./dev/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./dev/traefik/config.yml:/etc/traefik/config.yml:ro
      - ./dev/certs:/etc/certs:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - net
networks:
  net:
    external: true
## Static configuration
serversTransport:
  insecureSkipVerify: true

This needs to go into static config: traefik.yml

Thanks, @bluepuma77 :slight_smile:

I did notice in the Traefik access logs that the requests still appear to be made over http vs https/tls -

2023-02-01 08:49:53 172.18.0.1 - - [01/Feb/2023:15:49:53 +0000] "OPTIONS /fhirservers/organization/864462be-f048-4921-8bcc-08db0342c32a HTTP/2.0" 204 0 "-" "-" 2547 "api@docker" "http://172.18.0.15:80" 8ms
2023-02-01 08:49:53 172.18.0.1 - - [01/Feb/2023:15:49:53 +0000] "GET /fhirservers/organization/864462be-f048-4921-8bcc-08db0342c32a HTTP/2.0" 500 0 "-" "-" 2548 "api@docker" "http://172.18.0.15:80" 52ms
2023-02-01 08:49:53 [15:49:53 ERR] Connection id "0HMO4CUOPJVMO", Request id "0HMO4CUOPJVMO:00000002": An unhandled exception was thrown by the application.
2023-02-01 08:49:53 System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://iam.docker.localhost/.well-known/openid-configuration'.
2023-02-01 08:49:53  ---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://iam.docker.localhost/.well-known/openid-configuration'.
2023-02-01 08:49:53  ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
2023-02-01 08:49:53  ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch, RemoteCertificateChainErrors

Do I need to add anything special to get the container to container configuration to use https properly?

Interesting, this is not in the service documentation, only in the reference:

  - "traefik.http.services.<name>.loadbalancer.server.scheme=https"

Enjoy your FHIR :fire:

2 Likes