I am trying to run Traefik as an API gateway and want to trigger ForwardAuth middleware by using the following docker compose file but the middleware the auth endpoint is not being hit. I am using it with localhost.
version: '3'
services:
reverse-proxy:
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
ports:
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
- $PWD/traefik.toml:/traefik.toml
whoami:
image: emilevauge/whoami
labels:
- traefik.enable=true
- "traefik.frontend.rule=Host:whoami.docker.localhost"
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
- "traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
- "traefik.http.middlewares.testauth.ForwardAuth.Address=http://localhost:55391/api/Auth"
I was struggling with this for a while as well, and couldn't find an answer anywhere other than fairly hidden in the Traefik docs. The ForwardAuth docs don't actually mention this, but looking at the middlewares overview configuration example I suddenly noticed that you not only have to specify the middleware, you also have to apply it to the router.
Adding this label to whoami service should do the trick:
- "traefik.http.routers.whoami.middlewares=testauth"
Note that you can also specify multiple middlewares here, by comma-separating them, so you could add the other middlewares you defined like so:
- "traefik.http.routers.whoami.middlewares=testauth,test-redirectscheme,test-replacepath"
Related
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.
I am trying to set up a sample application with the Traefik reverse proxy in Docker.
I am using Traefik v2.2 for this project which has significant differences from Traefik.v1.0.
Here is my docker-compose.yml file:
version: '3'
services:
traefik:
# The official v2 Traefik docker image
image: traefik:v2.2
# Enables the web UI and tells Traefik to listen to docker
command:
- --api.insecure=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
ports:
# The HTTP port
- "89:80"
# The Web UI (enabled by --api.insecure=true)
- "8089:8080"
volumes:
# So that Traefik can listen to the Docker events
- "/var/run/docker.sock:/var/run/docker.sock:ro"
whoami:
# A container that exposes an API to show its IP address
image: containous/whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
I can access Traefik's dashboard when I go to localhost:8089 on my web browser, but I cannot access the whoami application when I type in the whoami.localhost address on my web browser. I'm just wondering if there is anything I need to change before I can access it, or do I need to change the host from whoami.localhost to localhost:3000 since that's the port I want to access the application in.
One problem I am spotting is that you exposed container port 80 of the traefik container to the host port 89. If you type in whoami.localhost in your web browser, your browser is going to search for an application on host port 80 at that address (since localhost maps natively to port 80), but it is not going to find anything there, because it can only be found at port 89. From my understanding, you should be able to access the application via the command line with the command curl -H Host:whoami.localhost http://127.0.0.1:89. Unfortunately, I am unsure how the URL whoami.localhost:89 is handled by your browser respectively by your DNS.
You can to modify the docker-compose.yml file this way:
version: "3"
services:
traefik:
# The official v2 Traefik docker image
image: traefik:v2.2
# Enables the web UI and tells Traefik to listen to docker
command:
- --api.insecure=true
- --providers.docker=true
ports:
# The HTTP port
- "89:80"
# The Web UI (enabled by --api.insecure=true)
- "8089:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
whoami:
# A container that exposes an API to show its IP address
image: containous/whoami
labels:
- traefik.http.routers.whoami.rule=Host(`whoami.localhost`)
And then you can access the application on your command terminal by typing in:
curl -H Host:whoami.localhost http://127.0.0.1:89
Note: whoami.localhost can be whoami.docker.localhost or app.localhost or whatever you want. The thing here is that you should localhost attached to the end, except if you're adding a Fully Qualifies Domain name (FQDN).
That's all.
I hope this helps
I'm trying to scale up my R plumber API's and starting playing with Traefik 2.0 as a means to expose, load balance, and secure the rest API's written in R. I can't get traefik to add basic auth and pass the path and query parameters to the container running my API. Basic auth works and I can set up the reverse proxy to the container correctly, but not both simultaneously. The setup below results in a 404 error.
I can run the containerized plumber API fine.
I can access the containerized plumber API through traefik (seen below) using the trestletech/plumber docker image through the path "api_test".
I can set up basic auth using Traefik's whoami example (seen below) and it works (ig http://localhost/traefexample/whoami).
I can't successfully add the two lines that are commented out below. I want those two lines to add basic auth, and while that works, I get a 404 error rather the getting the expected information.
version: '3.7'
services:
reverse-proxy:
# The official v2.0 Traefik docker image
image: traefik:v2.0
# Enables the web UI and tells Traefik to listen to docker
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --api.insecure=true
- --providers.docker
ports:
# The HTTP port
- "80:80"
- "8000:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
api_test:
# An R plumber api in a docker container
image: trestletech/plumber
labels:
- "traefik.http.routers.api_test.rule=Path(`/api_test/{path:.+}`)"
- "traefik.http.middlewares.api_test-replacepathregex.replacepathregex.regex=/api_test(.*)"
- "traefik.http.middlewares.api_test-replacepathregex.replacepathregex.replacement=$$1"
- "traefik.http.routers.api_test.middlewares=api_test-replacepathregex#docker"
# - "traefik.http.routers.api_test.middlewares=auth"
# - "traefik.http.middlewares.auth.basicauth.users=user:$$apr1$$q8eZFHjF$$Fvmkk//V6Btlaf2i/ju5n/"
traefexample:
# A container that exposes an API to show its IP address - example from traefik basic, auth is working
image: containous/whoami
labels:
- "traefik.http.routers.traefexample.rule=Path(`/traefexample/{path:.+}`)"
- "traefik.http.middlewares.traefexample-replacepathregex.replacepathregex.regex=/traefexample(.*)"
- "traefik.http.middlewares.traefexample-replacepathregex.replacepathregex.replacement=$$1"
- "traefik.http.routers.traefexample.middlewares=traefexample-replacepathregex#docker"
- "traefik.http.routers.traefexample.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=user:$$apr1$$q8eZFHjF$$Fvmkk//V6Btlaf2i/ju5n/"
With the posted setup I can use the endpoint "http://localhost/api_test/mean" and the response is the mean of some randomly selected numbers.
When I add the the two auth lines (currently commented out), I get the 404 error when I expect a single number.
here
- "traefik.http.routers.api_test.middlewares=api_test-replacepathregex#docker"
remove #docker so it should be
- "traefik.http.routers.api_test.middlewares=api_test-replacepathregex"
I'm running minio using its official docker-compose file which creates 4 services (containers): minio1,minio2,minio3,minio4. Traefik treats them as 4 unique services, but in reality, they should be treated as a single backend, that is, I want Traefik to generate 1 frontend an 1 backend (with 4 servers) for minio.
I tried putting them into a single group(servicefabric.groupname) but to no avail.
I have the following labels set for each minio service:
labels:
- "traefik.servicefabric.groupname=minio"
- "traefik.basic.frontend.rule=Host:foo.bar.com"
- "traefik.weight=10" # 10,20,30,40 incremented per service
- "traefik.frontend.rule=Host:traefik"
- "traefik.port=9000"
container_name: minio*
Is there any way to achieve this?
#Riverman
I had the same issue as you and I solved it by playing around as it's not fully documented in Traefik documentation. What you need to do is specify the traefik.backend value for all the services to be the same name and set traefik.frontend.backend to that traefik.backend value. You can't use the service piece for this. Below is an example.
services:
minio01:
image: minio/minio
hostname: minio01
restart: always
volumes:
- minio01-data:/export
networks:
- minio
- traefik
command: server http://minio01/export http://minio02/export
labels:
- 'traefik.enable=true'
- 'traefik.docker.network=traefik'
- 'traefik.frontend.rule=Host:minio.local'
- 'traefik.frontend.backend=minio'
- 'traefik.port=9000'
- 'traefik.protocol=http'
- 'traefik.backend=minio'
minio02:
image: minio/minio
hostname: minio02
restart: always
volumes:
- minio02-data:/export
networks:
- minio
- traefik
command: server http://minio01/export http://minio02/export
labels:
- 'traefik.enable=true'
- 'traefik.docker.network=traefik'
- 'traefik.frontend.rule=Host:minio.local'
- 'traefik.frontend.backend=minio'
- 'traefik.port=9000'
- 'traefik.protocol=http'
- 'traefik.backend=minio'
All minio services have to have the same frontend rule and the same backend name.
labels:
- "traefik.frontend.rule=Host:minio.${DOMAIN}"
- "traefik.backend=minio"
- "traefik.port=9000"
Also I think you misunderstood the meaning of "backend". A backend is a server to which Traefik route traffic based on the frontend rules. Same as "upstream"/"location" in nginx.
Edit
As stated in the comment, this configuration creates multiple frontends all pointing to the same backend, although functional this looks ugly. A quick solution is to just have one service with ‘frontend’ but if that service goes down, the frontend will be gone too.
A better way to do this is to set it in the config file, traefik.toml:
[frontends]
[frontends.frontend1]
backend = "minio"
[frontends.frontend1.minio]
rule = "Host: minio.${DOMAIN}”
Objective
I have a server running Rancher (Docker). In that server, I have several un-related stacks.
I want to make Traefik the main interaction point of that stack. And make it load balance / proxy the requests to different containers based on the path.
I want to make it send the traffic for /api to the backend server service. And send the traffic for / to the frontendservice.
Current state
Here's a slimmed down version of my docker-compose.yml showing only the relevant services:
version: '2'
services:
server:
image: server
labels:
- "traefik.frontend.rule=PathPrefix:/api"
- "traefik.enable=true"
- "traefik.port=80"
frontend:
image: frontend
labels:
- "traefik.frontend.rule=PathPrefix:/"
- "traefik.enable=true"
- "traefik.port=80"
proxy:
image: traefik:v1.4
command: --web --accessLog --rancher --rancher.exposedbydefault=false --rancher.metadata=true
volumes:
- /dev/null:/traefik.toml
Then using a Rancher load balancer that listens to the public ports, I redirect requests to app1.example.com to my proxy service. Then it takes the requests and re-directs traffic to each of the two containers based on the path.
I also redirect traffic to traefik.app1.example.com to the same proxy service, to the port 8080 to access the web UI.
If I have only one stack, it works.
The problem
If I add another stack (or if I duplicate that stack) and have more services with Traefik labels, the proxy from app1 will read the labels from the services in app2 and any other stack that declares Traefik labels.
Then, in the web UI for the proxy in app1, I can see all the backends from all the different stacks. But the frontend rules get overwritten.
Question
Up to now, I've seen examples mostly of how to use Traefik as a unique global load balancer / proxy. I just realized that I assumed that I could also create isolated Traefik instances per stack, or a hierarchy of Traefik load balancers.
It seems to me like I'm missing some configuration or misunderstanding something.
But still, I have to ask, is it possible to have different isolated Traefik instances per stack and make them only listen and use the services in their own stack?
Is it possible with Rancher? Is it possible with any other Docker stack orchestrator (e.g. Swarm)?
If that's possible, what am I missing?
I think I found how to solve it.
It seems I can't make Traefik only use services in his own stack directly. But it seems I can use Traefik constraints and tags to achieve almost the same.
Here's my updated docker-compose.yml using constraints and tags:
version: '2'
services:
server:
image: server
labels:
- "traefik.frontend.rule=PathPrefix:/api"
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.tags=app1.example.com"
frontend:
image: frontend
labels:
- "traefik.frontend.rule=PathPrefix:/"
- "traefik.enable=true"
- "traefik.port=80"
- "traefik.tags=app1.example.com"
proxy:
image: traefik:v1.4
command: --web --accessLog --constraints=tag==app1.example.com --rancher --rancher.exposedbydefault=false --rancher.metadata=true
volumes:
- /dev/null:/traefik.toml
It will only match services that have the Traefik tag app1.example.com. Those tags can be any string, but as I'm wanting to filter by a specific domain, I just used the domain I wanted to filter as the tag to use.
Also, notice that the tag is set in the services with a label traefik.tag.
If you are interested in Traefik v2 solution for this, you can use --providers.docker.constraints option to achieve the same result.
So, the basic example could be:
services:
traefik:
image: traefik:v2.3
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.constraints=Label(`custom.label`,`custom-value`)"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
custom_service:
image: ...
labels:
- "traefik.enable=true"
- "custom.label=custom-value"
Docs