Traefik v2 http 404 redirect to external - docker

For some time now I can't wrap my head around seemingly simple problem:
How to catch unknown routers and redirect it to external domain without using another reverse proxy (eg nginx as described here)?
traefik:
...
labels:
- "traefik.enable=true"
- "traefik.http.routers.http_catchall.rule=HostRegexp(`{any:.+}`)"
- "traefik.http.routers.http_catchall.priority=1"
- "traefik.http.routers.http_catchall.entrypoints=unsecure"
- "traefik.http.routers.http_catchall.middlewares=error-catch,https-redirect"
- "traefik.http.middlewares.error-catch.errors.status=404"
- "traefik.http.middlewares.error-catch.errors.service=error-redirect"
- "traefik.http.middlewares.error-catch.errors.query=/"
- "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true"
# now how to use "error-redirect" service to forward to eg https://google.com
Any idea?

You can add a file provider in which you define a service for an external url.
http:
services:
google:
loadBalancer:
servers:
- url: http://google.com
and assign that service in the middleware like so
- "traefik.http.middlewares.error-catch.errors.service=google#file"

Related

Traefik 2: access to .well-known acme folder, What do you think?

I had problem with my mailserver is it was not working properly when i added mailbox to Outlook. It warned me that i use wrong certificate, on closer inspection it showed default email docker creator certificate. Even though webmail is protected with SSL from Traefik.
After researching I manage to come up with this, it is combination of ones guy docker compose, cannot find the link for his post. And my previous attempt to host acme challenge on my flask website, what was overwritten by default with Nginx Proxy manager, so I abandon it.
But now while working with Traefik, what provides much more flexibility i was able to do it:
This is one page on my flask website, what returns files from within the .well-known folder, which is mapped in each docker container what needs access to lets encrypt certification process, behind reverse proxy.
#app.route('/.well-known/acme-challenge/<acmechalleng>')
def acme(acmechalleng):
try:
# acme_folder is file path to folder where challenges are stored
# for example: acmechall_folder = os.path.abspath('acmefiles/')
acme_folder=config.acmechall_folder
extr = {}
# Sets up ignored file names what will not be showed
ignore_files='.paths.json'
try:
items = json.load(open(os.path.join(acme_folder, '.paths.json')))
except Exception:
items = ""
for root, dirs, files in os.walk(acme_folder):
for f in files:
# this filters files we do not want to show ie: paths file
if f not in ignore_files:
full_path = os.path.join(root, f)
path = full_path.split(acme_folder,1)[1]
path = path.replace("\\", "/")
split_path = path.split('/')
extr.update({path[1:]: 0})
if items != extr:
with open(os.path.join(acme_folder, '.paths.json'), 'w', encoding='utf-8') as f:
json.dump(extr, f, ensure_ascii=False, indent=4)
# Only files what are in .pahts.json will be allowed to be read
items = json.load(open(os.path.join(acme_folder, '.paths.json')))
existing = []
for key, arr in items.items():
existing.append(key)
if acmechalleng in existing:
with open(os.path.join(acme_folder, acmechalleng),"rb") as f:
content = f.readlines()
return Response(content)
else:
return render_template('404.html', **_auto_values), 404
except Exception as err:
return render_template('404.html', **_auto_values), 404
Poste.io mail server Docker File, with access to .well-known challenges for Letsencrypt
version: '3'
networks:
traefikauth_net:
external: true
services:
mailserver:
image: analogic/poste.io
container_name: mailserver
hostname: mail.mydomain.com
networks:
- traefikauth_net
restart: unless-stopped
ports:
- "25:25"
- "587:587"
- "993:993"
environment:
- HOSTNAME=poste.mydomain.com
- TZ=Europe/London
- LETSENCRYPT_EMAIL=admin#mydomain.com
- LETSENCRYPT_HOST=mydomain.com
- VIRTUAL_HOST=poste.mydomain.com
- HTTPS=OFF
- DISABLE_CLAMAV=TRUE
- DISABLE_RSPAMD=TRUE
volumes:
- /opt/traefik/.well-known:/opt/www/.well-known/acme-challenge
- /opt/mailserver:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.poste-letsencrypt.rule=HostRegexp(`mydomain.com`,`{subdomain:[a-z]*}.mydomain.com`) && PathPrefix(`/.well-known/`)"
- "traefik.http.routers.poste-letsencrypt.entrypoints=http"
- "traefik.http.routers.poste-letsencrypt.service=mail"
- "traefik.http.services.poste-letsencrypt.loadbalancer.server.port=80"
- "traefik.http.routers.mail.rule=Host(`poste.mydomain.com`)"
- "traefik.http.routers.mail.entrypoints=https"
- "traefik.http.routers.mail.tls.certresolver=cloudflare"
- "traefik.http.routers.mail.service=mail"
- "traefik.http.services.mail.loadbalancer.server.port=80"
The main website, on "mydomain.com" needs also Traefik labels:
volumes:
- /opt/traefik/.well-known:/var/www/wellknown
labels:
- "traefik.enable=true"
- "traefik.http.routers.flask-letsencrypt.entrypoints=http"
- "traefik.http.routers.flask-letsencrypt.rule=HostRegexp(`mydomain.com`) && PathPrefix(`/.well-known/`)"
- "traefik.http.services.flask-letsencrypt.loadbalancer.server.port=80"
- "traefik.http.routers.flask-letsencrypt.service=myflask"
- "traefik.http.routers.myflask.entrypoints=https"
- "traefik.http.routers.myflask.rule=Host(`mydomain.com`)"
- "traefik.http.routers.myflask.service=myflask"
- "traefik.http.routers.myflask.tls=true"
- "traefik.http.routers.myflask.tls.certresolver=cloudflare"
- "traefik.http.services.myflask.loadbalancer.server.port=80"
I also have normal CertResolver for all the other domains what is in main Traefik file as follow traefik.yml:
certificatesResolvers:
cloudflare:
acme:
email: admin#mydomain.com
storage: /letsencrypt/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
entryPoints:
http:
address: ":80"
https:
address: ":443"
Traefik 2 docker-compose:
version: '3'
services:
traefik:
image: traefik
restart: always
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock
- /opt/traefik/traefik.yml:/traefik.yml:ro
- /opt/traefik/conf:/additionalsettings
- /opt/traefik/folderacme:/letsencrypt
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.api.rule=Host(`traefik.mydomain.com`)'
- 'traefik.http.routers.api.entrypoints=https'
- 'traefik.http.routers.api.service=api#internal'
- 'traefik.http.routers.api.tls=true'
- 'traefik.http.routers.api.middlewares=authelia#docker'
- "traefik.http.routers.api.tls.certresolver=cloudflare"
- "traefik.http.routers.api.tls.domains[0].main=mydomain.com"
- "traefik.http.routers.api.tls.domains[0].sans=*.mydomain.com"
- "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://logmein.mydomain.com/"
- "traefik.http.middlewares.authelia.forwardauth.trustforwardheader=true"
- 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email'
- 'traefik.http.middlewares.authelia-basic.forwardauth.address=http://authelia:9091/api/verify?auth=basic'
- 'traefik.http.middlewares.authelia-basic.forwardauth.trustForwardHeader=true'
- 'traefik.http.middlewares.authelia-basic.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email'
# global redirect to https
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=http"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
# middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
environment:
- CF_API_EMAIL=<cloudflare api email>
- CF_API_KEY=<cloudflare api key for certresolver>
ports:
- 80:80
- 443:443
command:
- '--api'
- '--providers.docker=true'
- '--providers.docker.exposedByDefault=false'
- '--entrypoints.http=true'
- '--entrypoints.http.address=:80'
- '--entrypoints.http.http.redirections.entrypoint.to=https'
- '--entrypoints.http.http.redirections.entrypoint.scheme=https'
- '--entrypoints.https=true'
- '--entrypoints.https.address=:443'
What do you think? I believe that python code could be much smaller, especially that part what stores the path in Json but i use that from my other project, and there I needed more then path to the file. This way I believe nobody should be able access other files, only those in ACME folder.

Traefik custom error middleware for HTTP status 502 doesn’t work

I would like to serve custom error pages for common HTTP error codes. I was following this tutorial. For this purpose, I created the following docker-compose.yml file to test the functionality. It consists of:
errorPageHandler which is a nginx server which is able to return static HTML pages (404.html and 502.html).
whoami1 which routes the request to port 80 of traefik/whoami image
whoami2 which routes the request to non-existent port 81 of traefik/whoami image which results in 502 - Bad Gateway
version: "3.7"
services:
errorPageHandler:
image: "nginx:latest"
networks:
- traefik-net
volumes:
- "./ErrorPages:/usr/share/nginx/ErrorPages"
- "./default.conf:/etc/nginx/conf.d/default.conf"
deploy:
replicas: 1
labels:
# enable Traefik for this service
- "traefik.enable=true"
- "traefik.docker.network=traefik-net"
# router (catches all requests with lowest possible priority)
- "traefik.http.routers.error-router.rule=HostRegexp(`{catchall:.*}`)"
- "traefik.http.routers.error-router.priority=1"
- "traefik.http.routers.error-router.middlewares=error-pages-middleware"
# middleware
- "traefik.http.middlewares.error-pages-middleware.errors.status=400-599"
- "traefik.http.middlewares.error-pages-middleware.errors.service=error-pages-service"
- "traefik.http.middlewares.error-pages-middleware.errors.query=/{status}.html"
# service
- "traefik.http.services.error-pages-service.loadbalancer.server.port=80"
whoami1:
image: "traefik/whoami"
networks:
- traefik-net
deploy:
replicas: 1
labels:
# enable Traefik for this service
- "traefik.enable=true"
- "traefik.docker.network=traefik-net"
# router
- "traefik.http.routers.whoami1.rule=HostRegexp(`whoami1.local`)"
- "traefik.http.routers.whoami1.service=whoami1"
# service
- "traefik.http.services.whoami1.loadbalancer.server.port=80"
- "traefik.http.services.whoami1.loadbalancer.server.scheme=http"
whoami2:
image: "traefik/whoami"
networks:
- traefik-net
deploy:
replicas: 1
labels:
# enable Traefik for this service
- "traefik.enable=true"
- "traefik.docker.network=traefik-net"
# router
- "traefik.http.routers.whoami2.rule=HostRegexp(`whoami2.local`)"
- "traefik.http.routers.whoami2.service=whoami2"
# service
- "traefik.http.services.whoami2.loadbalancer.server.port=81" # purposely wrong port
- "traefik.http.services.whoami2.loadbalancer.server.scheme=http"
networks:
traefik-net:
external: true
name: traefik-net
Folder ErrorPages contains two static HTML files, 404.html and 502.html. Content of default.conf is:
server {
listen 80;
server_name localhost;
error_page 404 /404.html;
error_page 502 /502.html;
location / {
root /usr/share/nginx/ErrorPages;
internal;
}
}
I added the following entries to my hosts file (172.15.16.17 is IP of the server where Traefik and all of the mentioned services are deployed):
172.15.16.17 error404.local
172.15.16.17 whoami1.local
172.15.16.17 whoami2.local
My observations:
When I visit http://error404.local, Traefik routes the request to nginx and 404.html is returned. This is expected behavior because http://error404.local doesn't match any of the routes defined in Traefik.
When I visit http://whoami1.local, Traefik routes request to whoami1 service and information about container is displayed on the page (expected behavior).
When I visit http://whoami2.local, Traefik doesn't route request to nginx service, but it displays its default Bad Gateway page. Why doesn't it route the request to the nginx?
The traefik routers (whoami1 and whoami2) needs to use the error middleware that you defined
https://doc.traefik.io/traefik/middlewares/http/errorpages/
Traefik error middleware docs
So add the following labels to their respective containers
- "traefik.http.whoami1.middlewares=error-pages-middleware"
- "traefik.http.whoami2.middlewares=error-pages-middleware"
the Traefik dashboard will show that the routes are using the middleware (refer image) One of my routes from my traefik dashboard
Another option would be to add the middleware to the entrypoint so that all routes use the error middleware (Add this to traefik container compose)
command:
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http.middlewares=error-pages-middleware#docker"

Keycloak returns 'Invalid parameter: redirect_uri'

[Edit-1] Add scope in oauth2 configuration, add grafana service, remove oauth-keycloak-signin. The configurations is referred from this link
[UPDATE] I am able to log in at Keycloak page but it couldn't route me to the Grafana service. Looked at the OAuth2 logs, something weird, the access token that generated by Keycloak was validated of Github, not for Keycloak :))) -> This was caused by missing oauth validate_url config.
Solution:
- 'traefik.http.middlewares.oauth-keycloak.forwardauth.address=http://oauth-keycloak:4185/oauth2/auth'
Log of OAuth2 Proxy
paddy_oauth-keycloak.1.nd9v50gfv9kc#staging | 123.28.110.207 - 411d7575-fb97-42ca-87ed-d57cad683b31 - - [2021/09/30 02:04:53] grafana.my-domain.com GET - "/oauth2/start?rd=https%3A%2F%2Fgrafana.my-domain.com%2F" HTTP/1.1 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36" 302 419 0.000
paddy_oauth-keycloak.1.nd9v50gfv9kc#staging | [2021/09/30 02:05:00] [internal_util.go:74] token validation request failed: status 400 - {"error":"invalid_request","error_description":"Token not provided"}
paddy_oauth-keycloak.1.nd9v50gfv9kc#staging | [2021/09/30 02:05:00] [internal_util.go:69] 400 GET https://keycloak.my-domain.com/auth/realms/staging/protocol/openid-connect/userinfo?access_token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJYa1NjbzduRjlaTUpiWDRXVU5mTlhJS2FwOG9ZMHZ1THVZZU1SUk9EQ1J3In0.eyJleHAiOjE2MzI5Njc4MDAsImlhdCI6MTYzMjk2NzUwMCwiYXV0aF90aW1lIjoxNjMyOTY3NDk5LCJqdGkiOiI4NGJjZjdiNC0yN2YzLTQ4NDktYjUzNi05OTNkNTczNzA5OWYiLCJpc3MiOiJodHRwczovL2tleWNsb2FrLnN0YWdpbmcucHJlY2lzaW9uYWcub3JnL2F1dGgvcmVhbG1zL3N0YWdpbmciLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNzk1NjE1YWUtN2VkNi00MWI3LWE5YWUtMjBkZmZhMTc1NjBhIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiYXV0aGVudGljYXRpb24iLCJzZXNzaW9uX3N0YXRlIjoiZTVjM2FkMDMtNzhmNi00ZmE4LThhOTgtZTdkYjk1YjZiNmEzIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsImRlZmF1bHQtcm9sZXMtc3RhZ2luZyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW5... {"error":"invalid_request","error_description":"Token not provided"}
paddy_oauth-keycloak.1.nd9v50gfv9kc#staging | 123.28.110.207 - 39bea317-002b-4366-858c-01aa6f6901b6 - dathuynh#my-domain.com [2021/09/30 02:05:00] [AuthSuccess] Authenticated via OAuth2: Session{email:dathuynh#my-domain.com user: PreferredUsername: token:true groups:[/pader]}
I am setting up keycloak and oauth2 for authentication in my system. The system is running in docker swarm mode and using traefik reverse-proxy. I followed this guide to set up the oauth2 container: https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider/#keycloak-auth-provider
I created a new client in the 'development' realm, with the Valid Redirect URL is https://oauth-keycloak.my-domain.com/oauth2/callback (it is the Oauth URL), used traefik forward auth to route the request to the Keycloak if it is unauthenticated.
I got Invalid parameter: redirect_uri for 2 case:
I access Grafana and the request was routed to Keycloak
I try to access this link in the OAuth config https://oauth-keycloak.my-domain.com/auth/realms/development/protocol/openid-connect/auth.
I have searched and try some suggestions but they did not work for me. Hope you guys can help. I have really appreciated it.
Here is my docker swarm configuration:
keycloak:
image: quay.io/keycloak/keycloak:15.0.2
deploy:
labels:
- "traefik.enable=true"
- "traefik.http.routers.keycloak.rule=Host(`keycloak.my-domain.com`)"
- "traefik.http.routers.keycloak.entrypoints=websecure"
- "traefik.http.routers.keycloak.tls=true"
- "traefik.http.routers.keycloak.tls.certresolver=leresolver"
# Set up service
- "traefik.http.routers.keycloak.service=keycloak-svc"
- "traefik.http.services.keycloak-svc.loadbalancer.server.port=8080"
environment:
- "DB_VENDOR=POSTGRES"
- "DB_ADDR=postgis"
- "DB_DATABASE=${POSTGRES_DB}"
- "DB_USER=${POSTGRES_USER}"
- "DB_PASSWORD=${POSTGRES_PASSWORD}"
- "KEYCLOAK_USER="
- "KEYCLOAK_PASSWORD="
- "PROXY_ADDRESS_FORWARDING=true"
- "KEYCLOAK_LOGLEVEL=DEBUG" # DEBUG, ERROR, INFO
grafana:
image: grafana/grafana
deploy:
resources:
limits:
memory: 256M
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.my-domain.com`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls=true"
- "traefik.http.routers.grafana.tls.certresolver=leresolver"
# Basic HTTP authentication
- "traefik.http.routers.grafana.middlewares=oauth-keycloak"
# Set up service
- "traefik.http.services.grafana-svc.loadbalancer.server.port=3000"
- "traefik.http.routers.grafana.service=grafana-svc"
environment:
- GF_SECURITY_ADMIN_USER=my-username
- GF_SECURITY_ADMIN_PASSWORD=my-pasword
- GF_USERS_ALLOW_SIGN_UP=true
volumes:
- "/home/app/grafana:/var/lib/grafana"
oauth-keycloak:
image: quay.io/oauth2-proxy/oauth2-proxy
deploy:
labels:
- "traefik.enable=true"
- "traefik.http.routers.oauth-keycloak.rule=Host(`oauth-keycloak.my-domain.com`) || PathPrefix(`/oauth2`)"
- "traefik.http.routers.oauth-keycloak.entrypoints=websecure"
- "traefik.http.routers.oauth-keycloak.tls=true"
- "traefik.http.routers.oauth-keycloak.tls.certresolver=leresolver"
# Set up service
- "traefik.http.routers.oauth-keycloak.service=oauth-keycloak-svc"
- "traefik.http.services.oauth-keycloak-svc.loadbalancer.server.port=4185"
# Set up middlewares
- 'traefik.http.middlewares.oauth-keycloak.forwardauth.address=http://oauth-keycloak:4185'
- 'traefik.http.middlewares.oauth-keycloak.forwardauth.trustForwardHeader=true'
- 'traefik.http.middlewares.oauth-keycloak.forwardauth.authResponseHeaders=X-Forwarded-User'
# - "traefik.http.middlewares.oauth-keycloak-signin.errors.service=oauth-keycloak-svc"
# - "traefik.http.middlewares.oauth-keycloak-signin.errors.status=401-403"
# - "traefik.http.middlewares.oauth-keycloak-signin.errors.query=/oauth2/sign_in"
environment:
OAUTH2_PROXY_CLIENT_ID: 'development'
OAUTH2_PROXY_CLIENT_SECRET: ''
OAUTH2_PROXY_PROVIDER: 'keycloak'
OAUTH2_PROXY_SCOPE: 'profile email address phone'
OAUTH2_PROXY_LOGIN_URL: 'https://keycloak.my-domain.com/auth/realms/development/protocol/openid-connect/auth'
OAUTH2_PROXY_REDEEM_URL: 'https://keycloak.my-domain.com/auth/realms/development/protocol/openid-connect/token'
OAUTH2_PROXY_PROFILE_URL: 'https://keycloak.my-domain.com/auth/realms/development/protocol/openid-connect/userinfo'
OAUTH2_PROXY_VALIDATE_URL: 'https://keycloak.my-domain.com/auth/realms/development/protocol/openid-connect/userinfo'
OAUTH2_PROXY_COOKIE_DOMAINS: 'my-domain.com'
OAUTH2_PROXY_HTTP_ADDRESS: '0.0.0.0:4185'
OAUTH2_PROXY_COOKIE_REFRESH: '1h'
OAUTH2_PROXY_COOKIE_SECURE: 'false'
OAUTH2_PROXY_COOKIE_SECRET: '0Y18nYVtNLzKQroYQpi0jw=='
OAUTH2_PROXY_EMAIL_DOMAINS: 'my-domain.com'
OAUTH2_PROXY_REVERSE_PROXY: 'true'
OAUTH2_PROXY_WHITELIST_DOMAINS: 'my-domain.com'
OAUTH2_PROXY_SHOW_DEBUG_ON_ERROR: 'true'
You configured a valid redirect URI for https://oauth-keycloak.my-domain.com/oauth2/callback as you said. In case of accessing grafana your redirect uri should be https://grafana.my-domain.com/oauth2/callback instead. You will need to add this to the list of valid redirect URIs as well.

Use traefik middleware globally

i am trying to declare https redirect inside the traefik.yml file. For now i tried to add those rules inside the traefik service in docker-compose.yml. That worked like a charm. Although i'd prefer to configure this global and middleware redirect inside the traefik.yml file and then just reference it in the traefik service on docker-compose.yml.
What i had before
version: '3'
networks:
web:
external: true
services:
traefik:
image: traefik:v2.1
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./.traefik/traefik.yml:/traefik.yml
- ./.traefik/acme.json:/acme.json
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`$HOSTNAME`)"
- "traefik.http.routers.traefik.service=api#internal"
- "traefik.http.routers.traefik.tls.certresolver=le"
- "traefik.http.routers.traefik.entrypoints=https"
# Global redirect to https
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=http"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
# Middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
That worked easily and redirected all other domains from http to https.
What i want now
I want to declare those redirects inside the traefik.yml.
So far i have done this.
api: {}
entryPoints:
http:
address: ":80"
https:
address: ":443"
log:
level: DEBUG
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: web
http:
# Global redirect to https
routers:
http-catchall:
rule: hostregexp(`{host:.+}`)"
entrypoints:
http
middlewares:
- redirect-to-https
# Middleware redirect
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
certificatesResolvers:
le:
acme:
email: john#doe.com
storage: acme.json
# Activate for Development: Certificate will not be valid. It's only for testing if it can be obtained.
#caServer: https://acme-staging-v02.api.letsencrypt.org/directory
httpChallenge:
entryPoint: http
As you can see i declared the http settings.
My question is now how can i reference those settings into my traefik service?
I tried it with
- "traefik.http.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https"
- "traefik.http.middlewares.traefik=redirect-to-https#file"
None of them work. Some show the middleware in the dashboard but it is not linked to any settings.
Did anyone find a solution to this? I can't get out anything from the docs about this. I think it must be linked somehow to the #file.
Thank you
#file means that the middleware was defined in the file provider.
You can add a file provider like this in traefik.yml.
providers:
file:
directory: "/path/to/dynamic/conf"
Create a file in that directory with the middleware.
http:
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
You can now reference redirect-to-https#file in your labels.
- "traefik.http.middlewares.traefik=redirect-to-https#file"
NOTE: Some of your configuration in traefik.yml might need to be moved to your new yml file. I am new to Traefik and have not full knownlegde of why yet.
See the following sections in documentation:
https://docs.traefik.io/middlewares/overview/#provider-namespace
https://docs.traefik.io/providers/file/
In fact, you don't need to set this middleware to traefik in labels block. If you have such configuration in your traefik.yml:
http:
routers:
http-catchall:
rule: hostregexp(`{host:.+}`)
entrypoints:
- http
middlewares:
- redirect-to-https
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
permanent: false
It means - all traffic which came to entrypoint http should use middleware redirect-to-https and be redirected to another entrypoint: https. This configuration is globally.
So, you just have to set your container to https entrypoint (as you did, in your example)
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`traefik.mydomain.ua`)"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=letsEncrypt"
- "traefik.http.routers.traefik.service=api#internal"

Adding Traefik StripPrefix middleware to docker-compose labels results in 504

I have developed several docker-ized full-stack web applications that I am trying to route requests to using Traefik. I want to take advantage of the dynamic configuration via docker-compose labels. I would like to apply the stripPrefix middleware option so I can use the same application routing as if each app were served at the root. However, once these rules are applied it results in a 504 Gateway Timeout response.
Here's my set up:
Traefik 2.0.1
Docker 19.03.2, Compose 1.24.1
NGINX:latest images
A global docker network on which the Traefik container runs
Multiple multi-container applications, each of which includes an NGINX web server
All applications have their own local networks and the NGINX containers are also on the global network.
Each application is configured to be listening at /
Here is the docker-compose.yml definition for the offending NGINX container:
nginx:
image: nginx:latest
container_name: "mps_nginx"
volumes:
- ./nginx/confs/nginx.conf:/etc/nginx/default.conf
- ./static:/www/static
restart: "always"
labels:
- traefik.http.routers.mps.rule=Host(`localhost`) && PathPrefix(`/mps`)
- traefik.http.middlewares.strip-mps.stripprefix.prefixes=/mps
- traefik.http.routers.mps.middlewares=strip-mps#docker
networks:
- default
- mps
The aggravating part is, when I comment out the middlewares labels, it runs just fine but cannot find a matching URL pattern.
Prior to this I tested my approach using the whoami container that is defined in the Traefik Quickstart Tutorial:
# Test service to make sure our local docker-compose network functions
whoami:
image: containous/whoami
labels:
- traefik.http.routers.whoami.rule=Host(`localhost`) && PathPrefix(`/whoami`)
- traefik.http.middlewares.strip-who.stripprefix.prefixes=/whoami
- traefik.http.routers.whoami.middlewares=strip-who#docker
A request to http://localhost/whoami returns (among other things)
GET / HTTP/1.1.
This is exactly how I expected my routing approaches to work for all my other applications. The Traefik dashboard shows green all around for every middleware I register and yet all I see is 504 errors.
If anyone has any clues I would sincerely appreciate it.
To summarize my solution to a similar problem
my-service:
image: some/image
ports: # no need to expose port, just to show that service listens on 8090
- target: 8090
published: 8091
mode: host
labels:
- "traefik.enable=true"
- "traefik.http.routers.myservice-router.rule=PathPrefix(`/myservice/`)"
- "traefik.http.routers.myservice-router.service=my-service"
- "traefik.http.services.myservice-service.loadbalancer.server.port=8090"
- "traefik.http.middlewares.myservice-strip.stripprefix.prefixes=/myservice"
- "traefik.http.middlewares.myservice-strip.stripprefix.forceslash=false"
- "traefik.http.routers.myservice-router.middlewares=myservice-strip"
Now details
Routing rule
... redirect all calls thats path starts with /myservice/
- "traefik.http.routers.myservice-router.rule=PathPrefix(`/myservice/`)"
... to service my-service
- "traefik.http.routers.myservice-router.service=my-service"``
... to port 8090
- "traefik.http.services.myservice-service.loadbalancer.server.port=8090"
... and uses myservice-strip middleware
- "traefik.http.routers.myservice-router.middlewares=myservice-strip"
... this middleware will strip /myservice from path
- "traefik.http.middlewares.myservice-strip.stripprefix.prefixes=/myservice"
... and will not add trailing slash (/) if path becomes an empty string
- "traefik.http.middlewares.myservice-strip.stripprefix.forceslash=false"
There is an issue with prefix without ending with '/'.
Test your config like this:
- "traefik.http.routers.whoami.rule=Host(`localhost`) && (PathPrefix(`//whoami/`) || PathPrefix(`/portainer`))"
- "traefik.http.middlewares.strip-who.stripprefix.prefixes=/whoami"
I had a similar problem that was solved with the addition of
- "traefik.http.middlewares.strip-who.stripprefix.forceslash=true"
It makes sure the strip prefix doesn't also remove the forward slash.
You can read more about the forceslash documentation https://docs.traefik.io/middlewares/stripprefix/

Resources