Using wildcard certificates in Traefik v2 on Docker Swarm - docker

I am using the following Docker Compose file to deploy Traefik on a swarm cluster.
version: "3.7"
services:
traefik:
image: traefik:v2.1
command:
- "--api.dashboard=true"
- "--accesslog=true"
- "--log.level=INFO"
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
- "--providers.docker.swarmMode=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=traefik-public"
- "--providers.file.watch=true"
- "--providers.file.filename=/file_provider.yml"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.dnsChallenge.provider=cloudflare"
- "--certificatesresolvers.letsencrypt.acme.dnsChallenge.delayBeforeCheck=15"
- "--certificatesresolvers.letsencrypt.acme.dnsChallenge.resolvers=1.1.1.1:53,1.0.0.1:53"
- "--certificatesresolvers.letsencrypt.acme.email=user#domain.tld"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- 80:80
- 443:443
volumes:
- traefik-certificates:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock
networks:
- traefik-public
environment:
- "CF_API_EMAIL=user#domain.tld"
- "CF_API_KEY=api-key"
deploy:
placement:
constraints:
- node.role == manager
labels:
- "traefik.enable=true"
- "traefik.docker.lbswarm=true"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https#docker"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.routers.api.tls.domains[0].main=*.domain.tld"
- "traefik.http.routers.api.tls.domains[0].sans=domain.tld"
- "traefik.http.routers.api.rule=Host(`management.domain.tld`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.api.service=api#internal"
- "traefik.http.services.api.loadbalancer.server.port=8080"
configs:
- file_provider.yml
volumes:
traefik-certificates:
configs:
file_provider.yml:
file: /home/access/docker/traefik-provider.yml
networks:
traefik-public:
external: true
At the moment, I have hit the rate limit on management.domain.tld and I instead want to use a wildcard certificate so there is less likelihood that I will run into a rate limit again. I have Traefik configured to generate the wildcard certificate which works, but there is still a rate-limiting error on management.domain.tld in the logs. Also, when I go to management.domain.tld in the browser, I get an invalid SSL/TLS error. How do I get Traefik to use the wildcard certificate instead of issuing a new certificate for every host rule?

Looks like you have done everything right. But there is a slight mistake in the config.
main is the Subject field for the certificate. Meaning the domain/sub-domain the certificate is being issued to.
sans is the Subject Alternate Names field for the certificate. Meaning alternative domain/sub-domain that the certificate is also valid for.
So, Instead of using:
version: "3.7"
services:
traefik:
image: traefik:v2.1
...
labels:
- "traefik.http.routers.api.tls.domains[0].main=*.domain.tld"
- "traefik.http.routers.api.tls.domains[0].sans=domain.tld"
...
You should use:
version: "3.7"
services:
traefik:
image: traefik:v2.1
...
labels:
- "traefik.http.routers.api.tls.domains[0].main=domain.tld"
- "traefik.http.routers.api.tls.domains[0].sans=*.domain.tld"
...

Related

Failing to get certificate with Traefik from Lets Encrypt

I am trying to get a certificate for my docker container but I keep getting errors, below is my docker-compose. This used to work before until i deleted the container to restart it again. I am using Traefik as the proxy and I am using it to request for certificates.
and I keep getting this error when i start my container to get the certitifcates.
Unable to obtain ACME certificate for domains "mydomain.com": unable to generate a certificate for the domains [mydomain.com]: error: one or more domains had a problem:\n[mydomain.com] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized ::
Cannot negotiate ALPN protocol "acme-tls/1" for tls-alpn-01 challenge\n",
"providerName": "myresolver.acme"
Please note i have replaced the actual domain with mydomain.com and other lines of images in the docker compose have been left out for brevity. Is there any rule i am not following properly?
services:
##Reverse Proxy
traefik:
image: library/traefik:v2.6.0
container_name: traefik
labels:
- traefik.enable=false
command:
- --api.insecure=false
- --providers.docker
#
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.web.http.redirections.entryPoint.scheme=https
- --entrypoints.websecure.address=:443
- --entryPoints.websecure.forwardedHeaders.insecure
- --entryPoints.web.forwardedHeaders.insecure
#
# ...
- --certificatesresolvers.myresolver.acme.email=email#email.com
- --certificatesresolvers.myresolver.acme.tlschallenge=true
- --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
# used during the challenge
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
#logs
# Writing Logs to a File
- --log.level=DEBUG
- --log.filePath=/logs/traefik.log
- --log.format=json
## Access Logs
- --accesslog=true
networks:
- traefik
ports:
- "80:80"
- "443:443"
- "8080:8080"
restart: always
volumes:
- ./logs/traefik/:/logs/
- ./letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
portainer:
image: portainer/portainer:latest
container_name: portainer
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik
ports:
- "9000:9000"
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./portainer-data:/data
labels:
- "traefik.http.routers.portainer.priority=1"
- "traefik.http.routers.portainer.rule=Host(`mydomain.com`)"
- "traefik.http.routers.portainer.tls=true"
- "traefik.http.routers.portainer.tls.certresolver=myresolver"
networks:
traefik:
name: traefik```

Traefik self-signed certificated wildcard subdomain in docker-compose

I'm looking for a solution to let traefik generate a wildcard certificate for my services. In fact in local development I do have multiple services sharing the same domain and currently I have to accept the certificate for each one.
I have 2 subdomains front.domain.localhost and api.domain.localhost and I would like a single certificate for both.
Here is a demo docker-compose.yml:
version: '3'
services:
traefik:
image: traefik:2.5
command:
- --providers.docker
- --entryPoints.http.address=:80
- --entryPoints.http.http.redirections.entryPoint.to=https
- --entryPoints.http.http.redirections.entryPoint.scheme=https
- --entryPoints.https.address=:443
labels:
- traefik.enable=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
front:
image: traefik/whoami
labels:
- traefik.http.routers.front_router.rule=Host(`front.domain.localhost`)
- traefik.http.routers.front_router.entrypoints=https
- traefik.http.routers.front_router.tls=true
api:
image: traefik/whoami
labels:
- traefik.http.routers.api_router.rule=Host(`api.domain.localhost`)
- traefik.http.routers.api_router.entrypoints=https
- traefik.http.routers.api_router.tls=true
With this one I should accept 2 certificates (one for each subdomain).
I tried with various combination of main and sans as explained in https://doc.traefik.io/traefik/routing/routers/#domains without success.
How can I achieve this ?

Traefic Routing for FireflyIII

Greetings Stack Overflow,
I have a RespberryPi4B, on which I installed Ubuntu 20.
(Linux ubuntu 5.4.0-1034-raspi aarch64 - Ubuntu 20.04.1 LTS)
On this Pi I want to install several Applications for my local use only.
To be able to have multiple Applications exposed, I use Traefik as a Proxy.
To easier deploy the Applications, I use Docker and Docker-Compose
Already up and running I have a Nextcloud instance, which works just fine.
Now I want to add FireflyIII as an Application, but the routing does not comply, and greets me with "Bad Gateway".
Here's what I have
The following docker-compose.yml for my Nextcloud works like a charm:
version: '3.3'
services:
nextcloud-db:
image: mariadb
container_name: nextcloud-db
command: --transaction-isolation=READ-COMMITTED --log-bin=ROW
restart: unless-stopped
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- /opt/containers/nextcloud/database:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD={supersecret}
- MYSQL_PASSWORD={supersecret}
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloudusr
- MYSQL_INITDB_SKIP_TZINFO=1
networks:
- default
nextcloud-redis:
image: redis:alpine
container_name: nextcloud-redis
hostname: nextcloud-redis
networks:
- default
restart: unless-stopped
command: redis-server --requirepass {supersecret}
nextcloud-app:
image: nextcloud
container_name: nextcloud-app
restart: unless-stopped
depends_on:
- nextcloud-db
- nextcloud-redis
environment:
REDIS_HOST: nextcloud-redis
REDIS_HOST_PASSWORD: {supersecret}
volumes:
- /opt/containers/nextcloud/app:/var/www/html
- /opt/containers/nextcloud/daten:/var/www/html/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.nextcloud-app.entrypoints=http"
- "traefik.http.routers.nextcloud-app.rule=Host(`nextcloud.mydomain.com`)"
- "traefik.http.middlewares.nextcloud-app-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.nextcloud-app.middlewares=nextcloud-app-https-redirect"
- "traefik.http.routers.nextcloud-app-secure.entrypoints=https"
- "traefik.http.routers.nextcloud-app-secure.rule=Host(`nextcloud.mydomain.com`)"
- "traefik.http.routers.nextcloud-app-secure.tls=true"
- "traefik.http.routers.nextcloud-app-secure.tls.certresolver=http"
- "traefik.http.routers.nextcloud-app-secure.service=nextcloud-app"
- "traefik.http.services.nextcloud-app.loadbalancer.server.port=80"
- "traefik.docker.network=proxy"
- "traefik.http.routers.nextcloud-app-secure.middlewares=nextcloud-dav,secHeaders#file"
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.regex=^/.well-known/ca(l|rd)dav"
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.replacement=/remote.php/dav/"
networks:
- proxy
- default
networks:
proxy:
external: true
While knowing that this configuration, and these traefik labels work, I would assume, that the following docker-compose.yml, now for FireflyIII would work as well. And while the container spins up without any visible issues - I can see in the container logs, that the applications connects to the database and prepares everything - the access via browser is not possible - I get a Bad Gateway.
This is my FireflyIII's docker-compose.yml
version: '3.3'
services:
fireflydb:
image: mariadb
container_name: fireflydb
environment:
- MYSQL_RANDOM_ROOT_PASSWORD=yes
- MYSQL_USER=fireflyuser
- MYSQL_PASSWORD={supersecret}
- MYSQL_DATABASE=fireflydb
volumes:
- firefly_db:/var/lib/mysql
networks:
- default
firefly:
image: jc5x/firefly-iii:latest
container_name: firefly
volumes:
- firefly_upload:/var/www/html/storage/upload
depends_on:
- fireflydb
env_file: .env
labels:
- "traefik.enable=true"
- "traefik.http.routers.firefly-app.entrypoints=http"
- "traefik.http.routers.firefly-app.rule=Host(`firefly.mydomain.com`)"
- "traefik.http.middlewares.firefly-app-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.firefly-app.middlewares=firefly-app-https-redirect"
- "traefik.http.routers.firefly-app-secure.entrypoints=https"
- "traefik.http.routers.firefly-app-secure.rule=Host(`firefly.mydomain.com`)"
- "traefik.http.routers.firefly-app-secure.tls=true"
- "traefik.http.routers.firefly-app-secure.tls.certresolver=http"
- "traefik.http.routers.firefly-app-secure.service=firefly-app"
- "traefik.http.services.firefly-app.loadbalancer.server.port=80"
- "traefik.docker.network=proxy"
networks:
- proxy
- default
volumes:
firefly_upload:
firefly_db:
networks:
proxy:
external: true
The only difference between the Traefik Labels is, that I don't need the replacepathregex labels for firefly, and that I changed the Hosts and application names:
nextcloud.mydomain.com -> firefly.mydomain.com
nextcloud-app/nextcloud-app-secure -> firefly-app/firefly-app-secure
I just don't understand yet, why the "same" configuration behaves differently.
The Traefik container logs don't throw any errors.
A note about the SSL Certificates, since the applications are run in my local network, and I edit my local hostfile to access the application via browser, the SSL renewal isn't possible, I am aware of that. I currently work around it by manually renewing on a different server and copying the cert to my Pi. Quick and dirty, but works for now.
For completeness, here's my Traefik's traefik.yml, docker-compose.yml and dynamic_conf.yml:
traefik.yml:
api:
dashboard: true
entryPoints:
http:
address: ":80"
https:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
filename: "/dynamic_conf.yml"
certificatesResolvers:
http:
acme:
email: mymail#mydomain.com
storage: acme.json
httpChallenge:
entryPoint: http
docker-compose.yml:
version: '3'
services:
traefik:
image: traefik:latest
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
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
- ./data/dynamic_conf.yml:/dynamic_conf.yml
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.mydomain.com`)"
- "traefik.http.middlewares.traefik-auth.basicauth.users=user:secret"
- "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.mydomain.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"
- "providers.file.filename=/dynamic_conf.yml"
networks:
proxy:
external: true
dynamic_conf.yml
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
http:
middlewares:
secHeaders:
headers:
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
sslRedirect: true
#HSTS Configuration
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
The only thing I could think of, might be a problem with the internal Ports.
But I don't know enough about traefik and docker yet, to say for sure.
I appreciate any hints and suggestions for improvement.
At first glance I'd recommend to change the port to 8080:
version: '3.3'
services:
# [...]
firefly:
labels:
#
- "traefik.http.services.firefly-app.loadbalancer.server.port=8080"
# [...]
The firefly-iii-Image you're using is based on their BaseImage which's README.md says:
Basically, I use the 7.4 Apache image with some minor changes.
And one change is:
Switch to port 8080

Traefik Docker SSL Configuration With Lets Encrypt

Hi everyone I am trying to enable SSL in my docker-compose.yml file for my backend service. All of my Traefik configuration is done in my docker-compose.yml file, so I may be missing a line. Running docker-compose on this configuration works without SSL and the site is displayed properly, but it does not work when using https. I have checked the Traefik documentation for the certResolvers and I am not sure what I am missing thanks.
version: "3"
networks:
NanoWall-Net:
services:
api:
build:
context: .
dockerfile: Dockerfile
labels:
- "traefik.docker.network=NanoWall-Net"
- "traefik.enable=true"
- "traefik.port=5000"
- "traefik.http.routers.http-catchall.rule=Host(`nanowalldocs.com`)"
- "traefik.http.routers.http-catchall.tls=true"
- "traefik.http.routers.http-catchall.tls.certresolver=le"
- "traefik.http.routers.http-catchall.tls.domains[0].sans=nanowalldocs.com"
- "traefik.http.routers.http-catchall.entrypoints=web"
ports:
- "5000:5000"
networks:
- NanoWall-Net
reverse-proxy:
image: traefik:v2.0
# Enables the web UI and tells Traefik to listen to docker
command:
- "--entryPoints.web.address=:80"
- "--entryPoints.websecure.address=:443"
- "--entryPoints.websecure.http.tls.certResolver: le"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--api.insecure=true"
- "--api.debug=true"
- "--api=true"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
- "--providers.docker.exposedbydefault=false"
- "--accesslog=true"
- "--accesslog.filepath=/var/log/traefik-access.log"
- "--accesslog.bufferingsize=1000"
- "--log.filePath=/var/log/traefik.log"
- "--certificatesResolvers.le.acme.email=jamar.phillip99#gmail.com"
- "--certificatesResolvers.le.acme.storage=acme.json"
- "--certificatesResolvers.le.acme.httpChallenge=true"
- "--certificatesResolvers.le.acme.httpChallenge.entryPoint=web"
ports:
# The HTTP port
- "80:80"
- "443:443"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
networks:
- NanoWall-Net
volumes:
- /acme.json/etc/traefik/acme.json
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: always
It may not be the only issue, but you are missing a colon in your traefik volumes section. You have:
- /acme.json/etc/traefik/acme.json
I think it should be (assuming your host location is really /acme.json and not ./acme.json or in some other directory):
- /acme.json:/etc/traefik/acme.json
That said, I have also been having an issue where traefik always wants it in /acme.json, so I just put it there instead of in /etc/traefik/acme.json .

Traefik recreat all ACME certificate at each restart

I'm currently configuring Traefik with Let's encrypt.
But I have an issue : Each time I restart the container, Traefik regenerate all certificate. Even those already in the acme.json file :(.
But my server do automatic restart sometimes. So, within a day, Let's encrypt does not want to give me more certificates.
Do any way exist to rsolve this issue ? :(
My docker-compose.yml file :
services:
traefik:
image: traefik:alpine
restart: always
container_name: traefik
networks:
- default
- traefik_proxy
ports:
- "80:80"
- "443:443"
- "8000:8080"
volumes:
# traefik configuration files
- ${TRAEFIK_CONTAINERS_CONFIG_DIR}/traefik.toml:/etc/traefik/traefik.toml
- ${TRAEFIK_CONTAINERS_CONFIG_DIR}/acme.json:/acme.json
- ${TRAEFIK_CONTAINERS_CONFIG_DIR}/log:/var/log/traefik/
- ${TRAEFIK_CONTAINERS_CONFIG_DIR}/shared:/shared/
# Docker
- /var/run/docker.sock:/var/run/docker.sock
# We have to link the authentification dir to use the differents .htpasswd
- ${AUTHENTIFICATION_FILES_DIRECTORY}:/htpasswd/
labels:
- "traefik.enable=true"
- "traefik.frontend.rule=Host:reverse.${DOMAIN_NAME}"
- "traefik.port=8080"
- "traefik.frontend.auth.basic.usersFile=${TRAEFIK_DEFAULT_AUTHENTIFICATION_FILE}"
- "traefik.tags=proxy"
- "traefik.docker.network=traefik_proxy"

Resources