Traefik, docker and bunny.net - correct method to setup?

I have a configuration running with docker and traefik. For my DNS I make use of Bunny.net

What is the correct method to setup when I want to use, for example, emby? Because I cannot find why, but emby won't load when I use bunny rather than letsencrypt. Or, would you rather suggest using letsencrypt over bunny?

The thing is mostly, I cannot find much resources on the combination of traefik with bunny cdn / dns. Therefor I'm asking this question to get things right.

My current setup: Traefik docker compose

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    environment:
      - BUNNY_API_KEY=${BUNNY_API_TOKEN}
      - "--log.level=DEBUG"
    networks:
      - traefik-internal
      - traefik-external
    ports:
      - 80:80 # HTTP entryPoints
      - 443:443 # HTTPS entryPoints
      - 8080:8080 # Dashbaord WebGui 
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro 
      - ./traefik.yml:/traefik.yml:ro 
      - traefik-certs:/certs
      - "./logs:/var/log/traefik"
volumes:
  traefik-certs:
    name: traefik-certs

networks:
  traefik-internal:
  traefik-external:
    name: network_traefik_external
    external: true

traefik.yml

log:
  level: DEBUG   # Log level, options: ERROR, WARN, INFO, DEBUG
  filePath: "/var/log/traefik/traefik.log"
  maxBackups: 3
accessLog:
  filePath: "/var/log/traefik/access.log"   
  bufferingSize: 100
  filters:
    statusCodes: ["200-399"]
  format: json


api:
  dashboard: true # Optional can be disabled
  insecure: true # Optional can be disabled
  debug: true # Optional can be Enabled if needed for troubleshooting 
entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: proxy
certificatesResolvers:
  letsencrypt:
    acme:
      email: mail@mydomain.com
      storage: /certs/acme.json
      caServer: https://acme-v02.api.letsencrypt.org/directory # prod (default)
      #caServer: https://acme-staging-v02.api.letsencrypt.org/directory # staging
      httpChallenge:
        entryPoint: web
  bunny:
    bunny:
    acme:
      email: mail@mydomain.com
      storage: /certs/acme.json
      dnsChallenge:
        provider: bunny
  cloudflare:
    acme:
      dnsChallenge:
        provider: cloudflare
        delayBeforeCheck: 0
      email: mail@mydomain.com
experimental:
  plugins:
    fail2ban:
      moduleName: "github.com/tomMoulard/fail2ban"
      version: "v0.8.3"

emby docker compose

services:
  emby:
    image: emby/embyserver
    container_name: embyserver
    restart: unless-stopped
    environment:
      - UID=1000
      - GID=100
      - GIDLIST=100
    volumes:
      - ./config:/config # Configuration directory
      - /media_folder:/media_folder # Media directory
    ports:
      - 8096:8096 # HTTP port
      - 8920:8920 # HTTPS port
    devices:
      - /dev/dri:/dev/dri # VAAPI/NVDEC/NVENC render nodes
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.emby.rule=Host(`emby.mydomain.com`)"
      - "traefik.http.routers.emby.entrypoints=websecure"
      - "traefik.http.routers.emby.tls=true"
      - "traefik.http.routers.emby.tls.certresolver=bunny"
      - "traefik.http.services.emby.loadbalancer.server.port=8096"
networks:
  traefik:
    name: network_traefik_external
    external: true

Traefik usually connects to target services via a Docker network. Within a Docker network all ports are reachable.

In general target services should not publish ports (using ports:), as then Traefik (security) middlewares could potentially be circumvented by accessing the service directly.

Your issue might be related to using multiple Docker networks. If you do so, make sure to set docker.network globally on provider or individually on labels.

Enable and check Traefik debug log (doc) and Traefik access log in JSON format (doc). Check if TLS certs are present in acme.json file.

Finally your issue is not clear:

What error message do you get when doing what?

With bunny as CDN, Now I use SSL Certificate Checker to check the certificate and the message is "No certificates were found."

openssl s_client -showcerts -connect emby.mysite.com:443

gives:

CONNECTED(00000003)
4027E31650740000:error:0A000410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1599:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 322 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

tail -f logs/traefik.log
gives:

024-12-13T12:03:37+01:00 DBG github.com/traefik/traefik/v3/pkg/server/router/tcp/manager.go:237 > Adding route for emby.mysite.com with TLS options default entryPointName=websecure
2024-12-13T12:03:37+01:00 DBG github.com/traefik/traefik/v3/pkg/provider/acme/provider.go:384 > Trying to challenge certificate for domain [emby.mysite.com] found in HostSNI rule ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=letsencrypt.acme routerName=seafile@docker rule=Host(`emby.mysite.com`)
2024-12-13T12:03:37+01:00 DBG github.com/traefik/traefik/v3/pkg/provider/acme/provider.go:851 > Looking for provided certificate(s) to validate ["emby.mysite.com"]... ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=letsencrypt.acme routerName=seafile@docker rule=Host(`emby.mysite.com`)
2024-12-13T12:03:37+01:00 DBG github.com/traefik/traefik/v3/pkg/provider/acme/provider.go:895 > No ACME certificate generation required for domains ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory domains=["emby.mysite.com"] providerName=letsencrypt.acme routerName=seafile@docker rule=Host(`emby.mysite.com`)

I have the following bunny setup:

  • for the record, I use mysite.com and mydomain.com both are actually synonyms for the same private domain name that I use but I want to keep that private.

Now I have found the following error in the logs:

2024-12-13T16:43:39+01:00 DBG github.com/go-acme/lego/v4@v4.17.4/log/logger.go:48 > [INFO] [emby.mysite.com] acme: Cleaning DNS-01 challenge lib=lego
2024-12-13T16:43:40+01:00 ERR github.com/traefik/traefik/v3/pkg/provider/acme/provider.go:396 > Unable to obtain ACME certificate for domains error="unable to generate a certificate for the domains [emby.mysite.com]: error: one or more domains had a problem:\n[emby.mysite.com] acme: error: 400 :: urn:ietf:params:acme:error:dns :: DNS problem: NXDOMAIN looking up TXT for _acme-challenge.emby.mysite.com - check that a DNS record exists for this domain\n" ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory domains=["emby.mysite.com"] providerName=bunny.acme routerName=seafile-secure@docker rule=Host(`emby.mysite.com`)

So I have understood that bunny does not directly support acme challenges? How can I either use traefik to use the API Key of bunny or How can I let bunny handle the acme challenge?

Did you create a emby.mysite.com DNS record?

Yes. I managed to continue a bit more in the meanwhile.

I had to add a bunny zone id in the docker-compose.yml and also the NS weren't fully propagated in my domain name provider.

Those are now fixed. There is one more issue:

Websites prove their identity via certificates. Firefox does not trust this site because it uses a certificate that is not valid for emby.mysite.com. The certificate is only valid for the following names: *.b-cdn.net, b-cdn.net
 
Error code: SSL_ERROR_BAD_CERT_DOMAIN

This is what my browser shows me.

openssl s_client -showcerts -connect emby.mysite.com:443

CONNECTED(00000003)
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA
verify return:1
depth=0 CN = *.b-cdn.net
verify return:1
---
Certificate chain
 0 s:CN = *.b-cdn.net
   i:C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Nov  5 00:00:00 2024 GMT; NotAfter: Nov 11 23:59:59 2025 GMT
-----BEGIN CERTIFICATE-----
xxx
-----END CERTIFICATE-----
 1 s:C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA
   i:C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA384
   v:NotBefore: Nov  2 00:00:00 2018 GMT; NotAfter: Dec 31 23:59:59 2030 GMT
-----BEGIN CERTIFICATE-----
xxx
-----END CERTIFICATE-----
 2 s:C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
   i:C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Services
   a:PKEY: rsaEncryption, 4096 (bit); sigalg: RSA-SHA384
   v:NotBefore: Mar 12 00:00:00 2019 GMT; NotAfter: Dec 31 23:59:59 2028 GMT
-----BEGIN CERTIFICATE-----
xxx
-----END CERTIFICATE-----
 3 s:C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Services
   i:C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Services
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA1
   v:NotBefore: Jan  1 00:00:00 2004 GMT; NotAfter: Dec 31 23:59:59 2028 GMT
-----BEGIN CERTIFICATE-----
xxx
-----END CERTIFICATE-----
---
Server certificate
subject=CN = *.b-cdn.net
issuer=C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 6207 bytes and written 399 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: xxx
    Session-ID-ctx: 
    Resumption PSK: xxx
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 43200 (seconds)
    TLS session ticket: xxx
    Start Time: 1734169593
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: xxx
    Session-ID-ctx: 
    Resumption PSK: xxx
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 43200 (seconds)
    TLS session ticket: xxx
    Start Time: 1734169593
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK

The certificate you receive is for *.b-cdn.net. Is this one of your domains?

Otherwise it's probably the wrong server and a wrong IP in DNS.

b-cdn.net is bunny.net, the dns resolver (like cloudflare) that I make use of. But I have a proxy enabled in bunny. Could that cause the issue?

Well, it’s probably not coming from Traefik.

Enable and check Traefik access log in JSON format (doc) during requests.

Any suggestions for what I can do?

Using regular DNS, the domain should point to your server IP, requests should be visible in Traefik access log.

If you enable settings you are not sure about, maybe try to switch them off.

I found that in the CDN component of bunny I can enable SSL. This solves the issue. Not sure now actually how all the ssl certificates are linked but this works.

OT: How did you manage to achieve this lifetime? I always get 604800 (seconds).