traefik loadbalancer server port - docker

i have a few services in my docker-compose file using traefik labels.
now i would like to clean this file and start using traefik yaml files.
the problem is that i could not find the equivalent to traefik.http.services.dnsmasq-traefik.loadbalancer.server.port=5380
and there arent any examples in the docs
the labels (this works perfectly)
- "traefik.http.routers.dnsmasq.rule=Host(`dnsmasq.docker.localdomain`)"
- "traefik.http.routers.dnsmasq.service=dnsmasq-traefik#docker"
- "traefik.http.services.dnsmasq-traefik.loadbalancer.server.port=5380"
the yaml (not working, gives me a Gateway Timeout)
http:
routers:
dnsmasq-preauth:
entryPoints: [http]
middlewares: [redirect-to-http]
service: dnsmasq-preauth
rule: Host(`dnsmasq.docker.localdomain`)
services:
dnsmasq-preauth:
loadBalancer:
servers:
- url: "http://dnsmasq.docker.localdomain:5380"

Whenever I get this Gateway timeout issue I immediately look in two places:
The Traefik Config needs to be exposedByDefault - docs here
providers:
docker:
exposedByDefault: false
# ...
If exposedByDefault is false then you need to do #2 in this list.
On your specific container you need to set the docker labels
- traefik.enable=true

Related

Traefik v2 reverse proxy to a local server outside Docker

I have a simple server written in Python that listens on port 8000 inside a private network (HTTP communication). There is now a requirement to switch to HTTPS communications and every client that sends a request to the server should get authenticated with his own cert/key pair.
I have decided to use Traefik v2 for this job. Please see the block diagram.
Traefik runs as a Docker image on a host that has IP 192.168.56.101. First I wanted to simply forward a HTTP request from a client to Traefik and then to the Python server running outside Docker on port 8000. I would add the TLS functionality when the forwarding is running properly.
However, I can not figure out how to configure Traefik to reverse proxy from i.e. 192.168.56.101/notify?wrn=1 to the Python server 127.0.0.1:8000/notify?wrn=1.
When I try to send the above mentioned request to the server (curl "192.168.56.101/notify?wrn=1") I get "Bad Gateway" as an answer. What am I missing here? This is the first time that I am in contact with Docker and reverse proxy/Traefik. I believe it has something to do with ports but I can not figure it out.
Here is my Traefik configuration:
docker-compose.yml
version: "3.3"
services:
traefik:
image: "traefik:v2.1"
container_name: "traefik"
hostname: "traefik"
ports:
- "80:80"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik.yml:/traefik.yml:ro"
traefik.yml
## STATIC CONFIGURATION
log:
level: INFO
api:
insecure: true
dashboard: true
entryPoints:
web:
address: ":80"
providers:
docker:
watch: true
endpoint: "unix:///var/run/docker.sock"
file:
filename: "traefik.yml"
## DYNAMIC CONFIGURATION
http:
routers:
to-local-ip:
rule: "Host(`192.168.56.101`)"
service: to-local-ip
entryPoints:
- web
services:
to-local-ip:
loadBalancer:
servers:
- url: "http://127.0.0.1:8000"
First, 127.0.0.1 will resolve to the traefik container and not to the docker host. You need to provide a private IP of the node and it needs to be accessible form the traefik container.
There is some workaround to make proxy to localhost:
change 127.0.0.1 to IP of docker0 interface
It should be 172.17.0.1
and then try to listen your python server on all interfaces (0.0.0.0)
if you use simple python http server nothing change... on default it listen on all interfaces

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/

Traefik Bad Gateway

I've got some strange issue. I have following setup:
one docker-host running traefik as LB serving multiple sites. sites are most php/apache. HTTPS is managed by traefik.
Each site is started using a docker-compose YAML containing the following:
version: '2.3'
services:
redis:
image: redis:alpine
container_name: ${PROJECT}-redis
networks:
- internal
php:
image: registry.gitlab.com/OUR_NAMESPACE/docker/php:${PHP_IMAGE_TAG}
environment:
- APACHE_DOCUMENT_ROOT=${APACHE_DOCUMENT_ROOT}
container_name: ${PROJECT}-php-fpm
volumes:
- ${PROJECT_PATH}:/var/www/html:cached
- .docker/php/php-ini-overrides.ini:/usr/local/etc/php/conf.d/99-overrides.ini
ports:
- 80
networks:
- proxy
- internal
labels:
- traefik.enable=true
- traefik.port=80
- traefik.frontend.headers.SSLRedirect=false
- traefik.frontend.rule=Host:${PROJECT}
- "traefik.docker.network=proxy"
networks:
proxy:
external:
name: proxy
internal:
(as PHP we use 5.6.33-apache-jessie or 7.1.12-apache f.e.)
Additionally to above, some sites get following labels:
traefik.docker.network=proxy
traefik.enable=true
traefik.frontend.headers.SSLRedirect=true
traefik.frontend.rule=Host:example.com, www.example.com
traefik.port=80
traefik.protocol=http
what we get is that some requests end in 502 Bad Gateway
traefik debug output shows:
time="2018-03-21T12:20:21Z" level=debug msg="vulcand/oxy/forward/http: Round trip: http://172.18.0.8:80, code: 502, Length: 11, duration: 2.516057159s"
can someone help with that?
it's completely random when it happens
our traefik.toml:
debug = true
checkNewVersion = true
logLevel = "DEBUG"
defaultEntryPoints = ["https", "http"]
[accessLog]
[web]
address = ":8080"
[web.auth.digest]
users = ["admin:traefik:some-encoded-pass"]
[entryPoints]
[entryPoints.http]
address = ":80"
# [entryPoints.http.redirect] # had to disable this because HTTPS must be enable manually (not my decission)
# entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[retry]
[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "example.com"
watch = true
exposedbydefault = false
[acme]
email = "info#example.com"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
Could the issue be related to using the same docker-compose.yml?
Another reason can be that you might be accidentally mapping to the vm's port instead of the container port.
I made a change to my port mapping on the docker-compose file and forgot to update the labeled port so it was trying to map to a port on the machine that was not having any process attached to it
Wrong way:
ports:
- "8080:8081"
labels:
- "traefik.http.services.front-web.loadbalancer.server.port=8080"
Right way
ports:
- "8080:8081"
labels:
- "traefik.http.services.front-web.loadbalancer.server.port=8081"
Also in general don't do this, instead of exposing ports try docker networks they are much better and cleaner. I made my configuration documentation like a year ago and this was more of a beginner mistake on my side but might help someone :)
For anyone getting the same issue:
After recreating the network (proxy) and restarting every site/container it seems to work now.
I still don't know where the issue was from.
If you see Bad Gateway with Traefik chances are you have a Docker networking issue. First have a look at this issue and consider this solution. Then take a look at providers.docker.network (Traefik 2.0) or, in your case, the docker.network setting (Traefik 1.7).
You could add a default network here:
[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "example.com"
watch = true
exposedbydefault = false
network = "proxy"
Or define/override it for a given service using the traefik.docker.network label.
Got the same problem and none of the above mentioned answers solved it for me. In my case a wrong loadbalancer was added. Removing the label or changing it to the correct port made the trick.
- "traefik.http.services.XXX.loadbalancer.server.port=XXX"
In your example you don't have traefik enabled:
traefik.enable=false
Make sure to enable it first and then test your containers.
The error "bad gateway" is returned when the web server in the container doesn't allow traffic from traefik e.g. because of wrong interface binding like localhost instead of 0.0.0.0.
Take Ruby on Rails for example. Its web server puma is configured by default like this (see config/puma.rb):
port ENV.fetch("PORT") { 3000 }
But in order to allow access from traefik puma must bind to 0.0.0.0 like so:
bind "tcp://0.0.0.0:#{ ENV.fetch("PORT") { 3000 } }"
This solved the problem for me.
Another cause can be exposing a container at a port that Traefik already uses.
I forgot to expose the port in my Dockerfile thats why traefik did not find a port to route to. So expose the port BEFORE you start the application like node:
#other stuff before...
EXPOSE 3000
CMD ["node", "dist/main" ]
Or if you have multiple ports open you have to specify which port traefik should route the domain to with:
- "traefik.http.services.myservice.loadbalancer.server.port=3000"
Or see docs
I faced very close issue to this exception my problem was not related to network settings or config, after time we figured out that the exposed port from the backend container is not like the port we mapping to to access form outside the service port was 5000 and we mapped 9000:9000 the solution was to fix the port issue first 9000:5000.

routing to other containers using zuul in docker

I am running two microservices say demo1 and demo2 in two containers using docker. I have configured zuul in demo1. I want to route from demo1 to demo2 that is, I want to access the api in demo2 from demo1.
demo1 is running on port 8080 and demo2 on port 8030 and I want to access the api like this- "localhost:8030/zuultest/test". But the routing is not working. It works fine if I access the demo1 like "localhost:8080/test".
Here is my zuul configuration in application.yml-
server:
port: 8030
#TODO: figure out why I need this here and in bootstrap.yml
spring:
application:
name: zuul server
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
zuul:
routes:
zuultest:
url: http://localhost:8080
stripPrefix: false
ribbon:
eureka:
enabled: false
you can use links option in the docker-compose.yml to link between the two containers.
demo1:
image: <demo1 image name>
links:
- demo2
demo2:
image: <demo2 image name>
Then in the zuul:routs:url configuration you can use the conatiner name, demo2 instead of it's IP.
you also need to ensure that the ports in question are open and accessible from external machine as well.
better still you may route the traffic from port 8080 (default open port ) to the desired port , 8030 in your case.
For explicitly exposing the port, please refer the link:
https://github.com/wsargent/docker-cheat-sheet#exposing-ports

Resources