SSL passthrough with Traefik - traefik

I need to send the SSL connections directly to the backend, not decrypt at my Traefik. The backend needs to receive https requests.
I tried the traefik.frontend.passTLSCert=true option but getting "404 page not found" error when I access my web app and also get this error on Traefik container
traefik | time="2018-09-16T10:47:41Z" level=error msg="Failed to create TLSClientConfig: no TLS provided"
traefik | time="2018-09-16T10:47:41Z" level=error msg="Failed to create RoundTripper for frontend frontend-Host-dev-mydomain-com-0: no TLS provided"
traefik | time="2018-09-16T10:47:41Z" level=error msg="Skipping frontend frontend-Host-dev-mydomain-com-0..."
Could you suggest any solution? Thank you.
I'm using Traefik version 1.6.6.
Here is my docker-compose.yml for the app container.
version: '3'
services:
app:
image: webdevops/php-nginx-dev:7.2
networks:
- proxy
volumes:
- ./:/app
- ../traefik/ssl/*.mydomain.com.crt:/opt/docker/etc/nginx/ssl/server.crt
- ../traefik/ssl/*.mydomain.com.key:/opt/docker/etc/nginx/ssl/server.key
environment:
- WEB_DOCUMENT_ROOT=/app
labels:
- traefik.enable=true
- traefik.frontend.rule=Host:dev.mydomain.com
- traefik.docker.network=proxy
- traefik.port=443
networks:
proxy:
external: true
The docker-compose.yml of my Traefik container.
version: "3"
services:
traefik:
image: traefik
container_name: traefik
command:
- --api
- --docker
- --docker.exposedbydefault=false
restart: always
ports:
- 80:80
- 443:443
networks:
- proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
- ./ssl:/sslcert
networks:
proxy:
external: true
Finally, my traefik.toml file.
debug = true
logLevel = "ERROR"
defaultEntryPoints = ["http","https"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/sslcert/*.mydomain.com.crt"
keyFile = "/sslcert/*.mydomain.com.key"
[retry]

Traefik now has TCP support in its new 2.0 version - which is still in alpha at this time (Apr 2019).
See PR https://github.com/containous/traefik/pull/4587
and the release notes of v2.0.0-alpha1 at https://github.com/containous/traefik/releases/tag/v2.0.0-alpha1 showing this TCP support PR being included
Hence once 2.0 is released (probably within 2-3 months), HTTPS passthrough will become possible.

Answer for traefik 1.0 (outdated)
passTLSCert forwards the TLS Client certificate to the backend, that is, a client that sends a certificate in the TLS handshake to prove it's identity.
Traefik is an HTTP reverse proxy. To establish the SSL connection directly with the backend, you need to reverse proxy TCP and not HTTP, and traefik doesn't (yet ?) support tcp (but there are issues for that on github).
Traefik won't fit your usecase, there are different alternatives, envoy is one of them.

The new passthrough for TCP routers is already available: https://docs.traefik.io/routing/routers/#passthrough

Related

Traefik does not use cert file provided for OpenConnect VPN

I have setup traefik in docker and use let's encrypt on the domain example.tld with some
services:
traefik:
image: "traefik:2.8.2"
container_name: "traefik"
hostname: "traefik"
restart: always
command:
- "--serverstransport.insecureskipverify=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.email=mail#example.tld"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--providers.file.filename=/etc/traefik/rules.yml"
- "--providers.file.watch=true"
ports:
- "443:443"
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./volumes/traefik/log:/etc/traefik/log"
- "./volumes/traefik/rules.yml:/etc/traefik/rules.yml"
- "./volumes/traefik/letsencrypt/:/letsencrypt/"
whoami:
image: "traefik/whoami"
container_name: "simple-service"
restart: always
labels:
- "traefik.enable=true"
- 'traefik.http.routers.whoami.tls.certresolver=letsencrypt'
- "traefik.http.routers.whoami.rule=Host(`whoami.example.tld`)"
This all functions, but now I wanted to add a OpenConnect VPN on the same port.
So in a file provider:
http:
routers:
router-vpn:
entryPoints:
- websecure
rule: Host(`vpn.example.tld`) # (same domain)
service: service-vpn
store: default
services:
service-vpn:
loadBalancer:
servers:
- url: "https://ocserver:3334"
tls:
stores:
default:
defaultCertificate:
certFile: /etc/traefik/log/certs/cert.pem
keyFile: /etc/traefik/log/certs/key.pem
certificates:
- certFile: /etc/traefik/log/certs/cert.pem
keyFile: /etc/traefik/log/certs/key.pem
The cert is copied from the OpenConnect server. The problem is that the OCC (OpenConnect Client) and the OCS (OpenConnect Server) connect over http CONNECT (the OCS receives the request) and use the public shown cert for encryption, but because traefik show's the lets encrypt cert the server can't decrypt the answer of the client and so does fail.
So now my question is how can i (on the same domain) force traefik to use the cert file (no matter if valid) for vpn.example.tld and for the rest of the domains use the LE cert?
Traefik currently only supports SNI based cert matching when the cert is valid and even this implementation is unreliable. I suggest using tls-passthrough as per documentation.

Getting "Gateway Timeout" for Mautic behind Traefik proxy

I deployed an multicontainer application with Mautic behind a Traefik reverse proxy.
However, I am getting a "Gateway timeout".
The reverse proxy's configuration seems OK as other containers within the application work fine.
I also changed the mautic settings to the mautics domain name.
Any idea?
docker-compose.yml
version: '3.3'
services:
reverse-proxy:
image: traefik:v2.4
restart: always
ports:
- '80:80'
- '443:443'
volumes:
- ./traefik:/etc/traefik
- /var/run/docker.sock:/var/run/docker.sock
mautic-app:
restart: always
image: mautic/mautic:v3
volumes:
- mautic_data:/var/www/html
environment:
- MAUTIC_DB_HOST=mautic-database
- MAUTIC_DB_USER=${MAUTIC_DB_USER}
- MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD}
- MAUTIC_DB_NAME=mautic3
ports:
- 80
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.mautic.tls=true'
- 'traefik.http.routers.mautic.tls.domains[0].main=optin.${SITE}'
- 'traefik.http.routers.mautic.tls.certresolver=lets-encrypt'
- 'traefik.http.routers.mautic.rule=Host(`optin.${SITE}`)'
depends_on:
- mautic-database
networks:
- mautic-net
mautic-database:
image: powertic/percona-docker
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MAUTIC_DB_PASSWORD}
ports:
- 3306
volumes:
- database:/var/lib/mysql
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --sql-mode=""
networks:
- mautic-net
volumes:
database:
driver: local
mautic_data:
driver: local
networks:
mautic-net:
driver: bridge
traefik.toml
[log]
level = "DEBUG"
[providers]
[providers.docker]
exposedByDefault = false
[providers.file]
directory = "/etc/traefik/dynamic"
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.https]
address = ":443"
[certificatesResolvers.lets-encrypt.acme]
storage = "/etc/traefik/acme.json"
email = "jenslaufer#jenslaufer.com"
[certificatesResolvers.lets-encrypt.acme.tlsChallenge]
force-https.toml
[http.routers]
[http.routers.force-https]
entryPoints = ["http"]
middlewares = ["force-https"]
rule = "HostRegexp(`{any:.+}`)"
service = "noop"
[http.middlewares]
[http.middlewares.force-https.redirectScheme]
scheme = "https"
[http.services]
[http.services.noop.loadBalancer]
Not sure if you're using Apache or PHP FPM behind the proxy.
But... Traefik does not support fastCgi Proxy
We encountered this issue with Traefik and set up our mautic kubernetes with nginx-proxy for that reason.
If you have docker running in swam mode, containers will have multiple networks attached. Traefik needs pointing to which network to use.
You must set label traefik.docker.network on the backend service container.
labels:
traefik.docker.network: <traefik network>
Otherwise, you will be getting success sometimes but most of the time traefik will return Gateway Timeout
It's a "misconfiguration" in docker-compose:
Traefik and Maurice are in different networks.
Moving Traefik to the mautic-net network fixed the problem.

Traefik and WildCard Certificates Issue By Third party

I have traefik set up and running, but experiencing issues with https, (wildcard certificate). Im able to get a redirect from 80 to 443 but nothing will load. I donot see much information in the logs and they have been set to debug level
Checked the permissions for the cert and set logs to debug
0644 on crt and 0600 on key
Tarefik TOML
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/etc/traefik/certs/server.crt"
keyFile = "/etc/traefik/certs/server.key"
Docker Compose
services:
reverse-proxy:
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
ports:
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
- /home/traefik/traefik.toml:/traefik.toml
- /home/traefik/certs:/etc/traefik/certs
networks:
- traefik-net
Sample NGINX server being run
nginx-docker:
image: nginx:latest
labels:
- "traefik.frontend.rule=Host:<hostname>.eogresources.com"
networks:
- traefik-net
Exposing 443 on traefik resolved my issue. Added additional port docker-compose file, change reflected below. Silly mistake. Also added the network in compose file
services:
reverse-proxy:
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
ports:
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
- /home/traefik/traefik.toml:/traefik.toml
- /home/traefik/certs:/etc/traefik/certs
networks:
- traefik-net
networks:
traefik-net:
driver: "overlay"

Traefik entrypoints and default certificate

Question 1
https://docs.traefik.io/configuration/entrypoints/#default-certificate seems to indicate that if I do not specify any certFile or keyFile, a self-signed certificate will be generated by Traefik, and used instead.
There can only be one defaultCertificate set per entrypoint. Use a single set of square brackets [ ], instead of the two needed for normal certificates. If no default certificate is provided, a self-signed certificate will be generated by Traefik, and used instead.
However, when I try this and enter https://localhost/whoami I get an SSL error by Chrome (ERR_SSL_PROTOCOL_ERROR). Logs also show level=error msg="failed to load X509 key pair: tls: failed to find any PEM data in certificate input". Have I misunderstood the configuration in that documentation?
This is the code I have to test this.
test.yml
version: '3.6'
services:
traefik:
image: traefik
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.toml:/etc/traefik/traefik.toml
deploy:
placement:
constraints:
- node.role == manager
labels:
- "traefik.port=8080"
- "traefik.frontend.rule=PathPrefixStrip:/traefik"
networks:
- traefiknet
whoami:
image: emilevauge/whoami
deploy:
labels:
- "traefik.port=80"
- "traefik.frontend.rule=PathPrefixStrip:/whoami"
networks:
- traefiknet
networks:
traefiknet:
traefik.toml
logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[api]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[entryPoints.https.tls.defaultCertificate]
[docker]
endpoint = "unix:///var/run/docker.sock"
watch = true
swarmMode = true
network = "test_traefiknet"
Start with:
docker stack deploy -c test.yml test
Question 2
Note that I also tested to do like it reads on this page: https://docs.traefik.io/configuration/entrypoints/#static-certificates
If an empty TLS configuration is provided, default self-signed certificates are generated.
However, that also did not work. My question is however, what is the difference between this configuration and the configuration shown in question 1 in the toml file?
I found out the answer. I needed to remove [entryPoints.https.tls.defaultCertificate]. Unfortunately I did not find the documentation very clear in this regard.

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