I meet some problems using traefik with docker and I don't know why.
With some containers, it's works like a charm and for other ones, I have an error when I try to access to these ones : Bad gateway (error 502).
Here is my traefik.toml :
# Service logs (here debug mode)
debug = true
logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
# Access log
filePath = "/var/log/traefik/access.log"
format = "common"
################################################################
# Web configuration backend
################################################################
[web]
address = ":8080"
################################################################
# Entry-points configuration
################################################################
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
################################################################
# Docker configuration backend
################################################################
[docker]
domain = "domain.tld"
watch = true
exposedbydefault = false
endpoint = "unix:///var/run/docker.sock"
################################################################
# Let's encrypt
################################################################
[acme]
email = "admin#domain.tld"
storageFile = "acme.json"
onDemand = false
onHostRule = true
entryPoint = "https"
[acme.httpChallenge]
entryPoint = "http"
[[acme.domains]]
main = "domain.tld"
sans = ["docker.domain.tld", "traefik.domain.tld", "phpmyadmin.domain.tld", "perso.domain.tld", "muximux.domain.tld", "wekan.domain.tld", "wiki.domain.tld", "cloud.domain.tld", "email.domain.tld"]
Here is my docker-compose.yml (for portainer, which is a container which works) :
version: '2'
services:
portainer:
restart: always
image: portainer/portainer:latest
container_name: "portainer"
#Automatically choose 'Manage the Docker instance where Portainer is running' by adding <--host=unix:///var/run/docker.sock> to the command
ports:
- "9000:9000"
networks:
- traefik-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ../portainer:/data
labels:
- traefik.enable=true
- traefik.backend=portainer
- traefik.frontend.rule=Host:docker.domain.tld
- traefik.docker.network=traefik-network
- traefik.port=9000
- traefik.default.protocol=http
networks:
traefik-network:
external : true
If I go to docker.domain.tld, it works ! and in https, with valide let's encrypt certificate :)
Here is my docker-compose.yml (for dokuwiki, which is a container which does not work) :
version: '2'
services:
dokuwiki:
container_name: "dokuwiki"
image: bitnami/dokuwiki:latest
restart: always
volumes:
- ../dokuwiki/data:/bitnami
ports:
- "8085:80"
- "7443:443"
networks:
- traefik-network
labels:
- traefik.backend=dokuwiki
- traefik.docker.network=traefik-network
- traefik.frontend.rule=Host:wiki.domain.tld
- traefik.enable=true
- traefik.port=8085
- traefik.default.protocol=http
networks:
traefik-network:
external: true
If I go to wiki.domain.tld, it does not work ! I have a bad gateway error on the browser. I have tried to change the traefik.port to 7443 and the traefik.default.protocol to https but I have the same error. Of course it works when I try to access the wiki with the IP and the port (in http / https). I have bad gateway only when I type wiki.domain.tld.
So, I don't understand why it works for some containers and not for other ones with the same declaration.
The traefik port should be the http port of the container, not the published port on the host. It communicates over the docker network, so publishing the port is unnecessary and against the goals of only having a single port published with a reverse proxy to access all the containers.
In short, you need:
traefik.port=80
Since this question has gotten lots of views, the other reason lots of people see a 502 from traefik is placing the containers on a different docker network from the traefik instance, or having a container on multiple networks and not telling traefik which network to use. This doesn't apply in your case since you have the following lines in your compose file that match up with the traefik service's network:
services:
dokuwiki:
networks:
- traefik-network
labels:
- traefik.docker.network=traefik-network
networks:
traefik-network:
external : true
Even if you only assign a service to a single network, some actions like publishing a port will result in your service being attached to two different networks (the ingress network being the second). The network name in the label needs to be the external name, which in your case is the same, but for others that do not specify their network as external, it may have a project or stack name prefixed which you can see in the docker network ls output.
traefik.docker.network must also be the fully qualified network name. Either externally defined, or prefixed with the stack name.
You can alternatively define a default network with providers.docker.network=traefik-network which means you don't have to add the label to every container.
Verify Apply:
firewall-cmd --add-masquerade --permanent
FROM: https://www.reddit.com/r/linuxadmin/comments/7iom6e/what_does_firewallcmd_addmasquerade_do/
Masquerading is a fancy term for Source NAT.
firewall-cmd in this instance will be adding an iptables rule,
specifically to the POSTROUTING chain in the nat table.
You can see what it has actually done by running iptables -t nat -nvL
POSTROUTING. A typical command to manually create a masquerading rule
would be iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE, which
translates to "For packets leaving interface eth0 after they have been
routed, change their source address to the interface address of eth0".
This automatically adds a connection tracking entry so that packets
for connections that are masqueraded in this way have their original
address and port information reinstated as they return back through
the system.
None of this makes your Linux system into a router; that is separate
behaviour which is enabled (for IPv4) either by doing sysctl -w
net.ipv4.ip_forward=1 or echo 1 > /proc/sys/net/ipv4/ip_forward.
Routing simply means that the system will dumbly traffic it receives
according to the destination of that traffic; the iptables NAT stuff
allows you to alter the packets which are emitted after that routing
takes place.
This is a really simple overview and there is a lot more complexity
and possibilities available by configuring it in different ways.
Related
Running Docker 18.09.7ce with Docker API v1.39 on Ubuntu 18.04 LTS.
I'm trying to set up Traefik 2.2 as a reverse proxy for some swarm services but for some reason Traefik can't connect to the Docker daemon via the TCP port given in the Traefik documentation. These three error messages keep repeating.
level=debug msg="FIXME: Got an status-code for which error does not match any expected type!!!: -1" status_code=-1 module=api
level=error msg="Failed to retrieve information of the docker client and server host: Cannot connect to the Docker daemon at tcp://127.0.0.1:2377. Is the docker daemon running?" providerName=docker
level=error msg="Provider connection error Cannot connect to the Docker daemon at tcp://127.0.0.1:2377. Is the docker daemon running?, retrying in 1.461723532s" providerName=docker
It's running on a manager node (I only have one node) and the swarm is working fine, with the API exposed via that TCP port, as shown by the output of the following command.
$ sudo ss --tcp --listening --processes --numeric | grep ":2377"
LISTEN 0 128 *:2377 *:* users:(("dockerd",pid=30747,fd=23))
My architecture is based on this blog post, with a shared overlay network called proxy created with docker network create --driver=overlay proxy.
I tried this but it didn't work, and I can't really find any other related questions. Here are my configuration files:
traefik.toml
[providers.docker]
endpoint = "tcp://127.0.0.1:2377"
swarmMode = true
network = "proxy"
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web-secure]
address = ":443"
[certificatesResolvers.le.acme]
email = "my-email#email.com"
storage = "/letsencrypt/acme.json"
caserver = "https://acme-staging-v02.api.letsencrypt.org/directory" # For testing
[certificatesResolvers.le.acme.httpChallenge]
entryPoint = "web"
[log]
level = "DEBUG"
traefik.yml
version: "3.7"
services:
reverse-proxy:
deploy:
placement:
constraints:
- node.role == manager
image: "traefik:v2.2"
ports:
- 80:80
- 443:443
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "/path/to/traefik.toml:/etc/traefik/traefik.toml"
- "letsencrypt:/letsencrypt"
networks:
- "proxy"
networks:
proxy:
external: true
volumes:
letsencrypt:
The only difference I can see is that the blog does not explicitly define an endpoint for the dockers provider. Maybe to removing that?
I have a MQTT broker started via docker-compose and managed by traefik:
mqtt:
container_name: mqtt
image: eclipse-mosquitto
restart: always
labels:
- 'traefik.port=1883'
- 'traefik.frontend.rule=Host:mqtt2.ex.com'
- 'traefik.frontend.entryPoints=mqtt'
ports:
- 3883:1883
The relevant part of traefik.toml where I am trying to set up the backend:
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.mqtt]
address = ":2884"
[tcp] # YAY!
[tcp.routers]
[tcp.routers.mqtt]
entrypoints = ["mqtt"]
rule = "HostSNI(`*`)" # Catches every request
service = "mqtt"
[tcp.services]
[tcp.services.mqtt.LoadBalancer]
I can access the broker via port `3883` but this is not what I intend to do (the exposed port above is just to make sure that the container is OK): I would like to proxy it though `traefik` like all my other **HTTP** services.
This however is not a HTTP service, it is a TCP one and my problem is that **I do not know how to configure such a TCP backend**.
The documentation is very light on that feature, it just states that
Currently, LoadBalancer is the only supported kind of TCP Service.
However, since Traefik is an ever evolving project, other kind of TCP
Services will be available in the future, reason why you have to
specify it.
What does this means in terms of configuring the backend? What should I add to either docker-compose.yaml or traefik.toml so that the backend is recognized as a TCP service? For the moment, it is seen as a HTTP one and the proxification does not work:
I'm trying to deploy a private repository on my docker swarm.
I'm following the official docker repository guide to deploy it as a service. I want to be able to use it with https, from outside with a simple url as https://myregistry.mysite.com.
To do so I use following traefik labels in my stack yml file :
traefik.backend: "privateregistry"
traefik.docker.network: "webgateway" # docker overlay external
traefik.enable: "true"
traefik.frontend.entryPoint: "https"
traefik.frontend.redirect.entryPoint: "https"
traefik.frontend.rule: "Host:myregistry.mysite.com"
traefik.port: "5000"
I'm seeing my two frontend/backend in traefik UI but when I access to https://myregistry.mysite.com/v2/ (for example) I've a 500 fatal error. The service log output is
http: TLS handshake error from 10.0.0.68:47796: tls: first record does not look like a TLS handshake
I think I misunderstood something, certs side probably.
Any idea to do that without error ?
Thanks
I suppose you are missing the certificate of the (registry-) server on your client machine. I assume you have two certificate files (used on the server):
myregistry.mysite.com.crt
myregistry.mysite.com.key
Copy myregistry.mysite.com.crt on your client machine to /etc/docker/certs.d/myregistry.mysite.com/ca.crt on Linux or
~/.docker/certs.d/myregistry.mysite.com/ca.crt on Mac. Now you should be able to login from the client:
docker login myregistry.mysite.com
Appendix - Server Setup
Your server setup might look like this:
~/certs/myregistry.mysite.com.crt
~/certs/myregistry.mysite.com.key
~/docker-compose.yml
~/traefik.toml
docker-compose.yml
version: '3'
services:
frontproxy:
image: traefik
command: --api --docker --docker.swarmmode
ports:
- "80:80"
- "443:443"
volumes:
- ./certs:/etc/ssl:ro
- ./traefik.toml:/etc/traefik/traefik.toml:ro
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
docker-registry:
image: registry:2
deploy:
labels:
- traefik.port=5000 # default port exposed by the registry
- traefik.frontend.rule=Host:myregistry.mysite.com
traefik.toml
defaultEntryPoints = ["http", "https"]
# Redirect HTTP to HTTPS and use certificate, see https://docs.traefik.io/configuration/entrypoints/
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/etc/ssl/myregistry.mysite.com.crt"
keyFile = "/etc/ssl/myregistry.mysite.com.key"
# Docker Swarm Mode Provider, see https://docs.traefik.io/configuration/backends/docker/#docker-swarm-mode
[docker]
endpoint = "tcp://127.0.0.1:2375"
domain = "docker.localhost"
watch = true
swarmMode = true
To deploy your registry run:
docker stack deploy myregistry -c ~/docker-compose.yml
I am running a single node swarm, I am using traefik to manage all my external connections, and I want to run a registry such that I can connect to it at registry.myhost.com
Now all the examples I can see suggest creating a registry as a normal container rather than a service, however when I do this, I do not have the ability to add it to my traefik network and thus enable it to be found externally.
Do I need to create another internal network and connect both traefik and it to it, and if so, what type. Or do I need to run the registry as a service (I'm only on a single node so volume shouldnt be much of an issue).
And for bonus points, can anyone give me some pointers on how to set it up with s3 as a storage backend?
Overview
You have two machines:
Server: Your (single) Docker Swarm manager node that runs traefik and other Docker containers like the registry.
Client: Another machine that should be able to connect to the registry and push Docker images to it.
I assume you have two certificate files:
registry.myhost.com.crt
registry.myhost.com.key
Server
Your server setup might look like this:
~/certs/registry.myhost.com.crt
~/certs/registry.myhost.com.key
~/docker-compose.yml
~/traefik.toml
docker-compose.yml
version: '3'
services:
frontproxy:
image: traefik
command: --api --docker --docker.swarmmode
ports:
- "80:80"
- "443:443"
volumes:
- ./certs:/etc/ssl:ro
- ./traefik.toml:/etc/traefik/traefik.toml:ro
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
docker-registry:
image: registry:2
deploy:
labels:
- traefik.port=5000 # default port exposed by the registry
- traefik.frontend.rule=Host:registry.myhost.com
- traefik.frontend.auth.basic=user:$$apr1$$9Cv/OMGj$$ZomWQzuQbL.3TRCS81A1g/ # user:password, see https://docs.traefik.io/configuration/backends/docker/#on-containers
traefik.toml
defaultEntryPoints = ["http", "https"]
# Redirect HTTP to HTTPS and use certificate, see https://docs.traefik.io/configuration/entrypoints/
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/etc/ssl/registry.myhost.com.crt"
keyFile = "/etc/ssl/registry.myhost.com.key"
# Docker Swarm Mode Provider, see https://docs.traefik.io/configuration/backends/docker/#docker-swarm-mode
[docker]
endpoint = "tcp://127.0.0.1:2375"
domain = "docker.localhost"
watch = true
swarmMode = true
To deploy your registry run:
docker stack deploy myregistry -c ~/docker-compose.yml
Add Another Stack
If your service is not defined in the same docker-compose.yml as traefik you can use the (external) network of the traefik service:
version: '3'
services:
whoami:
image: emilevauge/whoami # A container that exposes an API to show its IP address
networks:
- frontproxy_default # add network of traefik service "frontproxy"
- default
deploy:
labels:
traefik.docker.network: frontproxy_default
traefik.frontend.rule: Host:whoami.myhost.com
traefik.frontend.auth.basic: user:$$apr1$$9Cv/OMGj$$ZomWQzuQbL.3TRCS81A1g/ # user:password, see https://docs.traefik.io/configuration/backends/docker/#on-containers
networks:
frontproxy_default:
external: true # network of traefik service "frontproxy" is defined in another stack
Make sure you add the certificate files of whoami.myhost.com to traefik.toml:
[[entryPoints.https.tls.certificates]]
certFile = "/etc/ssl/registry.myhost.com.crt"
keyFile = "/etc/ssl/registry.myhost.com.key"
[[entryPoints.https.tls.certificates]]
certFile = "/etc/ssl/whoami.myhost.com.crt"
keyFile = "/etc/ssl/whoami.myhost.com.key"
or use a (single) wildcard certificate *.myhost.com
[[entryPoints.https.tls.certificates]]
certFile = "/etc/ssl/myhost.com.crt"
keyFile = "/etc/ssl/myhost.com.key"
See https://docs.traefik.io/configuration/entrypoints/ for further information.
Client
Copy registry.myhost.com.crt on your client machine to /etc/docker/certs.d/registry.myhost.com/ca.crt on Linux or
~/.docker/certs.d/registry.myhost.com/ca.crt on Mac. Now you should be able to login from the client:
docker login -u user -p password registry.myhost.com
Copy an image from Docker Hub to your registry
On your client run:
docker pull hello-world:latest
docker tag hello-world:latest registry.myhost.com/hello-world:latest
docker push registry.myhost.com/hello-world:latest
Now you can pull this image on another machine (for example on the server):
docker pull registry.myhost.com/hello-world:latest
Don't forget to add registry.myhost.com.crt on that client machine, too.
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.