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

So long ago I started studying the data of the solution, but I am so stupid that I have not found a solution to how to configure file docker-compose for a simple ASP.NET Core for traefik proxy.
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

Related

Multiple domains with Traefik

I am new to Traefik but trying to migrate from jwilder/nginx-proxy and letsencrypt-companion to Traefik.
I have setup Traefik with this config file:
traefik.yml
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: :443
api:
dashboard: true
insecure: true
certificatesResolvers:
le:
acme:
email: username#gmail.com
storage: acme.json
httpChallenge:
# used during the challenge
entryPoint: web
providers:
docker:
endpoint: unix:///var/run/docker.sock
exposedByDefault: false
docker-compose.yml
version: '3'
services:
traefik:
image: traefik:v2.2
restart: always
ports:
- 80:80
- 443:443
- 8080:8080
networks:
- web
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /data/disk1/traefik/traefik.yml:/traefik.yml
- /data/disk1/traefik/acme.json:/acme.json
container_name: traefik
When starting one container on domain #1
docker-compose.yml
version: "3"
services:
confluence:
container_name: confluence
image: atlassian/confluence-server:7.6.2
volumes:
- /data/disk1/atlassian/application-data/confluence:/var/atlassian/application-data/confluence
ports:
- "8090:8090"
external_links:
- postgres:postgres
environment:
- CATALINA_CONNECTOR_PROXYNAME=confluence.tld
- CATALINA_CONNECTOR_PROXYPORT=443
- CATALINA_CONNECTOR_SCHEME=https
- CATALINA_CONNECTOR_SECURE=true
- VIRTUAL_HOST=confluence.tld
- VIRTUAL_NETWORK=web
- VIRTUAL_PORT=8090
- LETSENCRYPT_EMAIL=user#tld
- LETSENCRYPT_HOST=confluence.tld
labels:
- traefik.enable=true
- traefik.http.routers.confluence.rule=Host(`confluence.tld`)
- traefik.http.routers.confluence.tls=true
- traefik.http.routers.confluence.tls.certresolver=le
- traefik.http.routers.confluence.service=confluence
- traefik.http.services.confluence.loadbalancer.server.port=8090
networks:
- web
restart: always
networks:
web:
external:
name: web
It works perfect.
NOTE: I have kept the environment variables for jwilder/nginx-proxy for the time being
When launching another container with different tld I can't get that working.
E.g.
docker-compose.yml
version: "3"
services:
confluence:
container_name: myapp
image: nginx:latest
volumes:
- /data/disk1/myapp/www/:/usr/share/nginx/html:ro
- /data/disk1/myapp/conf/nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "9999:80"
environment:
- VIRTUAL_HOST=www.tld2,tld2
- VIRTUAL_NETWORK=web
- VIRTUAL_PORT=9999
- LETSENCRYPT_EMAIL=user#tld2
- LETSENCRYPT_HOST=www.tld2,tld2
labels:
- traefik.enable=true
- traefik.http.routers.myapp.rule=Host(`tld2`) || Host(`www.tld2`)
- traefik.http.routers.myapp.tls=true
- traefik.http.routers.myapp.tls.certresolver=le
- traefik.http.routers.myapp.service=tld2
- traefik.http.services.myapp.loadbalancer.server.port=9999
networks:
- web
restart: always
networks:
web:
external:
name: web
It doesn't work but everything looks OK in Traefik dashboard.
Any ideas?
There is an error in the second docker-compose.yml:
You define the router named mypp to use a service named tld2:
traefik.http.routers.myapp.service=tld2
but your service is named myapp:
traefik.http.services.myapp.loadbalancer.server.port=9999
This should have generated an error in Traefik's log regarding an unresolvable service.
To fix this, configure your router myapp to use the service myapp:
traefik.http.routers.myapp.service=myapp

How to redirect to the dashboard from a URL?

I currently access the V2 dashboard through http://traefik.my.server:8080/dashboard/ (Traefik runs in a docker container and 8080 is exposed to the host).
I would like to change that so that the dashboard is available at http://traefik.my.server/dashboard
I tried to add the following labels to configure this behavior but I get a 404 when accessing http://traefik.my.server/dashboard
- traefik.http.routers.dashboard.rule=Host(`traefik.my.server:`) && Path(`/dashboard`)
- traefik.http.services.dashboard.loadbalancer.server.port=8080
- traefik.http.routers.dashboard.entryPoints=http
(the http entrypoint is port 80)
What is the correct way to set up such redirectio
Recommend read:
https://docs.traefik.io/v2.1/operations/dashboard/#secure-mode
https://blog.containo.us/traefik-2-0-docker-101-fc2893944b9d
https://github.com/containous/blog-posts/tree/master/2019_09_10-101_docker
FYI it's not redirection but a routing.
https://community.containo.us/t/how-to-redirect-to-the-dashboard-from-a-url/4082/2
Following up on #Idez help at https://community.containo.us/t/how-to-redirect-to-the-dashboard-from-a-url/4082, a working configuration is
The docker-compose file:
services:
traefik:
container_name: traefik
image: traefik
ports:
- 80:80
- 443:443
restart: unless-stopped
volumes:
- /etc/docker/container-data/traefik:/etc/traefik
- /var/run/docker.sock:/var/run/docker.sock
- /etc/localtime:/etc/localtime:ro
labels:
- traefik.http.routers.api.rule=Host(`traefik.mydomain.org`)
- traefik.http.routers.api.service=api#internal
- traefik.http.routers.api.middlewares=lan
- traefik.http.middlewares.lan.ipwhitelist.sourcerange=192.168.10.0/24, 192.168.20.0/24
- traefik.enable=true
version: "3"
Configuration file
global:
sendAnonymousUsage: true
entryPoints:
http:
address: ":80"
https:
address: ":443"
api:
dashboard: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
defaultRule: "Host(`{{ index .Labels \"com.docker.compose.service\" }}.mydomain.org`)"
log:
level: INFO
#level: DEBUG
certificatesResolvers:
le:
acme:
email: le#mydomain.org
storage: /etc/traefik/acme.json
tlsChallenge: {}
#caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"

How to use Traefik and Envoy in the same project to handle grpc-web?

I've got a service up and running on traefik with LetsEncrypt at grpc.mydomain.com. However, traefik doesn't support routing grpc-web request due to some issue with CORS (https://github.com/containous/traefik/issues/4210). Envoy appears to be an alternative to traefik which works with grpc-web, but I don't want to go about reconfiguring everything.
If I put envoy at envoy.mydomain.com then it actually hits traefik first and traefik can't route the grpc-web requests to envoy. So this doesn't work.
If I put envoy outside of traefik (mydomain.com:9091) then envoy doesn't have the TLS support that traefik has.
Do I need to switch everything to envoy? Is there an alternative I haven't considered? Any guidance welcome :)
Current Traefik Setup:
traefik:
image: traefik:v2.0.0
container_name: traefik
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.grpc.address=:8090
- --providers.docker
- --api
- --serversTransport.rootCAs=/certs/grpc.cert
# Lets Encrypt Resolvers
- --certificatesresolvers.leresolver.acme.email=${EMAIL}
- --certificatesresolvers.leresolver.acme.storage=/etc/acme/cert.json
- --certificatesresolvers.leresolver.acme.tlschallenge=${TLS_CHALLENGE}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /etc/acme/:/etc/acme/
- ./secrets/grpc.cert:/certs/grpc.cert
# Dynamic Configuration
labels:
# Dashboard
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik.service=api#internal"
- "traefik.http.routers.traefik.tls.certresolver=leresolver"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.middlewares=authtraefik"
# https://docs.traefik.io/middlewares/basicauth/
# password generated from `echo $(htpasswd -nb admin $PASSWORD) | sed -e s/\\$/\\$\\$/g`
- "traefik.http.middlewares.authtraefik.basicauth.users=admin:$$apr1$$6VzI3S0N$$29FC82dYEbjFN9tPSfWLX1"
# global redirect to https
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
# middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
ports:
- 80:80
- 443:443
- 8090:8090
networks:
- internal
- proxied
grpc_server:
image: ${GRPC_IMAGE}
container_name: grpc_server
volumes:
- /tmp/keyset.json:/tmp/keyset.json
- ./secrets/:/secrets/
working_dir: /app/__main__/
labels:
- "traefik.http.routers.combined_server.rule=Host(`grpc.${DOMAIN}`)"
- "traefik.http.routers.combined_server.entrypoints=grpc"
- "traefik.http.routers.combined_server.tls=true"
- "traefik.http.routers.combined_server.tls.certresolver=leresolver"
# http
- "traefik.http.services.grpc-svc.loadbalancer.server.scheme=h2c"
- "traefik.http.services.grpc-svc.loadbalancer.server.port=8090"
expose:
- 8090
networks:
- internal
- proxied
I also tried setting these to fix the CORS error but got nowhere.
- "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,PUT,DELETE,POST,OPTIONS"
- "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout"
- "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"
- "traefik.http.middlewares.testheader.headers.addvaryheader=true"
- "traefik.http.middlewares.testheader.headers.alloworigin=*"
A way to approach this issue is by using 2 different URLs that are both being handled by traefik at first. One URL is being used for "direct grpc" (grpc.mydomain.com), the other one for grpc-web (let's call it grpc-web.mydomain.com). Traefik does TLS termination for both.
The grpc.mydomain.com traffic is directly passed to the container running the grpc_server. The grpc-web.mydomain.com traffic is passed to envoy which acts as a grpc-web-proxy and then passes the traffic to the grpc_server.
So as you are using docker-compose, you would need to add an envoy service to your docker-compose.yml:
---
version: '3'
services:
traefik:
# traefik configuration from your question
# ...
grpc-server:
# grpc_server configuration from your question
# ...
envoy:
image: envoyproxy/envoy:v1.14.1
restart: unless-stopped
volumes:
- ./envoy.yaml:/etc/envoy/envoy.yaml
labels:
- traefik.enable=true
- traefik.http.routers.envoy.rule=Host(`grpc-web.mydomain.com`)
- traefik.http.services.envoy.loadbalancer.server.port=8080
- traefik.http.routers.envoy.tls=true
- traefik.http.routers.envoy.tls.certresolver=leresolver
The envoy.yaml configuration (mounted in the volumes section above) looks like this:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: grpc_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.grpc_web
- name: envoy.cors
- name: envoy.router
clusters:
- name: grpc_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
hosts: [{ socket_address: { address: grpc-server, port_value: 8090 }}]
This is a pretty basic grpc-web config for envoy. The important part to notice is that we set address: grpc-server, port_value: 8090 in the configuration of the "grpc_service" cluster configuration to the service name from the docker-compose.yml and to the port your grpc-server is listening on. Please note I renamed your service from grpc_server to grpc-server as the underscore is not a valid charater in hostnames.
On the client side, use:
"grpc-web.mydomain.com" in your javascript (grpc-web) code.
"grpc.mydomain.com" when writing a client in another language (like golang for example).
I created a working example, which can be found under: https://github.com/rbicker/greeter
If you want to get rid of deprecated warnings in envoy, you can update envoy.yaml from this answer with those three changes:
replace:
- name: envoy.http_connection_manager
config:
with:
- name: envoy.filters.network.http_connection_manager
typed_config:
"#type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
replace
- name: envoy.grpc_web
- name: envoy.cors
- name: envoy.router
with
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.cors
- name: envoy.filters.http.router
replace
hosts: [{ socket_address: { address: grpc-server, port_value: 8090 }}]
with
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: grpc-server
port_value: 8090

Is there a way to import a company root CA in traefik?

I have a docker swarm with traefik running in it and I want to be able to serve Grafana in https which is currently in http.
I've tried with the following traefik compose configuration:
version: "3.6"
services:
traefik:
image: traefik
command:
- --defaultentrypoints=http,https
- --docker
- --docker.swarmMode
- --docker.exposedByDefault=false
- --docker.domain=sdb.it
- --docker.watch
- --entryPoints=Name:http Address::80
- --entryPoints=Name:https Address::443 clientCA:/etc/ssl/certs/rootca.crt TLS:/etc/ssl/certs/sonarqube.crt,/etc/ssl/certs/sonarqube.key;/etc/ssl/certs/sdbit-grafana.pem,/etc/ssl/certs/sdbit-grafana.key
- --rootcas=/etc/ssl/certs/rootca.crt
- --insecureskipverify
- --logLevel=DEBUG
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- 80:80
- 443:443
networks:
- traefik
secrets:
- source: sdbit-sonarqube-docker.sdb.it.crt
target: /etc/ssl/certs/sonarqube.crt
mode: 644
- source: sdbit-sonarqube-docker.sdb.it.key
target: /etc/ssl/certs/sonarqube.key
mode: 644
- source: sdbit-grafana.sdb.it.pem
target: /etc/ssl/certs/sdbit-grafana.pem
mode: 644
- source: sdbit-grafana.sdb.it.key
target: /etc/ssl/certs/sdbit-grafana.key
mode: 644
- source: sdb-root-ca.crt
target: /etc/ssl/certs/rootca.crt
mode: 644
deploy:
placement:
constraints:
- node.role == manager
volumes:
certificates:
external: true
networks:
traefik:
external: true
secrets:
sdbit-sonarqube-docker.sdb.it.crt:
external: true
sdbit-sonarqube-docker.sdb.it.key:
external: true
sdbit-grafana.sdb.it.pem:
external: true
sdbit-grafana.sdb.it.key:
external: true
sdb-root-ca.crt:
external: true
and these labels on grafana:
grafana:
image: maven-repo.sdb.it:18080/grafana/grafana:6.0.1
user: "104"
depends_on:
- prometheus
ports:
- 3000:3000
volumes:
- grafana_data:/var/lib/grafana
configs:
- source: grafana_custom_ldap
target: /etc/grafana/custom_ldap.toml
environment:
.....
labels:
traefik.docker.network: traefik
traefik.enable: "true"
traefik.frontend.rule: Host:sdbit-grafana.sdb.it
traefik.frontend.redirect.entryPoint: https
traefik.domain: sdb.it
traefik.port: 3000
networks:
- back-tier
- front-tier
- traefik
restart: always
deploy:
placement:
constraints:
- node.role==worker
When traefik starts up it shows no errors in logs, but as soon as I try to point my browser to sdbit-grafana.sdb.it in traefik logs I can see:
time="2019-03-27T14:11:35Z" level=debug msg="http2: server: error reading preface from client 10.255.0.2:45240: remote error: tls: unknown certificate authority",
The certificate I'm trying to make work is taken from a company CA, and the pem file contains the root certificate.
As you can see from the compose file I tried to use the rootcas, the clientCA in https endpoint and also the insecureskipverify.
Any ideas?
I don't know where you found the lines defining entrypoints in traefik (- --entryPoints=Name:https Address::443 clientCA:/etc/ssl/certs/rootca.crt) but the entrypoints documentation says otherwise. I personally use
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.metrics.address=:8080
- --entrypoints.web.http.redirections.entrypoint.to=:443
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.web.http.redirections.entrypoint.permanent=true
Concerning the certificates, as per this doc, there should be a dynamic configuration file, I set it up using a volume and the following :
- --providers.file.directory=/etc/traefik/conf.d/
- --providers.file.watch=true
and adding a tls.yml file inside this conf.d directory with the following content :
tls:
certificates:
- certFile: /path/to/domain.cert
keyFile: /path/to/domain.key
Your use case could also use the power of the default cert definition :
tls:
stores:
default:
defaultCertificate:
certFile: path/to/cert.crt
keyFile: path/to/cert.key
I also suggest you try lets encrypt certificates with auto renewal for it is simpler and at least as secure. As a side note I suggest you hide the domain in your question using http://example.com/ Hopes this help

Traefik not set backend/frontend in swarm mode

i would like use traefik in a cluster swarm, following this guide https://docs.traefik.io/user-guide/swarm-mode/#deploy-traefik i've write this stack file:
traefik:
image: traefik:alpine
deploy:
placement:
constraints:
- node.role == manager
command: --api --docker --docker.watch --docker.swarmMode
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "80:80"
- "8080:8080"
labels:
- "traefik.enable=false"
backend:
image: registry.example.com/backend
labels:
- "traefik.backend=backend"
- "traefik.backend.buffering.maxRequestBodyBytes=2147483648"
- "traefik.backend.loadbalancer.sticky=true"
- "traefik.frontend.rule=Host:backend.localhost"
- "traefik.frontend.passHostHeader=true"
- "traefik.port=80"
api:
image: registry.example.com/api
labels:
- "traefik.backend=api"
- "traefik.backend.buffering.maxRequestBodyBytes=2147483648"
- "traefik.backend.loadbalancer.sticky=true"
- "traefik.frontend.rule=Host:api.localhost"
- "traefik.frontend.passHostHeader=true"
- "traefik.port=80"
Traefik start but nothing is configured, I can not understand where is the error.
You forgot the network part from the example.
You miss both network related labels and the networks itslelf:
deploy:
labels:
- "traefik.docker.network=traefik-network" # for both api and backend
...
networks:
- "traefik-network" # for traefik, api and backend
...
networks:
traefik-network:{} # you can also make it external
EDIT :
also, on swarm, the labels should be set under the "deploy" section of your service, and not ont the service itself.