Traefik 2.0 behind docker swarm not working - docker-swarm

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`)"

Related

Traefik reverse proxy service into sub folder that doesn't allow BASE URL changing

I recently got into self hosting, I found tailscale to be the best way to access the services that i want on all my devices but typing ports is getting real annoying and I am trying a to enable SSL for some of the important services.
Now most guides on reverse hosting say to use subdomains but I don't want to and thus want to make them accessible in sub-folders instead of sub-domains.
I have been trying to set up a reverse proxy to do that now I have tried Nginx proxy-manager, Caddy and Traefik out of which I found Traefik being the easiest to understand as noob.
I am trying to reverse proxy stuff using traefik to some success, simple services like the ones which have one page work but for bigger services it doesn't work.
This is my traefik docker-compose.yml
version: "3"
networks:
# network created for reverse proxy such that all other
# containers are also on it can communicate with each other
revProxy-net:
name: revProxy-net
driver: bridge
services:
traefik:
image: traefik:v3.0.0-beta2
container_name: traefik
ports:
- 80:80
- 443:443
- 8080:8080
volumes:
- ./config:/etc/traefik
- ./logs:/var/log/traefik
- /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
- /var/run/docker.sock:/var/run/docker.sock
networks:
- revProxy-net
restart: unless-stopped
and this is the traefik.yml
global:
checkNewVersion: true
sendAnonymousUsage: false # true by default
# (Optional) Log information
# ---
log:
level: ERROR # DEBUG, INFO, WARNING, ERROR, CRITICAL
format: common # common, json, logfmt
filePath: /var/log/traefik/traefik.log
# (Optional) Accesslog
# ---
accesslog:
format: common # common, json, logfmt
filePath: /var/log/traefik/access.log
# (Optional) Enable API and Dashboard
# ---
api:
dashboard: true # true by default
insecure: true # Don't do this in production!
# Entry Points configuration
# ---
entryPoints:
web:
address: :80
# (Optional) Redirect to HTTPS
# ---
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: :443
certificatesResolvers:
tailsolver:
tailscale: {}
providers:
docker:
exposedByDefault: false # Default is true
file:
# watch for dynamic configuration changes
directory: /etc/traefik
watch: true
Lets take glances a simple (it has only one html and one js file that loads), which works with this configuration, it is accessible on https://lenovo-ideapad-320-15ikb.tail9ece4.ts.net/glances/
version: "3"
services:
glances:
image: nicolargo/glances:latest-full
container_name: glances
restart: always
ports:
- 61208-61209:61208-61209
environment:
- GLANCES_OPT=-w
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./glances.conf:/etc/glances.conf
pid: host
networks:
- revProxy-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.glances.entrypoints=web,websecure"
- "traefik.http.routers.glances.rule=Host(`lenovo-ideapad-320-15ikb.tail9ece4.ts.net`) && PathPrefix(`/glances`)"
- "traefik.http.middlewares.strip-glances.stripprefix.prefixes=/glances"
- "traefik.http.routers.glances.middlewares=strip-glances#docker"
- "traefik.http.routers.glances.tls=true"
- "traefik.http.routers.glances.tls.certresolver=tailsolver"
- "traefik.http.routers.glances.tls.domains[0].main=lenovo-ideapad-320-15ikb.tail9ece4.ts.net"
networks:
revProxy-net:
external: true
But when i try to use this same thing on jellyfin, it gives Bad Gateway when going to https://lenovo-ideapad-320-15ikb.tail9ece4.ts.net/jellyfin/ ,Here is the jellyfin docker-compose.yml
version: "2.1"
#name: media-stack
services:
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
container_name: jellyfin
environment:
- PUID=1000
- PGID=1000
- TZ=${TZ_NAME}
#- JELLYFIN_PublishedServerUrl=192.168.0.25 #optional
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
volumes:
- ./jellyfin/config:/config
- /home/sagnik/Projects/yt-diff/yt-dlp/:/yt-dlp
# Removed for testing purposes
ports:
- ${JELLYFIN_PORT}:8096
- 8920:8920
- 7359:7359/udp
- 1900:1900/udp
deploy:
resources:
reservations:
devices:
- capabilities: [ gpu ]
restart: unless-stopped
labels:
- 'traefik.enable=true'
## HTTP Router
#### Entry point where Jellyfin is accessible via
#### Change secure to https in the line below to have accessible without needing to specify a port and change the SSLHost option below
- 'traefik.http.routers.jellyfin.entryPoints=web,websecure'
#### Host or Path where Jellyfin is accessible
#### Remove (or change) this rule if you'd rather have Jellyfin accessible at a PathPrefix URI
- 'traefik.http.routers.jellyfin.rule=Host(`lenovo-ideapad-320-15ikb.tail9ece4.ts.net`) && PathPrefix(`/jellyfin`)'
#### Prefix stripper
- "traefik.http.middlewares.strip-jellyfin.stripprefix.prefixes=/jellyfin"
- "traefik.http.routers.jellyfin.middlewares=strip-jellyfin#docker"
#### Using the tailscale ones
- "traefik.http.routers.jellyfin.tls=true"
- "traefik.http.routers.jellyfin.tls.certresolver=tailsolver"
- "traefik.http.routers.jellyfin.tls.domains[0].main=lenovo-ideapad-320-15ikb.tail9ece4.ts.net"
networks:
- revProxy-net
networks:
revProxy-net:
external: true
I have tried reading the documentation, and reading the ways to change base url for some services but I don't understand what is happening.
You forgot about the port!
- 'traefik.http.routers.jellyfin.service=jellyfin-svc'
- 'traefik.http.services.jellyfin-svc.loadBalancer.server.port=8096'

How to set a DDNS in Traefik host?

I am new in Traefik and I am using that to make the reverse proxy for my docker images, and I want to use my local computer like a server that could be accessed externally.
Here is what I did:
I create a DDNS pointing to my external ip in No-Ip:
Host-name: myhost.ddns.net
Target/ip: my-external-ip
Type: A
I want to use Traefik, so I want to expose the http default port (80) and https default port (443), so I made the port-forward in my router:
Doing that, I expect that http or https requests is being redirect to my internal host, that is the one which is the server of my application
Create the docker-compose.yml and traefik.yml files:
docker-compose.yml:
version: '3.7'
services:
traefik:
image: traefik:v2.0.1
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- external
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.myhost.ddns.net`)"
- "traefik.http.middlewares.traefik-auth.basicauth.users=*user:password*
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.myhost.ddns.net`)"
# - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=http"
- "traefik.http.routers.traefik-secure.service=api#internal"
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
*another-services-configs...*
networks:
external:
external: true
traefik.yml:
api:
dashboard: true
# Writing Logs to a File, in JSON
log:
level: DEBUG
filePath: "log-file.log"
format: json
# Configuring a buffer of 100 lines
accessLog:
filePath: "log-access.log"
bufferingSize: 100
entryPoints:
http:
address: ":80"
https:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
certificatesResolvers:
http:
acme:
email: my-email#hotmail.com
storage: acme.json
httpChallenge:
entryPoint: http
Finally, when I run docker-compose up -d , the application goes on, but I can not acess the traefik dashboard when I try to access traefik.myhost.ddns.net in the browser. The error message is that could not be found any web site with that host.
But, if I change the Host-name in the label to - traefik.http.routers.traefik.rule=Host('traefik.localhost')" , I can access the traefik dashboard typing traefik.localhost in the browser.
The question is, how can I use my ddns in the Host label to be able to access my traefik server externally?

Docker Swarm - Requests fail to reach a service on a different node

I've setup a Docker Swarm with Traefik v2 as the reverse proxy, and have been able to access the dashboard with no issues.
I am having an issue where I cannot get a response from any service that runs on a different node to the node Traefik is running on. I'm been testing and researching and presuming it's a network issue of some type.
I've done some quick testing with a empty Nginx image and was able to deploy another stack and get a response if the image was on the same node. Other stacks on the swarm which deploy across multiple nodes (but not including the Traefik node) are able to communicate to each other without issues).
Here is the test stack to provide some context of what I was using.
version: '3.8'
services:
test:
image: nginx:latest
deploy:
replicas: 1
placement:
constraints:
- node.role==worker
labels:
- "traefik.enable=true"
- "traefik.docker.network=uccser-dev-public"
- "traefik.http.services.test.loadbalancer.server.port=80"
- "traefik.http.routers.test.service=test"
- "traefik.http.routers.test.rule=Host(`TEST DOMAIN`) && PathPrefix(`/test`)"
- "traefik.http.routers.test.entryPoints=web"
networks:
- uccser-dev-public
networks:
uccser-dev-public:
external: true
The uccser-dev-public network is an overlay network across all nodes, with no encryption.
If I added a constraint to specify the Traefik node, then the requests worked with no issues. However, if I switched it to a different node, I get the Traefik 404 page.
The Traefik dashboard is showing it sees the service.
However the access logs show the following:
proxy_traefik.1.6fbx58k4n3fj#SWARM_NODE | IP_ADDRESS - - [21/Jul/2021:09:03:02 +0000] "GET / HTTP/2.0" - - "-" "-" 1430 "-" "-" 0ms
It's just blank, and I don't know where to proceed from here. The normal log shows no errors that I can see.
Traefik stack file:
version: '3.8'
x-default-opts:
&default-opts
logging:
options:
max-size: '1m'
max-file: '3'
services:
# Custom proxy to secure docker socket for Traefik
docker-socket:
<<: *default-opts
image: tecnativa/docker-socket-proxy
networks:
- traefik-docker
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
NETWORKS: 1
SERVICES: 1
SWARM: 1
TASKS: 1
deploy:
placement:
constraints:
- node.role == manager
# Reverse proxy for handling requests
traefik:
<<: *default-opts
image: traefik:2.4.11
networks:
- uccser-dev-public
- traefik-docker
volumes:
- traefik-public-certificates:/etc/traefik/acme/
ports:
- target: 80 # HTTP
published: 80
protocol: tcp
mode: host
- target: 443 # HTTPS
published: 443
protocol: tcp
mode: host
command:
# Docker
- --providers.docker
- --providers.docker.swarmmode
- --providers.docker.endpoint=tcp://docker-socket:2375
- --providers.docker.exposedByDefault=false
- --providers.docker.network=uccser-dev-public
- --providers.docker.watch
- --api
- --api.dashboard
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --log.level=DEBUG
- --global.sendAnonymousUsage=false
deploy:
placement:
constraints:
- node.role==worker
# Dynamic Configuration
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`SWARM_NODE`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.dashboard.service=api#internal"
- "traefik.http.services.dummy-svc.loadbalancer.server.port=9999" # Dummy service for Swarm port detection. The port can be any valid integer value.
volumes:
traefik-public-certificates: {}
networks:
# This network is used by other services
# to connect to the proxy.
uccser-dev-public:
external: true
# This network is used for Traefik to talk to
# the Docker socket.
traefik-docker:
driver: overlay
driver_opts:
encrypted: 'true'
Any ideas?
Further testing showed other services were working on different nodes, so figured it must be an issue with my application. Turns out my Django application still had a bunch of settings configured for it's previous hosting location regarding HTTPS. As it wasn't passing the required settings it had denied the requests before the were processed. I needed to have the logging level for gunicorn (WSGI) lower to see more information too.
In summary, Traefik and Swarm were fine.
Another reason for this can be that Docker Swarm ports haven't been opened on all of the nodes. If you're using UFW that means running the following on every machine participating in the swarm:
ufw allow 2377/tcp
ufw allow 7946/tcp
ufw allow 7946/udp
ufw allow 4789/udp

Traefik version 2 only shows 404 or no website at all

I try to set up Traefik in version 2 but I only get "404 Page not found" or DNS_PROBE_FINISHED_NXDOMAIN errors in my browser.
When I check the API endpoints for routers I can see that my two containers are enabled in Traefik and that the rules are correct.
curl http://localhost:8080/api/http/routers
[{"entryPoints":["web","secure"],"service":"gotify-gotify","rule":"Host(`sub2.example.org`)","tls":{"certResolver":"letsencrypt"},"status":"enabled","using":["secure","web"],"name":"gotify#docker","provider":"docker"},{"entryPoints":["web","secure"],"service":"nextcloud-cloud","rule":"Host(`sub.example.org`)","tls":{"certResolver":"letsencrypt"},"status":"enabled","using":["secure","web"],"name":"nextcloud#docker","provider":"docker"}]
But on "sub2" I get no website at all and on "sub" I get "404 page not found". I have set a DNS entry for "*" so all subdomains go to the same server.
I have set the following labels for the docker containers
labels:
traefik.enable: true
traefik.http.routers.nextcloud.rule: "Host(`sub.example.org`)"
traefik.http.routers.nextcloud.entrypoints: "web, secure"
traefik.http.routers.nextcloud.tls.certresolver: "letsencrypt"
And this is my Traefik configuration traefik.toml
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.secure]
address = ":443"
[providers.docker]
exposedByDefault = false
network = "traefik"
[certificatesResolvers.letsencrypt.acme]
email = "me#example.org"
storage = "acme.json"
[certificatesResolvers.letsencrypt.acme.httpChallenge]
entryPoint = "web"
[api]
insecure = true
debug = true
dashboard = false
Traefik itself is running as a docker container.
version: "3.7"
services:
traefik:
image: traefik:v2.0
container_name: traefik
restart: unless-stopped
volumes:
- "./traefik.toml:/etc/traefik/traefik.toml"
- "./acme:/etc/traefik/acme"
- "/var/run/docker.sock:/var/run/docker.sock"
ports:
- "80:80"
- "127.0.0.1:8080:8080"
- "443:443"
networks:
- traefik
networks:
traefik:
driver: bridge
name: traefik
I use ufw to manage firewall rules and opened port 22, 80 and 443
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
You can find a working example for traefik 2.2.1. Also, you can check full setup gist: https://gist.github.com/fatihyildizhan/8f124039a9bd3801f0caf3c01c3601fb
I prefer to use traefik.yml with version 2.0. It looks simple and many people are familiar with the YAML files.
[Traefik v2.0] - docker-compose.yml with httpChallenge
version: '3.7'
services:
traefik:
image: traefik:v2.2.1
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.your-domain.com`)"
- "traefik.http.middlewares.traefik-auth.basicauth.users=username:hashed-password"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.your-domain.com`)"
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=http"
- "traefik.http.routers.traefik-secure.service=api#internal"
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
networks:
proxy:
external: true
[Traefik v2.0] - traefik.yml with httpChallenge
api:
dashboard: true
# Writing Logs to a File, in JSON
log:
level: DEBUG
filePath: "log-file.log"
format: json
# Configuring a buffer of 100 lines
accessLog:
filePath: "log-access.log"
bufferingSize: 100
entryPoints:
http:
address: ":80"
https:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
certificatesResolvers:
http:
acme:
email: your-email.com
storage: acme.json
httpChallenge:
entryPoint: http
[Traefik v2.0] - your-container docker-compose.yml
version: '3.7'
services:
your-container-name:
image: docker.pkg.github.com/username/repo-name/image-name:latest
container_name: your-container-name
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.your-container-name.entrypoints=http"
- "traefik.http.routers.your-container-name.rule=Host(`your-container-name.your-domain.com`)"
- "traefik.http.middlewares.your-container-name-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.your-container-name.middlewares=your-container-name-https-redirect"
- "traefik.http.routers.your-container-name-secure.entrypoints=https"
- "traefik.http.routers.your-container-name-secure.rule=Host(`your-container-name.your-domain.com`)"
- "traefik.http.routers.your-container-name-secure.tls=true"
- "traefik.http.routers.your-container-name-secure.tls.certresolver=http"
- "traefik.http.routers.your-container-name-secure.service=your-container-name"
- "traefik.http.services.your-container-name.loadbalancer.server.port=80"
- "traefik.docker.network=proxy"
networks:
proxy:
external: true
Several things could be causing this, some of which are:
You have SSL/TLS proxying enabled at your DNS level (e.g. CloudFlare) which will prevent http challenge completion.
You have a misconfigured storage path for the certificate resolver (probably not in this case but for other readers); check your Traefik container logs docker logs traefik for errors like
level=error msg="The ACME resolver \"[resolver]\" is skipped from the resolvers
list because: unable to get ACME account: open /[path_to_storage]/acme.json:
no such file or directory
level=error msg="the router [service]#docker uses a non-existent resolver:
[resolver]"
If you see these errors, make sure the storage folder exists and/or the volume is mapped correctly from your host to the Traefik docker container (you may need to create it manually, Traefik won't do it for you, at least currently).
There is a technical issue with the service behind the proxy (e.g. Nginx, Apache, etc is misconfigured). Traefik will produce a generic 404 page not found for a series of errors that do not technically correspond to a real 404 error (e.g. 500, 501, maybe others) and this can be confusing.

Configure Traefik in front of two docker containers, all on port 80

I try to run three docker containers on one host. Traaefik is one of the containers to proxy traffic to the other containers.
My first goal is to reach each container through a dedicated hostname on port 80. Traefik ui should be available only through a hostname and on port 80 also, having some sort of authentication.
Using only a docker-compose.yml, I can reach all three containers using the hostnames, all on port 80. But to add authentication, I guess I need to introduce a traefik.toml. But this gives me troubles.
Next goal would be to introduce SSL using let's encrypt on all three hosts.But first things first...
Working solution with three hosts, all on port 80, lacking authorization for Traefik UI:
version: "2"
networks:
web:
services:
prox:
image: containous/traefik:latest # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Træfik to listen to docker
restart: unless-stopped
ports:
- "80:80" # The HTTP port
labels:
- "traefik.port=8080"
- "traefik.backend=traefikception"
- "traefik.frontend.rule=Host:traefik.test.com"
- "traefik.enable=true"
volumes:
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
networks:
- web
seafile_1:
image: seafileltd/seafile
container_name: seafile_1
restart: unless-stopped
environment:
SEAFILE_ADMIN_EMAIL: me#test.com
SEAFILE_ADMIN_PASSWORD: ####
SEAFILE_SERVER_HOSTNAME: 1.test.com
labels:
- traefik.enable=true
- traefik.frontend.rule=Host:1.test.com
- traefik.port=80
- traefik.backend=seafile_1
- traefik.docker.network=web
volumes:
- /opt/seafile-data/ttt_1:/shared
networks:
- web
seafile_2:
image: seafileltd/seafile
container_name: seafile_2
restart: unless-stopped
environment:
SEAFILE_ADMIN_EMAIL: me#test2.com
SEAFILE_ADMIN_PASSWORD: #####
SEAFILE_SERVER_HOSTNAME: 2.test2.com
labels:
- traefik.enable=true
- traefik.frontend.rule=Host:2.test2.com
- traefik.port=80
- traefik.backend=seafile_1
- traefik.docker.network=web
volumes:
- /opt/seafile-data/ttt_2:/shared
networks:
- web
Adding the following traefik.toml:
defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.proxy]
address=":80"
[entryPoints.proxy.auth]
[entryPoints.proxy.auth.basic]
users = [
"joh:$apr1$RKdHyOKO$QDK1EKB4UJbsda7CXfPfK0",
]
[api]
entrypoint="proxy"
I get lot's of the following errors in the log, none of the containers is reachable from outside:
prox_1 | time="2018-06-17T19:23:26Z" level=fatal msg="Error preparing server: listen tcp :8080: bind: address already in use"
prox_1 | time="2018-06-17T19:24:26Z" level=error msg="Error opening listener listen tcp :8080: bind: address already in use"
prox_1 | time="2018-06-17T19:24:26Z" level=fatal msg="Error preparing server: listen tcp :8080: bind: address already in use"
I am pretty sure I need to adapt my docker-compose.yml and move settings to traefik.toml, but I cannot get my head around how to to that.
Thanks in advance!!
With the help of traefik support on slack I was able to solve this.
you may not have more than one entryPoint per Port
The Authorization can be configured in the docker-compose.yml
add acme.json and configure https and Let's encrypt only in traefik.toml
In /opt/traefik put the following three files:
acme.json:
may be empty but must be well secured:
touch acme.json
chmod 600 acme.json
docker-compose.yml:
version: "2"
networks:
web:
services:
prox:
image: containous/traefik:latest # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Træfik to listen to docker
restart: unless-stopped
ports:
- "80:80"
- "443:443"
# - "8080:8080" # Don't want this port open (on all hostnames!)
labels:
- "traefik.port=8080"
- "traefik.backend=traefikception"
- "traefik.frontend.rule=Host:traefik.example.me"
- "traefik.enable=true"
- "traefik.frontend.auth.basic=admin:$$ert2$$RKdHyOKO$$QDK1EKB4UJbsda7CXfPfK0"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock" # So that Traefik can listen to the Docker events
- "./traefik.toml:/traefik.toml"
- "./acme.json:/acme.json"
networks:
- web
seafile_org1:
image: seafileltd/seafile
container_name: seafile_org1
restart: unless-stopped
environment:
SEAFILE_ADMIN_EMAIL: mail#mail.me
SEAFILE_ADMIN_PASSWORD: ####
SEAFILE_SERVER_HOSTNAME: org1.example.me
labels:
- traefik.enable=true
- traefik.frontend.rule=Host:org1.example.me
- traefik.port=80
- traefik.backend=seafile_org1
- traefik.docker.network=web
volumes:
- /opt/seafile-data/org1:/shared
networks:
- web
seafile_org2:
image: seafileltd/seafile
container_name: seafile_org2
restart: unless-stopped
environment:
SEAFILE_ADMIN_EMAIL: mail#mail.com
SEAFILE_ADMIN_PASSWORD: ####
SEAFILE_SERVER_HOSTNAME: org2.example.com
labels:
- traefik.enable=true
- traefik.frontend.rule=Host:org2.example.com
- traefik.port=80
- traefik.backend=seafile_org2
- traefik.docker.network=web
volumes:
- /opt/seafile-data/org2:/shared
networks:
- web
get what you need to put as value to traefik.frontend.auth.basic issuing:
htpasswd -n admin
traefik.toml:
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[retry]
[api]
dashboard = true
# Enable ACME (Let's Encrypt): automatic SSL.
[acme]
email = "you#mail.com"
storage = "acme.json"
entryPoint = "https"
# If true, display debug log messages from the acme client library.
# acmeLogging = true
# Enable certificate generation on frontends host rules.
onHostRule = true
# CA server to use.
# Uncomment the line to use Let's Encrypt's staging server,
# leave commented to go to prod.
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
# Use a HTTP-01 ACME challenge.
# Optional (but recommended)
[acme.httpChallenge]
entryPoint = "http"
This uses Let's encrypt staging environment to get you three certs. Comment the line with caServer to get the real certs! Recreate an empty acme.json as well!
The seafile-data is stored in
/opt/seafile-data/org1
and
/opt/seafile-data/org2
respectively.
In /opt/traefik you can start the system:
docker-compose up -d
and watch the logs with
docker-compose logs
Startup takes some time on first run to setup seafile, get the certs,...
Your hosts should be reachable, giving no SSL errors or warnings on
http://traefik.example.me (Asking your credentials to see the page)
http://org1.example.me
http://org2.example.com
What's left to do is to edit the ccnet.conf file in each of the seafile installation directories (/opt/seafile-data/org1/seafile/conf/ccnet.conf) and change the protocol to "http" and remove the port ":8000" from SERVICE_URL so that shared links are correct for that setup as well. The line should read:
SERVICE_URL = https://org1.example.me
You can do it all in the Docker Stacks file:
version: "3.7"
services:
traefik:
image: traefik:1.7.13
command: >
--api
--docker
--docker.swarmmode
--docker.watch
--docker.exposedbydefault=false
# --debug=true
--loglevel=error # debug
--defaultentrypoints=https,http
--entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
--entryPoints="Name:https Address::443 TLS"
--retry
--acme=true
--acme.entrypoint=https
--acme.httpchallenge
--acme.httpchallenge.entrypoint=http
--acme.domains="..."
--acme.email="..."
--acme.storage=/certs/acme.json
ports:
- 80:80 # HTTP
- 443:443 # HTTPS
- 8080:8080 # The Web UI (enabled by --api)
volumes:
- acme:/certs
- /var/run/docker.sock:/var/run/docker.sock:ro
whoami:
image: containous/whoami
deploy:
labels:
traefik.frontend.rule: Path:/whoami
traefik.enable: "true"
traefik.port: 80
volumes:
acme:

Resources