How to set Traefik 2.4 service name in docker-compose labels - docker

Is there any way to set traefik.http.services name in docker-compose labels?
Lets say i have simple docker-compose.yml:
version: '3.4'
services:
traefik:
image: "traefik:v2.4.2"
command:
- --log.level=warning
- --api.insecure=true
- --api.dashboard=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
ports:
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
labels:
- traefik.enable=true
# Dashboard
- traefik.http.routers.traefik.rule=Host(`traefik.localhost`)
# this is interesting - traefik is naming his api service somehow
- traefik.http.routers.traefik.service=api#internal
- traefik.http.services.traefik.loadbalancer.server.port=8080
whoami:
image: "traefik/whoami"
labels:
- traefik.enable=true
- traefik.http.routers.webwho.rule=Host(`who.localhost`)
This works great, after docker-compose up i can see the dashboard at http://traefik.localhost and "whoami" at http://who.localhost
The problem is the name of 'whoami' traefik service - it is something like whoami-{name_of_project} which is problem when i want to reference it in other label.
For example, i want to use new 'foo' docker service as 404.html provider (in this example i will use traefik/whoami image, which is silly, but hey, this is only example ;) )
I do that by using low priority "catch all" router:
version: '3.4'
services:
traefik:
image: "traefik:v2.4.2"
command:
- --log.level=warning
- --api.insecure=true
- --api.dashboard=true
- --api.debug=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
ports:
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
labels:
- traefik.enable=true
# Dashboard
- traefik.http.routers.traefik.rule=Host(`traefik.localhost`)
# this is interesting - traefik is naming his api service somehow
- traefik.http.routers.traefik.service=api#internal
- traefik.http.services.traefik.loadbalancer.server.port=8080
whoami:
image: "traefik/whoami"
labels:
- traefik.enable=true
- traefik.http.routers.webwho.rule=Host(`who.localhost`)
foo:
image: "traefik/whoami"
labels:
- traefik.enable=true
- traefik.http.routers.error-router.rule=HostRegexp(`{host:.+}`)
- traefik.http.routers.error-router.priority=1
- traefik.http.routers.error-router.middlewares=error-pages-middleware
- traefik.http.middlewares.error-pages-middleware.errors.status=400-599
# nope!
# actual name of this service (as seen in traefik dashboard) is something like 'foo-test'
# and this will not work.
# (btw, there is very clear Error Message in traefik console about service foo does not exists,
# making debugging pleasant experience :) Thank you Traefik!)
- traefik.http.middlewares.error-pages-middleware.errors.service=foo
- traefik.http.middlewares.error-pages-middleware.errors.query=/{status}.html
but i have no idea how to set name of traefik service so i can reference it as value of the traefik.http.middlewares.error-pages-middleware.errors.service=??? label - service name foo-test isnt static (that 'test' is name of my directory which contains docker-compose.yml) and it keep changing from time to time (especially when used with visual studio .dcproj)
So - is there any way to set name of service?
What did i try:
Google & doc. Nope, but maybe because i dont know what to ask.
Setting container_name: foo does not help at all.
Interestlingly, if i add label - traefik.http.services.foo.loadbalancer.server.port=80 it automagically name the traefik service as foo which is exactly what i want and everything works. But this feels like "Plan B" because i dont want to set port, i want to set the name of the service.
using traefic dynamic configuration
[http.services]
[http.services.foo.loadBalancer]
[[http.services.foo.loadBalancer.servers]]
url = "http://foo:80/"
should work (i didnt tested it) -- but again, i dont want to set whole url, i want to set the name of service...

Looks like (at least in v2.4) there isnt any other way than
labels:
- traefik.http.services.<<name_of_service>>.loadbalancer.server.port=80
AFAIK even in the documentation, there is only one mention:
labels:
- "traefik.http.routers.myproxy.rule=Host(`example.net`)"
# service myservice gets automatically assigned to router myproxy
- "traefik.http.services.myservice.loadbalancer.server.port=80"
(source: https://doc.traefik.io/traefik/routing/providers/docker/ )

Related

Allow both http and https with Traefik on Docker

I am using Traefik in my VPS to route the traffic to my websites, after hours of messing around with it I finally managed to get it working with https using Le's Encrypt.
Now, one thing that I need to do is be able to also access my website via plain http as this is a hobby project for older browsers and the only reason I added tls is because Firefox doesn't like my website without it.
The problem is that, with my current configuration, I can access my website via https normally but when I try it with plain http I get a 404 error.
Here's what my config on docker-compose looks like:
version: "3"
services:
traefik:
image: "traefik:v2.5"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.teeresolver.acme.tlschallenge=true"
- "--certificatesresolvers.teeresolver.acme.email=me#gmail.com"
- "--certificatesresolvers.teeresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
- "80:80"
- "8080:8080"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- mywebsite
# [...]
mywebsite:
image: my-web-site/site
build:
context: ~/mywebsite-runner/_work/my-web-site-php/my-web-site-php
dockerfile: Dockerfile
volumes:
- ./tee-downloads:/var/www/build/downloads
- ./tee-contents:/var/www/build/contents
ports:
- "0.0.0.0:8001:80"
labels:
- "traefik.enable=true"
- "traefik.http.routers.themywebsite.rule=Host(`mywebsite.com`, `www.mywebsite.com`)"
- "traefik.http.routers.themywebsite.entrypoints=websecure,web"
- "traefik.http.routers.themywebsite.tls.certresolver=teeresolver"
networks:
- mywebsite
networks:
mywebsite:
I have been searching for a solution for hours but the only things I can find on google are configs to redirect http to https, which I can't do.
Does anyone know how to do that?
Thanks in advance for the help.
In traefik , each router defines a set of policies to apply depending of rules and entrypoints.
If you want 2 policies, one for http and one for https, you need to define 2 traefik routers :
mywebsite:
...
labels:
- "traefik.enable=true"
- "traefik.http.routers.themywebsite.entrypoints=websecure"
- "traefik.http.routers.themywebsite.tls.certresolver=teeresolver"
- "traefik.http.routers.themywebsite.rule=Host(`mywebsite.com`, `www.mywebsite.com`)"
- "traefik.http.routers.httpwebsite.entrypoints=web"
- "traefik.http.routers.httpwebsite.rule=Host(`mywebsite.com`, `www.mywebsite.com`)"
One called themywebsite
Another one called httpwebsite
As a result, you do not use a certresolver for httpwebsite router.

How to use traefik segments to route request to the right service on the right port of the same container

I have a docker container that has 2 ports exposed, each for a different web service.
One is an API, the other is a simple web page with documentation.
I have tried to understand Traefik's doc. Looks like I need to use segments and I am failing miserably.
I want
https://api.mydomain.net routed to port my-container:4000
https://doc.mydomain.net routed to port my-container:3000
This is what I have now, which works but only serves port 4000
my-service:
image: myregistry.com:5005/my-service:latest
container_name: my-service
labels:
- traefik.http.routers.my-service-router.tls=true
- traefik.http.routers.my-service-router.entrypoints=secure
- traefik.http.routers.my-services-router.rule=Host(`www.mydomain.net`)
networks:
- internal
and I tried segments as follow
my-service:
image: myregistry.com:5005/my-service:latest
container_name: my-service
expose:
- 4000 # my API
- 3000 # my doc
labels:
# segment myapi
- traefik.myapi.port=4000
- traefik.myapi.http.routers.my-service-router.tls=true
- traefik.myapi.http.routers.my-service-router.entrypoints=secure
- traefik.myapi.http.routers.my-services-router.rule=Host(`api.mydomain.net`)
# segment mydoc
- traefik.mydoc.port=3000
- traefik.mydoc.http.routers.my-service-router.tls=true
- traefik.mydoc.http.routers.my-service-router.entrypoints=secure
- traefik.mydoc.http.routers.my-services-router.rule=Host(`doc.mydomain.net`)
networks:
- internal
but it's wrong isn't it?
so I tried different accordingly to the doc...
my-service:
image: myregistry.com:5005/my-service:latest
container_name: my-service
expose:
- 4000 # my service
- 3000 # my other service
labels:
# segment myapi
- traefik.myapi.port=4000
- traefik.myapi.frontend.entrypoints=secure
- traefik.myapi.frontend.rule=Host(`api.mydomain.net`)
# segment mydoc
- traefik.mydoc.port=3000
- traefik.mydoc.frontend.entrypoints=secure
- traefik.mydoc.frontend.rule=Host(`doc.mydomain.net`)
networks:
- internal
I am not understanding the doc, so any pointers would be welcome.
I'm pretty sure that "mydoc" and "myapi" shouldn't be there:
my-service:
image: myregistry.com:5005/my-service:latest
container_name: my-service
expose:
- 4000 # my service
- 3000 # my other service
labels:
# segment myapi
- traefik.http.services.myapi.loadbalancer.server.port=4000
- traefik.http.routers.myapi.entrypoints=secure
- traefik.http.routers.myapi.rule=Host(`api.mydomain.net`)
- traefik.http.routers.myapi.service=myapi
# segment mydoc
- traefik.http.services.mydoc.loadbalancer.server.port=3000
- traefik.http.routers.mydoc.entrypoints=secure
- traefik.http.routers.mydoc.rule=Host(`adoci.mydomain.net`)
- traefik.http.routers.mydoc.service=mydoc
networks:
- internal
Also check that the traefik container is in the internal network too.

Traefik route 404

I am trying to host a few different websites on a single Raspberry Pi using Docker. I was told that I would need to use something like Traefik to route everything properly.
I tried using the Docker Basic Example under User Guides in their documentation as a test. I followed along with the example and created the docker-compose.yml file and copied in the example from the docs:
version: "3.3"
services:
traefik:
image: "traefik:v2.2"
container_name: "traefik"
command:
# - "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
ports:
- "80:80"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
whoami:
image: "containous/whoami"
container_name: "simple-service"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
Using this example going to the devices local IP I recieve a page that simply says:
404 Page not found
I've tried changing the Traefik container image version, and editing the example with my relevant information as well as recreating the example on another host and still I receive the above 404.
Am I doing something incorrect with Traefik to receive this 404?
In the user guide you have mentioned, there is this note:
Replace whoami.localhost by your own domain within the traefik.http.routers.whoami.rule label of the whoami service.
So, after you replace whoami.localhost with you local IP, you should be able to see whoami service responding correctly.

How to setup basic auth globally in traefik v2?

I'm using traefik 2.1 and would like to setup basic auth for all containers, in 1.x it was easy to do:
[entryPoints.http.auth.basic]
usersFile = "/etc/traefik/.htpasswd"
But how to setup it in 2.x? I'd like to avoid inserting code in all my docker-compose.yml files - got a lot of them.
The main idea is:
we can use built-in middleware https://docs.traefik.io/middlewares/basicauth/
we need to connect middleware from above to a container which needs to be secured
Please find an example of docker-compose.yml
version: '3.7'
services:
traefik:
image: "traefik:v2.2.1"
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=default"
- "--entrypoints.web.address=:80"
- "--api"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
ports:
- 80:80
# management console
- 8080:8080
labels:
- "traefik.enable=true"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
# auth middleware with user / password
- "traefik.http.middlewares.my-auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
whoami:
image: "containous/whoami"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
# connect your auth middleware to a service which you want to protect
- "traefik.http.routers.whoami.middlewares=my-auth"
So, now we can check that:
auth has prompted on http://whoami.localhost
the valid user name is "test:test" or "test2:test2"
You should use htpasswd command for generating a list of users and connect it according to the Traefik docs.
That's it. Happy coding ;)

Traefik routing to both known and wildcard subdomain on a single domain

Is it possible to have a wildcard subdomain that does not include a specific subdomain?
*.mydomain.com OK
login.mydomain.com SKIP
I cannot access my login container when using a wildcard on my app container. Below is an image of what I am trying to accomplish. (the traffic logo should technically be between the list of routes and the containers)
The following configuration does not work if the rule HostRegexp:{subdomain:[a-z]+}.${HOST_DOMAIN} is included.
This configuration successfully works after removing the host regex for everything EXCEPT the wildcard subdomains.
services:
traefik:
image: traefik
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- .traefik.toml:/etc/traefik/traefik.toml:ro
ports:
- "80:80"
- "443:443"
api:
image: my-api-image
labels:
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.frontend.rule=Host:app.${HOST_DOMAIN}; PathPrefix: /api"
app:
image: my-app-image
labels:
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.frontend.rule=Host:app.${HOST_DOMAIN}"
- "traefik.frontend.rule=HostRegexp:{subdomain:[a-z]+}.${HOST_DOMAIN}" # this second rule overwrites the first rule and I am aware of that, I am just showing what rules i've tried :)
login:
image: my-login-image
labels:
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.frontend.rule=Host:login.${HOST_DOMAIN}"
My problem is currently with the app container. I am getting a bad gateway if I have the following included as a frontend rule:
"traefik.frontend.rule=HostRegexp:{subdomain:[a-z]+}.${HOST_DOMAIN}"
I also tried leaving the above under app, and removing the following without any luck:
"traefik.frontend.rule=Host:app.${HOST_DOMAIN}"
Any suggestions or ideas would be appreciated. Thanks.
Edit:
Rewording this a bit.
So this is what worked for me:
version: '2'
services:
traefik:
image: traefik
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# I removed your traefik.toml as you did not specify what is in it, so it's irrelevant
ports:
- "80:80"
- "443:443"
# Very helpful for debugging dashboard can be seen at http://localhost:8080 if the port is exposed
- "8080:8080"
labels:
# You don't want traefik trying to create proxy for itself
- "traefik.enable=false"
# Since we have no traefik.toml any longer, let's put the essentials on the command line
command: ["--api","--docker"]
app:
# this is my test image of a web server that dumps request back to the caller
image: andrewsav/talkback
# the hostname is a part of the dump, so let's specify something that we can relate to
hostname: "app"
labels:
# note that you want this frontened to match the last. otherwise it will match login.${HOST_DOMAIN}"
- "traefik.frontend.priority=1"
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.frontend.rule=HostRegexp:{subdomain:[a-z]+}.${HOST_DOMAIN}"
api:
image: andrewsav/talkback
hostname: "api"
labels:
# this frontend needs to match before the one above
- "traefik.frontend.priority=2"
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.frontend.rule=Host:app.${HOST_DOMAIN}; PathPrefix: /api"
login:
image: andrewsav/talkback
hostname: "login"
labels:
- "traefik.frontend.priority=3"
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.frontend.rule=Host:login.${HOST_DOMAIN}"
A few notes:
Bad Gateway indicates that the endpoint you told traefik to talk to is not listening. Look at at the dashboard and find out which backend is used and double check that ip/port is correct.
You have to use priorities for matching order. Please refer to the documentation on how it works.

Resources