Traefik in Docker: Path routing not working - docker

I am trying to setup traefik in a container on a docker host:
Host: myserver.some.domain
Traefik: v2.1.3
Docker Host: v19.03.8
I want to view the dashboard when I request "http://myserver.some.domain/traefik" and further navigation should be reflected in the url like requesting the first url and landing on "http://myserver.some.domain/traefik/dashboard/#/".
I experimented with multiple middleswares:
Path
PathPrefix
StripPrefix
So far PathPrefix sounds like the most correct choice, but I get "404 page not found".
For now I exposed also port 8080, so I can crosscheck my changes (on http://myserver.some.domain:8080, which works). Later on, I want to hide port 8080 and only let the routing on port 80 do the work.
My docker-compose.yml looks like this:
version: "3"
services:
traefik:
image: traefik:2.1.3
container_name: 'traefik'
command:
# Enable DEBUG log for issue resolving
- "--log.level=DEBUG"
# Enable dashboard
- "--api.dashboard=true"
# Enable debug information in api
- "--api.debug=true"
# Allow api access on unsecure http requests
# Will be removed when SSL will be configured
- "--api.insecure=true"
# Default http port
- "--entrypoints.web.address=:80"
# Dashboard port
- "--entrypoints.traefik.address=:8080"
# Allow traefik to se other docker containers for dynamic routing
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
# Hide containers without traefik configuration by default
- "--providers.docker.exposedByDefault=false"
# Use the container's configured network
# All containers use network "proxy", type "bridge"
- "--providers.docker.useBindportIP=false"
labels:
# Enable Traefik configuration for container
traefik.enable: "true"
# Use docker network "proxy"
traefik.docker.network: "proxy"
# Define http entrypoint
traefik.http.routers.traefik.entrypoints: "web"
# Proxy all requests which start with "/traefik"
traefik.http.routers.traefik.rule: "PathPrefix(`/traefik`)"
# # Proxy request on path "/traefik"
# traefik.http.routers.traefik.rule: "Path(`/traefik`)"
# Replace path prefix "/traefik" with "/"
traefik.http.routers.traefik.middlewares: "traefik_replacepath"
traefik.http.middlewares.traefik_replacepath.replacePath.path: "/"
# # Strip path prefix "/traefik" and force slash "/"
# traefik.http.routers.traefik.middlewares: "traefik_stripprefix"
# traefik.http.middlewares.traefik_stripprefix.stripprefix.prefices: "/traefik"
# traefik.http.middlewares.traefik_stripprefix.stripPrefix.forceSlash: "true"
# Define port for service
traefik.http.services.traefik.loadbalancer.server.port: "8080"
volumes:
# Allow traefik to see other containers
- "/var/run/docker.sock:/var/run/docker.sock"
networks:
- proxy
ports:
# Expose port 80 to handle web/http requests
- "80:80"
# For DEBUG: Expose port 8080 to see dashboard without routing
# Will be removed when default rounting is working
- "8080:8080"
networks:
proxy:
external: true
Anybody knows where I am wrong?
Best regards,
David

Related

Setting Traefik to intercept traffic between Docker containers

I have Traefik container (traefik v. 2.8) running as reverse proxy for local development.
I also use docker-compose.yml file to define my services.
Also, I have exposed the services present in docker-compose.yml via host.docker.internal by setting these lines in my /etc/hosts file:
127.0.0.1 host.docker.internal
localhost host.docker.internal
My setup is as such:
host.docker.internal:8443 used for service_a
host.docker.internal:8453 used for service_b
I have setup Traefik route from a.localhost that goes to host.docker.internal:8443.
I can access a.localhost from the host outside the containers just fine, and Traefik does really route the traffic to host.docker.internal:8443 as I want.
Problem is that I have a reason to have service B (host.docker.internal:8453) call service A via the a.localhost hostname.
This does not work, as in service B, I get unknown host when trying to access a.localhost
Here is extract from my docker-compose.yml file:
version: '3'
services:
reverse_proxy:
image: traefik:v2.8
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
- "80:80"
- "443:443"
# The Web UI (enabled by --api.insecure=true)
- "9000:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
- ./dev-traefik/traefik.yml:/etc/traefik/traefik.yml
- ./dev-traefik:/configurations
service_a:
ports:
- "8443:8443"
service_b:
ports:
- "8453:8453"
Also I'm using a yml-based configuration for Traefik, present in dynamic-config.yml:
http:
routers:
service-a-router:
service: service-a
rule: "Host(`a.localhost`)"
tls: "true" # using tls
services:
service-a:
loadBalancer:
servers:
- url: "https://host.docker.internal:8443" # service A
tls:
certificates:
- certFile: "/etc/https/tls.crt"
keyFile: "/etc/https/tls.key"
stores:
default:
defaultCertificate:
certFile: "/etc/https/tls.crt"
keyFile: "/etc/https/tls.key"
It seems like Traefik is able to listen to requests made from host network, as accessing https://a.localhost from browser outside the container network works just fine.
On the other hand, requests made by service_a container don't seem to be caught by Traefik.
What I have also tried is to add a.localhost to /etc/hosts in the host machine running the containers like this:
127.0.0.1 a.localhost
localhost a.localhost
And then using curl inside service B container to access service A.
This resulted in getting connection refused as opposed to Could not resolve host: a.localhost. This leads me to suggest that traefik couldn't intercept traffic from service b container
What am I doing wrong?
Is there a way to make such setup work? I do have a legit reason for it, which relates to having as close setup as possible in local development as on other environments which are deployed to cloud.
I wasn't able to have Traefik intercept container -> container traffic the way I originally specified I'd want, but was able to actually nevertheless get similar setup working.
Here's the scenario:
I have two services that are accessed via HTTP & TLS:
service_a
service_b
I want to be able to use host.docker.internal special DNS name to my advantage and actually have Traefik to proxy traffic from https://host.docker.internal/service_a to service_a port 8443 both outside Docker container network (from the host machine running Docker) AND from service_b via the fact that both the host machine running Docker can access host.docker.internal and also hosts inside the Docker network.
Using this fact to my advantage, I just defined a path for service_a as such in Traefik's YML configuration file:
http:
routers:
service-a-router:
service: service-a
rule: "Host(`host.docker.internal`) && PathPrefix(`/service_a`)"
tls: "true" # using tls
services:
service-a:
loadBalancer:
servers:
- url: "https://host.docker.internal:8443" # service A
tls:
certificates:
- certFile: "/etc/https/tls.crt"
keyFile: "/etc/https/tls.key"
stores:
default:
defaultCertificate:
certFile: "/etc/https/tls.crt"
keyFile: "/etc/https/tls.key"
And docker-compose.yml was made to look like this:
version: '3'
services:
reverse_proxy:
image: traefik:v2.8
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
- "80:80"
- "443:443"
# The Web UI (enabled by --api.insecure=true)
- "9000:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
- ./dev-traefik/traefik.yml:/etc/traefik/traefik.yml
- ./dev-traefik:/configurations
service_a:
ports:
- "8443:8443"
service_b:
ports:
- "8453:8453"
Now as I use host.docker.internal in Host rule in my Traefik YML config, Traefik is in fact able to intercept both traffic from the Docker host machine and from the Docker container service_b.
service_b just need to configure URL of https://host.docker.internal/service_a to access service_a through Traefik.

Deploying FastAPI with HTTPS powered by Traefik

i followed the guide for Deploying FastAPI with HTTPS powered by Traefik enter link description here
can someone tell me what changes should i make to access https
the docker compose consist 3 files
1)docker-compose.traefik.yml
services:
traefik:
# Use the latest v2.3.x Traefik image available
image: traefik:v2.3
ports:
# Listen on port 80, default for HTTP, necessary to redirect to HTTPS
- 80:80
# Listen on port 443, default for HTTPS
- 443:443
restart: always
volumes:
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount the volume to store the certificates
# Mount the volume to store the certificates
- traefik-public-certificates:/certificates
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Do not expose all Docker services, only the ones explicitly exposed
- --providers.docker.exposedbydefault=false
# Create an entrypoint "http" listening on port 80
- --entrypoints.http.address=:80
- --entrypoints.https.address=:443
# Create the certificate resolver "le" for Let's Encrypt, uses the environment variable EMAIL
- --certificatesresolvers.le.acme.email=spb7221#gmail.com
# Store the Let's Encrypt certificates in the mounted volume
- --certificatesresolvers.le.acme.storage=/certificates/acme.json
# Use the TLS Challenge for Let's Encrypt
- --certificatesresolvers.le.acme.tlschallenge=true
- --accesslog
# Enable the Traefik log, for configurations and errors
- --log
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public
volumes:
# Create a volume to store the certificates, there is a constraint to make sure
# Traefik is always deployed to the same Docker node with the same volume containing
# the HTTPS certificates
traefik-public-certificates:
networks:
# Use the previously created public network "traefik-public", shared with other
# services that need to be publicly available via this Traefik
traefik-public:
external: true
2)docker-compose.yml
#!/bin/bash
services:
backend:
build: .
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
ports:
# Listen on port 80, default for HTTP, necessary to redirect to HTTPS
- 8000:8000
labels:
# Enable Traefik for this specific "backend" service
- traefik.enable=true
# Define the port inside of the Docker service to use
- traefik.http.services.app.loadbalancer.server.port=80
# Make Traefik use this domain in HTTP
- traefik.http.routers.app-http.entrypoints=http
- traefik.http.routers.app-http.rule=Host(`inskade.in`)
# Use the traefik-public network (declared below)
- traefik.docker.network=traefik-public
- traefik.http.routers.app-https.entrypoints=https
- traefik.http.routers.app-https.rule=Host(`inskade.in`)
- traefik.http.routers.app-https.tls=true
# Use the "le" (Let's Encrypt) resolver
- traefik.http.routers.app-https.tls.certresolver=le
# https-redirect middleware to redirect HTTP to HTTPS
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
# Middleware to redirect HTTP to HTTPS
- traefik.http.routers.app-http.middlewares=https-redirect
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public
networks:
traefik-public:
external: true
3)docker-compose.override.yml
services:
backend:
ports:
- 80:80
networks:
traefik-public:
external: false
here where i am checking the container
in browser I am able to access through http
i have checked the docker container of traefik and the certificate is present
the certificate
{
"le": {
"Account": {
"Email": "spb7221#gmail.com",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:spb7221#gmail.com"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/45w5706050"
},
"PrivateKey": "MIIJJwIBAAKCAgEAqmkfY8MqLzdnq8IV573RdqNIIHIev0WDpd8Y3QnzaN9HN7U8wBRQIhpSf98bRbZ77UQOGwzzSCObU5KE9lx80anU0zKPDQV0
"KeyType": "4096"
},
"Certificates": [
{
"domain": {
"main": "inskade.in"
},
"certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS10tCk1JSUdHVENDQlFHZ0F3SUJBZ0lTQkV1aHo3WU1MdHJNUGV6QUlrTkc3OFVXTUEwR0NTcUdT
"key": "LS0tLS1CRUdJTiBSU0EgUFJJVkFU1RSBLRVktLS0tLQpNSUlKS1FJQkFBS0NBZ0VBbkFLYzlNRFRQdUkxcW9sOWFYUEhHWTNlMFBDVWNyQ3NnaVFpS09Y
"Store": "default"
}
]
}
}
first, you should probably not post your certificates in plain clear sight, those are supposed to be private, especially "PrivateKey"
second, you are using traefik labels, and the names of these labels are relevant as you can see in the traefik docs
You named your docker service "backend" and should refer to it using this name so
- traefik.http.routers.app-https.entrypoints=https
changes to
- traefik.http.routers.backend.entrypoints=https
I didn't tested it but i think if you change every "app-https" and "app" with the correct "backend" name it should work.
last point, I do recommand putting the redirection from http to https in the traefik configuration, I personnaly use the following commands :
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=:443
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.web.http.redirections.entrypoint.permanent=true

Getting 502 Bad Gateway when trying to configure HTTPS on Traefik

I got a basic Traefik 2 setup working for HTTP here...
Now I'm trying to get HTTPS working, and basic auth for the dashboard with TLS and redirects...
docker_compose.yml:
version: '3.8'
networks:
myweb:
external: true
services:
proxy:
image: traefik:v2.3.0-rc4-windowsservercore-1809
container_name: traefik
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
# Mount the certs drive
- ./traefik-ssl-certs/:c:/certs/
# Mount the config folder
- ./traefik-config/:c:/config/
# Mount the host docker engine pipe ("docker volume ls")
- source: '\\.\pipe\docker_engine'
target: '\\.\pipe\docker_engine'
type: npipe
command:
- "--api.insecure=true"
# Register the traefik config directory as per: https://docs.traefik.io/providers/file/#directory
- --providers.file.directory=c:/config/
- --providers.file.watch=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
# Redirect http to https
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.web.http.redirections.entryPoint.scheme=https
- --entrypoints.web.http.redirections.entrypoint.permanent=true
# Configure Docker provider
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.endpoint=npipe:////./pipe/docker_engine"
- "--providers.docker.network=myweb"
- "--providers.docker.watch=true"
networks:
- myweb
labels:
- traefik.http.routers.api.service=api#internal
- traefik.enable=true
- traefik.docker.network=myweb
remoteling:
image: remoteling:latest
container_name: remoteling
networks:
- myweb
labels:
- traefik.enable=true
- traefik.docker.network=myweb
- traefik.http.middlewares.http2https.redirectscheme.scheme=https
- traefik.http.routers.remoteling-http.middlewares=http2https
- traefik.http.routers.remoteling-http.rule=Host(`example.com`) || Host(`example.example.com`)
- traefik.http.routers.remoteling-http.entrypoints=web
- traefik.http.services.remoteling.loadbalancer.server.port=443
- traefik.http.routers.remoteling-https.rule=Host(`example.com`) || Host(`example.example.com`)
- traefik.http.routers.remoteling-https.entrypoints=websecure
- traefik.http.routers.remoteling-https.tls=true
depends_on:
- proxy
From powershell I'm running:
docker network create -d nat myweb
docker-compose -p myweb up
In my working dir I have the following file structure:
./docker-compose.yml
./traefik-config/traefik.yml
./traefik-ssl-certs/example.com.crt
./traefik-ssl-certs/example.com.key
./traefik-ssl-certs/example.example.com.key
./traefik-ssl-certs/example.example.com.key
And the traefik.yml file looks like this:
tls:
certificates:
- certFile: c:/certs/example.example.com.crt
keyFile: c:/certs/example.example.com.key
- certFile: c:/certs/example.com.crt
keyFile: c:/certs/example.com.key
The traefik dashboard shows my service defined as a loadbalancer, which is good (is there any other type of service other than loadbalancer? I'm not sure how else to define the port other than via a loadbalancer). Clicking on the service gives me the local network IP - and when I visit that IP my site loads just fine (albeit with an SSL cert mismatch warning - expected).
However when I try to visit https://example.com or https://example.example.com - I get a 502 Bad Gateway. Any idea why I'd be getting this?
The browser shows the SSL certs are valid, with no warnings, so I assume my certificates config is fine.
The http to https redirect seems to be working, if I visit http://example.com it forwards me to https://example.com
What is wrong with my routing config to cause these Bad Gateways?
I have solved my problem! There were a few issues:
I had configured a TLS cert in my Dockerfile, back from when I was running the image as a single service on my server. So my image already had port 443 bound with the TLS cert. I think that caused issues when the Traefik router tried to configure TLS for the service. So I had to rebuild my image, removing the TLS. I also removed the code that required HTTPS attributes too, that is now the responsibility of traefik.
Image only needs to expose 1 port: My understanding now is that my web application should only run through port 80 (e.g. don't even need port 443 exposed in the image's firewall) and the Traefik router configures and handles the TLS/443 etc through port 80.
I hadn't actually defined my HTTP and HTTPS services properly. I have shared my docker-compose.yml file below - notice for both traefik and my other service I have separated the labels into sections: defining the service, routing for HTTP, routing for HTTPS, redirect middleware, and basic auth for the traefik dashboard. I couldn't find any good documentation or tutorials that really broke down the necessary aspects for traefik 2.0 and categorized them clearly.
The service definition label / loadbalancer port should point to whatever port the image's service is hosted from, e.g. port 80 in most cases, or in the case of the traefik service 8080. But crucially it doesn't need to also point to 443 for https.
In summary my (verbose) learning notes afterall are, you need to:
Define the service again as a label: Didn't work for me without the service definition label. I had to add a service label pointing to the name of the service under which the image is defined.
Define routers for http and https: Whatever text you put after the traefik.http.routers.YOUR_ROUTER_NAME becomes your router. It wasn't clear to me I needed separate routers for both http and https. You must do this for each service (e.g. traefik, whoami, remoteling, etc.)
Define the routers' entrypoints: AFAIK the name you put after the entrypoint in the traefik command defines a new entrypoint that you can use for other services. So in the traefik service definition you'd have --entrypoints.WEBNAME.address=:80 and --entrypoints.WEBSECURENAME.address=:443 (replacing those caps with your own name to use throughout the docker-compose.yml file.
Define the routers' domain names to capture: Just like you define routers for each http and https you must define the domains to capture for both of these routers, even just the same domain/path.
Add tls for https router: For the https router you need the tls.true label.
Separate middleware redirection definitions for traefik and each of your services: I've read that you can declare a global one, but AFAIK each service must opt-in by assigning the middleware to the http router.
Providing your own SSL certs on Docker for Windows: There was precious little information about running Docker for Windows with your own SSL certs. I have a batch script in my 'traefik' working dir with a subfolder containing the SSL certs (crt and key files). I mount this as the first volume, - ./traefik-ssl-certs/:c:/certs/. Then, in my working dir I have another folder called traefik-config containing my traefik.yml file (details in the question above). In linux everyone seems to just mount the config file directly, but mounting files doesn't work in Windows so I had to mount as a folder instead, then I used the command providers.file.directory=c:/config/, which tells traefik to look for the config file in there. The config file provides the location of the SSL certs for traefik to load. If you enable TLS for a router, Traefik will automatically use any cert that matches the domain you've specified on that router.
Basic Auth: Must define the middleware as one label, and then assign that middleware to your https router. And I suppose if you're not using HTTPS redirect then you could assign it to your http router but it wouldn't be secure obviously.
docker-compose.yml:
version: '3.8'
networks:
myweb:
external: true
services:
proxy:
image: traefik:v2.3.0-rc4-windowsservercore-1809
container_name: traefik
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
# Mount the certs drive
- ./traefik-ssl-certs/:c:/certs/
# Mount the config folder
- ./traefik-config/:c:/config/
# Mount the host docker engine pipe ("docker volume ls")
- source: '\\.\pipe\docker_engine'
target: '\\.\pipe\docker_engine'
type: npipe
command:
- --api=true
- --api.dashboard=true
- --api.insecure=false
# Register the traefik config directory as per: https://docs.traefik.io/providers/file/#directory
- --providers.file.directory=c:/config/
- --providers.file.watch=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
# Configure Docker provider
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --providers.docker.endpoint=npipe:////./pipe/docker_engine
- --providers.docker.network=myweb
- --providers.docker.watch=true
networks:
- myweb
labels:
- traefik.enable=true
- traefik.docker.network=myweb
# Define the service
- traefik.http.services.proxy.loadbalancer.server.port=8080
# Routing for dashboard HTTP
- traefik.http.routers.dash-http.service=api#internal
- traefik.http.routers.dash-http.rule=Host(`example.com`)
- traefik.http.routers.dash-http.entrypoints=web
# Routing for dashboard HTTPS
- traefik.http.routers.dash-https.service=api#internal
- traefik.http.routers.dash-https.rule=Host(`example.com`)
- traefik.http.routers.dash-https.entrypoints=websecure
- traefik.http.routers.dash-https.tls=true
# Http-to-Https redirect Middleware
- traefik.http.middlewares.dash-http2https.redirectscheme.scheme=https
- traefik.http.middlewares.dash-http2https.redirectscheme.permanent=true
- traefik.http.routers.dash-http.middlewares=dash-http2https
# BasicAuth for dashboard
# Windows doesn't have htpasswd command so I generated one here: https://hostingcanada.org/htpasswd-generator/
# As per Traefik documentation, escaped single $ char with $$ for the yml parser
# user/pass = admin/testpassword
- traefik.http.middlewares.api-auth.basicauth.users=admin:$$2y$$10$$mfWQ11K16V6gVK.8Y6q1Eeh765NZscmjCrjJlAtaWubEsjU8HLYOO
- traefik.http.routers.dash-https.middlewares=api-auth
remoteling:
image: remoteling:latest
container_name: remoteling
networks:
- myweb
labels:
- traefik.enable=true
- traefik.docker.network=myweb
# Define the service
- traefik.http.services.remoteling.loadbalancer.server.port=80
# Routing for remoteling HTTP
- traefik.http.routers.remoteling-http.service=remoteling
- traefik.http.routers.remoteling-http.entrypoints=web
- traefik.http.routers.remoteling-http.rule=Host(`services.example.com`)
# Routing for remoteling HTTPS
- traefik.http.routers.remoteling-https.service=remoteling
- traefik.http.routers.remoteling-https.entrypoints=websecure
- traefik.http.routers.remoteling-https.rule=Host(`services.example.com`)
- traefik.http.routers.remoteling-https.tls=true
# Http-to-Https redirect Middleware
- traefik.http.middlewares.remoteling-http2https.redirectscheme.scheme=https
- traefik.http.middlewares.remoteling-http2https.redirectscheme.permanent=true
- traefik.http.routers.remoteling-http.middlewares=remoteling-http2https
depends_on:
- proxy
Hopefully someone else finds that useful.

Traefik configuration with Docker not working

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

Traefik 2.0 behind docker swarm not working

So, I'm trying to use Traefik to load-balance my web apps via docker swarm.
However, I already tried many configurations but somehow not works. I already read the documentation and read some articles in the internet. Unfortunately, many articles references traefik 1.x instead traefik 2.0.
Here is my docker-stack.yml for traefik
version: '3.7'
services:
traefik:
image: traefik:2.0
deploy:
mode: global
placement:
constraints:
- node.role == manager
restart_policy:
condition: on-failure
labels:
- traefik.docker.network=load_balancer
configs:
- source: traefik
target: /etc/traefik/traefik.yml
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- load_balancer
configs:
traefik:
file: ./traefik.yml
networks:
load_balancer:
external: true
name: load_balancer
whoami.yml (for testing purpose)
version: '3.7'
services:
whoami:
image: containous/whoami
deploy:
labels:
- traefik.enable=true
- traefik.docker.network=load_balancer
- traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)
networks:
- load_balancer
networks:
load_balancer:
external: true
name: load_balancer
My traefik.yml
log:
level: DEBUG
api:
insecure: true
providers:
docker:
exposedByDefault: false
swarmMode: true
watch: true
docker network ls
hxjw9rytw3od load_balancer overlay swarm
curl -H Host:whoami.docker.localhost http://127.0.0.1
404 page not found
Maybe you have to add entrypoints declaration in your config: https://docs.traefik.io/routing/entrypoints/
I hope is not too late to answer this. I've found the solution.
First, you can either use traefik.yml for configuration or use traefik cli flags in docker-compose command field.
Here is the working approach if you use traefik.yml as your main configuration.
It is recommended to use directory over file.
traefik.yml
log:
level: DEBUG
api:
insecure: true
# This is required
entryPoints:
web:
address: ':80'
websecure:
address: ':443'
providers:
file: # Required, if you use traefik.yml as your main configuration
directory: /etc/traefik
watch: true
docker:
exposedByDefault: false
swarmMode: true
watch: true
Working approach if you use traefik cli flags
docker-compose.stack.yml
version: '3.7'
services:
traefik:
image: traefik:2.0
deploy:
mode: global
placement:
constraints:
- node.role == manager
restart_policy:
condition: on-failure
command:
- --log.level=DEBUG
- --api.insecure=true
- --ping=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker.swarmmode=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=load_balancer
- --providers.docker.watch=true
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- load_balancer
networks:
load_balancer:
external: true
name: load_balancer
whoami.yml (for testing purpose)
version: '3.7'
services:
whoami:
image: containous/whoami
deploy:
labels:
- traefik.enable=true
- traefik.docker.network=load_balancer
- traefik.http.routers.whoami.entrypoints=web
- traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)
- traefik.http.services.whoami.loadbalancer.server.port=80
networks:
- load_balancer
networks:
load_balancer:
external: true
name: load_balancer
Test via curl
curl -H Host:whoami.docker.localhost 127.0.0.1
I can suggest you to Not use traefik.yml but to use the cli args to configure your instance.
You can make it like this :
version: "3.7"
services:
ingress:
image: traefik:v2.0
networks:
- ingress-net
ports:
- "80:80"
- "443:443"
# TCP Port if needed for any service you have
- "60000:60000"
command:
### ###
# Traefik Global Configuration #
### ###
# Enable DEBUG logs
- "--log.level=DEBUG" # DEBUG, INFO, etc...
- "--ping=true"
# Enable api access without authentification (only GET route so it only possible to get IPs)
- "--api.insecure=true" # You can insecure here, because It accessible only in the container if you didn't open the port.
# Set the provider to Docker
- "--providers.docker=true"
# Set the docker network
- "--providers.docker.network=ingress-net"
# Set to docker swarm cluster
- "--providers.docker.swarmMode=true"
# If False : Do not expose containers to the web by default
- "--providers.docker.exposedByDefault=false"
# Default rule to service-name.example.com
- "--providers.docker.defaultRule=Host(`{{ trimPrefix `/` .Name }}.example.com`)"
# Default http port
- "--entrypoints.http.address=:80"
# Default https port
- "--entrypoints.https.address=:443"
# Enable let's encrypt
- "--certificatesResolvers.certbot=true"
- "--certificatesResolvers.certbot.acme.httpChallenge=true"
- "--certificatesResolvers.certbot.acme.httpChallenge.entrypoint=http"
- "--certificatesResolvers.certbot.acme.email=admin#example.com"
- "--certificatesResolvers.certbot.acme.storage=/letsencrypt/acme.json"
# TCP Entrypoint if needed
- "--entrypoints.tcpendpointname.address=:60000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./acme.json:/letsencrypt/acme.json
deploy:
replicas: 1
labels:
### ###
# Traefik Dashboard #
### ###
# Enable this endpoint
- traefik.enable=true
##
# Http
#
# Set the service route
- traefik.http.routers.ingress_http.rule=Host(`ingress.example.com`)
# Set the entrypoint (http or https)
- traefik.http.routers.ingress_http.entrypoints=http
# Rule to redirect to http to https
- traefik.http.middlewares.ingress-https-redirect.redirectscheme.scheme=https
# Enable Https redirection
- traefik.http.routers.ingress_http.middlewares=ingress-https-redirect#docker
#
##
##
# Https
#
- traefik.http.routers.ingress_https.rule=Host(`ingress.example.com`)
# Set the entrypoint (http or https)
- traefik.http.routers.ingress_https.entrypoints=https
# Enable Let's encrypt auto certificat creation
- traefik.http.routers.ingress_https.tls.certresolver=certbot
# Enable authentification
- traefik.http.routers.ingress_https.middlewares=ingress-auth#
# Uncommant this to enable basic authentification
# - traefik.http.middlewares.ingress-auth.basicauth.users=admin:$$this$$is$$encrypted$$password
#
##
##
# TCP Endpoint
#
# Set the service route
- "traefik.tcp.routers.tcpendpointname.rule=HostSNI(`*`)"
# Here you can set the host uri if you use tls only.
# - "traefik.tcp.routers.tcpendpointname.rule=HostSNI(`tcp.example.com`)"
# - "traefik.tcp.routers.tcpendpointname.tls=true"
# Set the entrypoin
- "traefik.tcp.routers.tcpendpointname.entrypoints=tcpendpointname"
#
##
##
# Service
#
# Set the service port
- traefik.http.services.ingress.loadbalancer.server.port=8080
#
##
placement:
constraints:
- node.role == manager
networks:
ingress-net:
external: true
I hope this will Help you.
You can use the same labels for any other containers, that work with the same logic.
Since you've got a 404 page not found Traefik seems to be available.
However, when using curl to fetch http://127.0.0.1 this IP address is going to be content of request's Host header field. This in turn is used by Traefik for routing the request. Since your whoami service is meant to match requests for Host whoami.docker.localhost this given response of Traefik is just fine.
Have you tried fetching http://whoami.docker.localhost instead? You might need to inject this hostname into hosts /etc/hosts files prior to testing with curl.
127.0.0.1 whoami.docker.localhost
Optionally, you can try manual HTTP request with a tool like netcat (sometimes available as nc):
# netcat 127.0.0.1 80
GET / HTTP/1.0
Host: whoami.docker.localhost
You need to press Enter twice after entering second line of request as required by HTTP.
Port Detection
Docker Swarm does not provide any port detection information to Traefik.
Therefore you must specify the port to use for communication by using the label traefik.http.services.<service_name>.loadbalancer.server.port (Check the reference for this label in the routing section for Docker).
Traefik's service discovery with Docker requires container labels instead of image labels (check traefik's quickstart).
The following minimal working example works on docker swarm:
version: '3.7'
services:
traefik:
image: traefik:2.0
command: --providers.docker
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
whoami:
image: containous/whoami
labels: # defining a container label instead of an image label
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

Resources