Configuring SSL with mkcert and Docker

Hey,

I'm trying to configure traefik with custom certificates issued using mkcert, but traefik always seems to fall back to the generated cert.

docker-compose.yml

services:
  reverse-proxy:
    # The official v3 Traefik docker image
    image: traefik:v3.3
    restart: always
    ports:
      - "80:80"
      - "443:443"
      # The Web UI
      - "8888:8080"
    volumes:
      - ./traefik.yml:/etc/traefik/traefik.yml
      - ./traefik_dynamic.yml:/etc/traefik/traefik_dynamic.yml
      - ./cert:/etc/traefik/cert
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - demo

networks:
  demo:
    external: true

traefik.yml

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

api:
  insecure: true

providers:
  docker:
    defaultRule: 'Host(`{{ .Name }}.dev.xz`) || Host(`{{ .Name  }}.test`)'
    network: demo
  file:
    filename: "/etc/traefik/traefik_dynamic.yml"

log:
  level: DEBUG
type or paste code here

traefik_dynamic.yml

tls:
  certificates:
    - certFile: /etc/traefik/cert/cert.pem
      keyFile: /etc/traefik/cert/key.pem
  stores:
    default:
      defaultCertificate:
        - certFile: /etc/traefik/cert/cert.pem
          keyFile: /etc/traefik/cert/key.pem

Certificates are generated using this:
mkcert -cert-file cert/cert.pem -key-file cert/key.pem dev.xz "*.dev.xz"

I run docker-compose up to start traefik.

I run docker run --network demo --name whoami -d traefik/whoami to start the whoami container

After this I can successfully reach this container via traefik:

curl -I http://whoami.dev.xz
HTTP/1.1 200 OK

I'm using dnsqmasq so *.dev.xz resolves to 127.0.0.1:

nslookup whoami.dev.xz
Server:		127.0.0.1
Address:	127.0.0.1#53

Name:	whoami.dev.xz
Address: 127.0.0.1

All is fine up to this - but using SSL just refuses to use my provided default cert. It just falls back to the default self-signed traefik certificate:

2025-03-22T20:33:33Z DBG github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:321 > No default certificate, fallback to the internal generated certificate tlsStoreName=default

OpenSSL confirms this:

openssl s_client -connect whoami.dev.xz:443
Connecting to 127.0.0.1
CONNECTED(00000003)
depth=0 CN=TRAEFIK DEFAULT CERT
verify error:num=18:self-signed certificate
verify return:1
depth=0 CN=TRAEFIK DEFAULT CERT
verify return:1
---
Certificate chain
 0 s:CN=TRAEFIK DEFAULT CERT
   i:CN=TRAEFIK DEFAULT CERT
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Mar 22 20:22:41 2025 GMT; NotAfter: Mar 22 20:22:41 2026 GMT
---

What am I missing? Isn't this supposed to work?

You need to load the TLS certs in dynamic co fig file, then enable TLS on entrypoint or router.

entryPoints:
  websecure:
    address: ':443'
    http:
      tls: {}

Am I not loading TLS certs in dynamic config file? Isn't that what the providers.file section is for?

I've tried adding http.tls to the configuration file (like below) - it makes no difference.

diff -u traefik.old traefik.yml
--- traefik.old	2025-03-23 11:34:23
+++ traefik.yml	2025-03-23 11:33:30
@@ -3,6 +3,8 @@
     address: ":80"
   websecure:
     address: ":443"
+    http:
+      tls: {}

 api:
   insecure: true

Just noticed I'm actually getting an error on the traefik_dynamic.yml file:

2025-03-23T10:43:27Z DBG github.com/traefik/traefik/v3/pkg/provider/file/file.go:122 > add watcher on: /etc/traefik/traefik_dynamic.yml
2025-03-23T10:43:27Z ERR github.com/traefik/traefik/v3/pkg/provider/file/file.go:105 > Error while building configuration (for the first time) error="field not found, node: [0]" providerName=file

Turns out there was a dash too much in the defaultCertficate section of the traefik_dynamic.yml file.. :angry:

diff -u traefik_dynamic.old traefik_dynamic.yml
--- traefik_dynamic.old	2025-03-23 11:51:07
+++ traefik_dynamic.yml	2025-03-23 11:49:19
@@ -5,6 +5,6 @@
   stores:
     default:
       defaultCertificate:
-        - certFile: /etc/traefik/cert/cert.pem
-          keyFile: /etc/traefik/cert/key.pem
+        certFile: /etc/traefik/cert/cert.pem
+        keyFile: /etc/traefik/cert/key.pem

I didn't need the certificates section of the dynamic config (or the http.tls in the main configuration file). Now everything works as expected!

UPDATE: To get the routing to work the http.tls was indeed required.I'd still get the correct certificate, but the routing would not work so I'd just see the 404 page from traefik.