I have read Traefik Docker TLS Challenge Documentation - Traefik and, unless I missed something, then there is in my opinion one step missing: "bootstrap" Traefik with a valid SSL certificate.
Step 1
Bootstrap Traefik with a Valid SSL Certificate.
Otherwise, if you just jump to TLSChallenge / TLS-ALPN-01, you will get an error like:
Unable to obtain ACME certificate for domains \"SUB.MYDOMAIN.TLD\": unable to generate a certificate for the domains [SUB.DOMAIN.TLD]: error: one or more domains had a problem:\n[SUB.DOMAIN.TLD] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized :: Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge\n" ACME CA="https://acme-v02.api.letsencrypt.org/directory"
Therefore, what worked for me, is to issue the initial Letsencrypt Certificate using the HTTP Challenge.
The HTTPS permanent redirect needs to be temporarily disabled because the HTTP ACME challenge occurs on port 80 !
Basically one need to disable:
a. Permanent Redirect Disable: #- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
b. TLS Challenge Disable: #- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
And one need to enable
a. HTTP Challenge Enable: - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
b. HTTP Challenge Entrypoint Enable: - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
version: '3.9'
networks:
traefik:
external: true
services:
traefik:
image: traefik:latest
hostname: SUB.DOMAIN.TLD
domainname: SUB.DOMAIN.TLD
restart: unless-stopped
container_name: traefik
ports:
- 80:80
- 443:443
networks:
- traefik
volumes:
- /run/user/1001/podman/podman.sock:/var/run/docker.sock:ro
- ~/data/traefik/letsencrypt:/letsencrypt
- ~/config/traefik:/config
- ~/certificates/traefik:/certificates
- ~/log/traefik:/log
command:
## Logging
# Server Log
- "--log.level=DEBUG"
- "--log.filePath=/log/server/traefik.log"
# Error Log
- "--accesslog=true"
- "--accesslog.filePath=/log/access/access.log"
## Dashboard & API
- "--api"
- "--api.insecure=false" # production = false , development = true
- "--api.dashboard=true"
## EntryPoints
# Unsecure Connection - Redirect to Secure
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entryPoints.web.http.redirections.entrypoint.scheme=https"
# - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
# Secure Connection
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http.tls=true"
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
- "--entryPoints.websecure.transport.respondingTimeouts.readTimeout=420"
- "--entryPoints.websecure.transport.respondingTimeouts.writeTimeout=420"
- "--entryPoints.websecure.transport.respondingTimeouts.idleTimeout=420"
## Letsencrypt Configuration
# - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" # For testing only
- "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory" # Production - Rated limited !!!
- "--certificatesresolvers.letsencrypt.acme.email=MYEMAIL@DOMAIN.TLD"
# - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
## Docker / Podman Intergration
- "--providers.docker=true"
- "--providers.docker.exposedByDefault=false"
- "--providers.docker.watch=false"
- "--providers.docker.swarmMode=false"
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
## Other
- "--serversTransport.insecureSkipVerify=true"
# No Telemetry
- "--global.sendAnonymousUsage=false"
labels:
# Enable Traefik
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.dashboard.rule=Host(`SUB.DOMAIN.TLD`) && PathPrefix(`/api` , `/dashboard`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=authtraefik"
# Authentication for Dashboard access
- "traefik.http.middlewares.authtraefik.basicauth.usersfile=/config/users"
Step 2
Issue docker-compose up -d
or podman-compose up -d
in my case.
Step 3
Verify that the initial certificate works by visiting the website and checking the server log.
Step 4
Reverse the Operations done in Step 1.
Basically one need to enable:
a. Permanent Redirect Enable: - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
b. TLS Challenge Enable: - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
And one need to disable
a. HTTP Challenge Disable: #- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
b. HTTP Challenge Entrypoint Disable: #- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
Final compose.yml
file:
version: '3.9'
networks:
traefik:
external: true
services:
traefik:
image: traefik:latest
hostname: SUB.DOMAIN.TLD
domainname: SUB.DOMAIN.TLD
restart: unless-stopped
container_name: traefik
ports:
- 80:80
- 443:443
networks:
- traefik
volumes:
- /run/user/1001/podman/podman.sock:/var/run/docker.sock:ro
- ~/data/traefik/letsencrypt:/letsencrypt
- ~/config/traefik:/config
- ~/certificates/traefik:/certificates
- ~/log/traefik:/log
command:
## Logging
# Server Log
- "--log.level=DEBUG"
- "--log.filePath=/log/server/traefik.log"
# Error Log
- "--accesslog=true"
- "--accesslog.filePath=/log/access/access.log"
## Dashboard & API
- "--api"
- "--api.insecure=false" # production = false , development = true
- "--api.dashboard=true"
## EntryPoints
# Unsecure Connection - Redirect to Secure
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entryPoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
# Secure Connection
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http.tls=true"
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
- "--entryPoints.websecure.transport.respondingTimeouts.readTimeout=420"
- "--entryPoints.websecure.transport.respondingTimeouts.writeTimeout=420"
- "--entryPoints.websecure.transport.respondingTimeouts.idleTimeout=420"
## Letsencrypt Configuration
# - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" # For testing only
- "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory" # Production - Rated limited !!!
- "--certificatesresolvers.letsencrypt.acme.email=MYEMAIL@DOMAIN.TLD"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
# - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
# - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
## Docker / Podman Intergration
- "--providers.docker=true"
- "--providers.docker.exposedByDefault=false"
- "--providers.docker.watch=false"
- "--providers.docker.swarmMode=false"
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
## Other
- "--serversTransport.insecureSkipVerify=true"
# No Telemetry
- "--global.sendAnonymousUsage=false"
labels:
# Enable Traefik
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.dashboard.rule=Host(`SUB.DOMAIN.TLD`) && PathPrefix(`/api` , `/dashboard`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=authtraefik"
# Authentication for Dashboard access
- "traefik.http.middlewares.authtraefik.basicauth.usersfile=/config/users"
Step 5
Issue docker-compose up -d
or podman-compose up -d
and once again visit the website and check the server log to make sure that everything is working.