How to publish websocket through traefik from docker container - traefik

I have traefik running in my docker swarm, doing https proxying for a couple of websites, this part is working fine.
The problem is that I have one container that only publishes a WSS (mosquitto), for my home automation setup, and I can't get it to work.
In my automation stack yml file I have the following stanza for mosquitto, from what I have read on various pages, I just need to specify HTTPS as a protocol, as it also covers WSS
mqtt:
deploy:
restart_policy:
condition: any
delay: 5s
max_attempts: 3
window: 120s
placement:
constraints:
- node.labels.mysensors==yes
replicas: 1
labels:
- traefik.frontend.rule=Host:mqtt.mydomain.com
- traefik.port=9001
- traefik.docker.network=traefik-public
- traefik.enable=true
- traefik.redirectorservice.frontend.entryPoints=http
- traefik.redirectorservice.frontend.redirect.entryPoint=https
- traefik.frontend.whiteList.sourceRange=192.168.0.0/16
- traefik.tags=traefik-public
- traefik.webservice.frontend.entryPoints=https
ports:
- 1883:1883
networks:
- homeautomation
- traefik-public
volumes:
- /opt/mosquitto:/mosquitto
image: "eclipse-mosquitto:1.4.12"
In my Traefik dashboard, I only see the other (https) service backends exposed, and not this WSS one.. Wonder what I am missing in my configuration.

Add in labels:
- traefik.backend.loadbalancer.stickiness: "true"
This will allow to support wss connections

Related

Traefik/Portainer - ERR_TOO_MANY_REDIRECTS

I'm trying to setup Traefik and Portainer but seem to be hitting some issues. I think mainly around Traefik and setting up new containers.
Everything looks correct to me but I seem to be getting an error when I point to my subdomain
ERR_TOO_MANY_REDIRECTS
If I point to the IP address and Port, the Portainer dashboard is displayed, it just seems to be that when pointing to my sub-domain, there is some recursive redirection I'm assuming.
My docker compose looks like this:-
version: '3'
services:
portainer:
image: portainer/portainer:latest
container_name: portainer-new
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
ports:
- 8000:8000
- 9000:9000
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.entrypoints=http"
- "traefik.http.routers.portainer.rule=Host(`MY_URL`)"
- "traefik.http.middlewares.portainer-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.portainer.middlewares=portainer-https-redirect"
- "traefik.http.routers.portainer-secure.entrypoints=https"
- "traefik.http.routers.portainer-secure.rule=Host(`MY_URL`)"
- "traefik.http.routers.portainer-secure.tls=true"
- "traefik.http.routers.portainer-secure.tls.certresolver=http"
- "traefik.http.routers.portainer-secure.service=portainer"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
- "traefik.docker.network=proxy"
networks:
proxy:
external: true
Any ideas?
Okay, so I figured out my issue.
The above is correct and valid. I use CloudFlare for proxy/DNS etc... I had added my subdomain to my DNS settings, but my Proxy Status was Proxied rather than DNS ONLY. After setting DNS only the above worked.

Is there a way to let some traefik services manage their tls certificates themselves?

I'll try to configure traefik for something like that:
1) server.example.com --> traefik --> httpChallengeToLetsEncrypt
2) client --> traefik (passthrough tls) --> server.example.com( with let's encrypt )
N.B.: traefik receives its requests at example.com level
What is happening:
1) Works correctly only if traefik does not manage let's encrypt certificates itself (otherwise it does not transmit any request whose pathPrefix begins with ".well-known/acme-challenge" :-\ )
2) Does not work with a config for tcp router like this:
tcp:
routers:
example:
entryPoints:
- web-secure
rule: "HostSNI(`server.example.com`)"
service: example
tls:
passthrough: true
services:
example:
loadBalancer:
servers:
- url: "https://192.168.0.1:443/"
How would you let one or more services manage their let's encrypt certificates themselves ?
And is it possible to do it at the same time that traefik also manages let's encrypt certificates or the problem mentioned in point 1 is it redibitory?
Best regards,
jmc
use tls.passthrough=true and a tcp router instead of http
below is a fully working example where apache is responsible for its own certificates.
traefik never touches them
version: "3"
services:
traefik:
image: traefik
command:
- --api.insecure=true
- --providers.docker=true
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
labels:
- traefik.http.routers.api.rule=Host(`traefik.docker.local`)
- traefik.http.routers.api.service=api#internal
whoami:
image: containous/whoami
labels:
- traefik.http.routers.whoami.rule=Host(`whoami.docker.local`)
- traefik.http.routers.whoami.service=whoami#docker
- traefik.http.services.whoami.loadbalancer.server.port=80
apache:
build: php-apache
depends_on: [traefik]
env_file: ./php-apache/env
volumes:
- "./php-apache/cert/haproxy/:/etc/ssl/haproxy/"
- "./php-apache/cert/private/:/etc/ssl/private/"
- "./php-apache/cert/trusted/:/usr/local/share/ca-certificates/"
- "./php-apache/conf/:/etc/apache2/conf-enabled/"
- "./php-apache/log/:/var/log/apache2/"
- "./php-apache/sites/available/:/etc/apache2/sites-available/"
- "./php-apache/sites/enabled/:/etc/apache2/sites-enabled/"
- "./php-apache/www/:/var/www/"
labels:
- "traefik.http.routers.apache.entrypoints=http"
- "traefik.http.routers.apache.priority=1"
- "traefik.http.routers.apache.rule=HostRegexp(`{catchall:.*}`)"
- "traefik.http.routers.apache.service=apache#docker"
- "traefik.http.services.apache.loadbalancer.server.port=80"
- "traefik.tcp.routers.apache.entrypoints=https"
- "traefik.tcp.routers.apache.rule=HostSNI(`*`)"
- "traefik.tcp.routers.apache.service=apache#docker"
- "traefik.tcp.routers.apache.tls.passthrough=true"
- "traefik.tcp.services.apache.loadbalancer.server.port=443"

Traefik and Harbor

I have changed the docker-compose.yml after the default Conf-Generation. My Proxy configuration looks like:
( I had only touched the proxy part )
proxy:
image: goharbor/nginx-photon:v1.9.4
container_name: nginx
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
- NET_BIND_SERVICE
volumes:
- ./common/config/nginx:/etc/nginx:z
networks:
- harbor
- web
dns_search: .
expose:
- 8080
ports:
- 8081:8080 #only to test if its online
labels:
- "traefik.enable=true"
- "traefik.backend=harbor-backend"
- "traefik.docker.network=web"
- "traefik.frontend.rule=Host:harbor.example.com"
- "traefik.frontend.entryPoints=https,http"
- "traefik.port=8080"
depends_on:
- registry
- core
- portal
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy"
networks:
harbor:
external: false
web:
external: true
In my Harbor.yml i had leaved the http port to 80 and disabled https.
My Proxy configuration is the default one.
The Web UI works fine but when I try to login with the docker client i get this response:
root#h2791112:~# docker login registry.example.com
Username: admin
Password:
Error response from daemon: Get https://registry.example.com/v2/: unauthorized: authentication required
And that are the crendentials that work with the ui
did I miss a label ?
This worked for me: https://github.com/goharbor/harbor/issues/3114#issuecomment-432962664
Follow the steps

Deploying Traefik with LetsEncrypt and multiple Docker backend

I am considering replacing Apache for Traefik for my web project (Kestrel / .Net Core). After reading the documentation, a few things remain unclear to me regarding Traefik:
1/ Does Traefik automatically handle the LetsEncrypt certificate renewal or does it need to be done manually or via an external script? From the doc it's said that this is performed when adding a new host or restart, but what happens after 3 months of Traefik running without any restart/new host added?
2/ When a Docker backend becomes unreachable, how is it possible to serve a custom static HTML page? I can see how to set specific error page from the documentation, but not how to redirect trafic to it when a given backend becomes unavailable.
3/ When a Docker backend needs to be updated, is there some steps that need to be performed on Traefik prior to performing the Docker stop/restart?
4/ It seems I can't get to have 2 docker backend running at the same time, see the configuration file below, if I uncomment the 2nd backend (api.mydomain.io), then the 1st one becomes not available anymore. Am I missing something here?
version: '3'
services:
reverse-proxy:
image: traefik # The official Traefik docker image
command: --docker # Enables the web UI and tells Træfik to listen to docker
ports:
- "80:80" # The HTTP port
- "443:443" # The HTTPS port
- "8080:8080" # The Web UI (enabled by --api)
networks:
- proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- $PWD/traefik.toml:/etc/traefik/traefik.toml
- $PWD/acme.json:/acme.json
- /root/mydomain_prod/cert/:/certs/
- /root/mydomain_prod/503.html:/503.html
container_name: traefik-reverse-proxy
##############################
# Front - www.mydomain.io
##############################
mydomain-front:
image: mydomain-front
labels:
- traefik.enable=true
- traefik.backend=mydomain-front
- traefik.frontend.rule=Host:traefik.mydomain.io
- traefik.port=8084
networks:
- internal
- proxy
container_name: mydomain-front
##############################
# API - api.mydomain.io
# Note: If I uncomment this one, then www.mydomain.io won't work anymore
##############################
#mydomain-api:
# image: mydomain-api
# labels:
# - traefik.enable=true
# - traefik.backend=mydomain-api
# - traefik.frontend.rule=Host:api.mydomain.io
# - traefik.port=8082
# networks:
# - internal
# - proxy
# container_name: mydomain-api
Many thanks,
Flo
1/ Traefik can handle the LetsEncrypt certificate renewal. Just remember to create a Volume to store the acme.json file. When the certificate expires, Traefik will do the renewal without asking.
2/ I don’t know if it’s possible. If you find a solution, share it.
3/ When you need to update a Docker, just update it. Traefik will be trigger from that change and update is own configuration.
4/ You can have to backend running at the same time. Below you can see a docker-compose.yml configuration :
version: '3'
services:
two-backend-service:
restart: always
image: ……..
labels:
- traefik.enable=true
- traefik.service1.frontend.rule=Host:service1.exemple.com
- traefik.service1.frontend.passHostHeader=true
- traefik.service1.port=8082
- traefik.Service2.backend=service2
- traefik.Service2.frontend.rule=Host:service2.exemple.com
- traefik.Service2.frontend.passHostHeader=true
- traefik.Service2.port=8081
traefik:
build:
context: ./traefik
dockerfile: Dockerfile
restart: always
ports:
- 80:80
- 443:443
labels:
- traefik.enable=false
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_letsencrypt:/etc/traefik/acme/
volumes:
traefik_letsencrypt:
driver: local

Redis connection refused when using traefik

I'm having a hard time trying to configure one redis container for all my applications using traefik. This is my configuration:
1 - Docker compose for Traefik and Redis:
version: '2'
services:
proxy:
container_name: traefik
image: traefik:1.3.6-alpine
command: --docker
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
networks:
- proxy
labels:
- traefik.frontend.rule=Host:monitor.company.dev
- traefik.port=8080
redis:
container_name: main_redis
image: redis:3.2
restart: always
volumes:
- ./data/redis:/data
networks:
- proxy
labels:
- traefik.backend=main-redis
- traefik.default.protocol=http
- traefik.frontend.rule=Host:main-redis.company.dev
- traefik.docker.network=proxy
- traefik.port=6379
networks:
proxy:
external: true
2 - Docker compose for my PHP Application.
version: '2'
services:
...
php:
container_name: myapp_php
build: ./docker/php # php:7.1-fpm base image
networks:
- internal
- proxy
labels:
- traefik.enable=false
- traefik.docker.network=proxy
expose:
- 9000
networks:
proxy:
external: true
internal:
external: false
I tried to connect my php application to main-redis.company.dev on both ports 6379 and 80 but I get a Redis::connect(): connect() failed: Connection refused message.
I also changed these stuff in my redis.conf:
Commented the line with bind 127.0.0.1
And changed protected-mode to no
My docker containers are staying in the same network, so I think it should work. Anyone knows why am I having this problem?
2022 UPDATE to #djeeg answer
For some time now you can use TCP mode for your routers. To do that you need to define the labels with TCP instead of HTTP
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.redis.rule=HostSNI(`redis.example.com`)"
- "traefik.tcp.routers.redis.entrypoints=redis" //6379 entrypoint
- "traefik.tcp.routers.redis.tls.certresolver=myresolver" //let's encrypt resolver
- "traefik.tcp.routers.redis.service=redis"
- "traefik.tcp.services.redis.loadbalancer.server.port=6379"
once you got that working in order to connect assuming you are using TSL you will get error Error: Protocol error, got "H" as reply type byte.
To prevent this you need to do things.
Allow for tls connection in the connection string
Setup SNI for your DNS name or provide public certificate file via cert pr cacert
redis-cli -u redis://redis.example.com:6379 --tls --sni redis.example.com
First off, remove the traefik labels from your redis service definition, traefik is currently (Nov 2017) a HTTP proxy, so you can't expose the endpoint like that
See here:
https://github.com/containous/traefik/issues/10
https://github.com/containous/traefik/issues/1611
Then to connect the php service to the redis service, that looks like you are trying to do that within the same docker instance (rather than externally)
Instead of main-redis.company.dev:6379, it should be like on of these:
redis:6379
main_redis:6379
%PROJECT_NAME%_redis:6379
depending upon how you are deploying the container