This is the configuration I'm using.
traefik.toml
[api]
dashboard = true
[providers]
[providers.file]
filename = "/etc/traefik/dynamic.toml"
watch = true
[entrypoints]
[entrypoints.HttpEntrypoint]
address = ":80"
[entrypoints.HttpsEntrypoint]
address = ":443"
[certificatesResolvers.LetsEncrypt.acme]
email = "**EMAIL**"
storage = "/acme/acme.json"
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
[certificatesResolvers.LetsEncrypt.acme.httpChallenge]
entryPoint = "HttpEntrypoint"
[metrics.prometheus]
[accessLog]
[ping]
[log]
level = "DEBUG"
dynamic.toml
[http.routers.UserRedirectRouter]
entrypoints = ["HttpEntrypoint"]
rule = "Host(`**DOMAIN**`)"
middlewares = ["HttpsRedirectMiddleware"]
service = "noop@internal"
[http.routers.UserOpenapiRouter]
entrypoints = ["HttpsEntrypoint"]
rule = "Host(`**DOMAIN**`) && PathPrefix(`/api`)"
middlewares = ["RatelimitMiddleware", "ApiStripprefixMiddleware"]
service = "UserOpenapiService"
[http.routers.UserOpenapiRouter.tls]
certResolver = "LetsEncrypt"
[[http.routers.UserOpenapiRouter.tls.domains]]
main = "**DOMAIN**"
[http.routers.UserRouter]
entrypoints = ["HttpsEntrypoint"]
rule = "Host(`**DOMAIN**`)"
middlewares = ["UserCorsMiddleware"]
service = "UserService"
[http.routers.UserRouter.tls]
certResolver = "LetsEncrypt"
[[http.routers.UserRouter.tls.domains]]
main = "**DOMAIN**"
[http.routers.UserUploadRouter]
entrypoints = ["HttpsEntrypoint"]
rule = "Host(`**DOMAIN**`) && PathPrefix(`/upload/`)"
middlewares = ["RatelimitMiddleware"]
service = "UserTusdService"
[http.routers.UserUploadRouter.tls]
certResolver = "LetsEncrypt"
[[http.routers.UserUploadRouter.tls.domains]]
main = "**DOMAIN**"
[http.routers.UserDownloadRouter]
entrypoints = ["HttpsEntrypoint"]
rule = "Host(`**DOMAIN**`) && PathPrefix(`/download`) && Method(`GET`)"
middlewares = ["RatelimitMiddleware", "UserCorsMiddleware"]
service = "UserService"
[http.routers.UserDownloadRouter.tls]
certResolver = "LetsEncrypt"
[[http.routers.UserDownloadRouter.tls.domains]]
main = "**DOMAIN**"
[http.services]
[http.services.UserOpenapiService.loadBalancer]
[[http.services.UserOpenapiService.loadBalancer.servers]]
url = "http://user-service:8044"
[http.services.UserService.loadBalancer]
[[http.services.UserService.loadBalancer.servers]]
url = "http://user-service:80"
[http.services.UserTusdService.loadBalancer]
[[http.services.UserTusdService.loadBalancer.servers]]
url = "http://user-service:1080"
[http.middlewares]
[http.middlewares.UserCorsMiddleware.headers]
accessControlAllowOrigin = "*"
accessControlAllowMethods = ["GET", "OPTIONS"]
accessControlAllowHeaders = ["Content-Type", "Authorization"]
accessControlMaxAge = 100
[http.middlewares.ApiStripprefixMiddleware.stripPrefix]
prefixes = ["/api"]
[http.middlewares.RatelimitMiddleware.rateLimit]
average = 1000
burst = 500
[http.middlewares.HttpsRedirectMiddleware.redirectScheme]
scheme = "https"
permanent = true
Traefik is running on kubernetes using the spec:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: traefik
labels:
user.service: traefik
spec:
serviceName: traefik
replicas: 1
selector:
matchLabels:
user.service: traefik
template:
metadata:
labels:
user.service: traefik
spec:
containers:
- name: traefik-container
image: traefik:v2.2.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
- containerPort: 443
- containerPort: 8080
volumeMounts:
- name: traefik-volume
mountPath: /etc/traefik
readOnly: true
- name: traefik-acme-volume
mountPath: /acme
readinessProbe:
httpGet:
path: /ping
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /ping
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
volumes:
- name: traefik-volume
secret:
secretName: traefik-secret
items:
- key: traefik.toml
path: traefik.toml
- key: dynamic.toml
path: dynamic.toml
volumeClaimTemplates:
- metadata:
name: traefik-acme-volume
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: traefik
labels:
user.service: traefik
spec:
selector:
user.service: traefik
ports:
- protocol: TCP
port: 80
name: traefik-container-0
- protocol: TCP
port: 443
name: traefik-container-1
type: NodePort
externalIPs:
- **SERVER_IP**
With the firewall set to allow port 80/443 from anywhere. I can see in the Traefik logs that it tries to request the certificates but ends in an error:
time=\"2020-05-07T09:27:02Z\"
level=debug
msg=\"legolog: [INFO] [**DOMAIN**] acme: use http-01 solver\"
time=\"2020-05-07T09:27:02Z\"
level=debug
msg=\"legolog: [INFO] [**DOMAIN**] acme: Trying to solve HTTP-01\"
time=\"2020-05-07T09:27:06Z\"
level=debug
msg=\"legolog: [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/54807777\"
time=\"2020-05-07T09:27:06Z\"
level=debug
msg=\"legolog: [INFO] Unable to deactivate the authorization: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/54807777\"
time=\"2020-05-07T09:27:06Z\"
level=error
msg=\"Unable to obtain ACME certificate for domains \\\"**DOMAIN**\\\" : unable to generate a certificate for the domains [**DOMAIN**]: error: one or more domains had a problem:\\n[**DOMAIN**] acme: error: 400 :: urn:ietf:params:acme:error:connection :: Fetching http://**DOMAIN**/.well-known/acme-challenge/KT8HsuNSvwrzYO9_rrCaGTp-FxmULjE2t8z0ti8R_1c: Connection refused, url: \\n\"
providerName=LetsEncrypt.acme
If I then take the .well-known URL from the last error message and wget it from outside the network:
wget http://**DOMAIN**/.well-known/acme-challenge/KT8HsuNSvwrzYO9_rrCaGTp-FxmULjE2t8z0ti8R_1c
Resolving **DOMAIN** (**DOMAIN**)... **SERVER_IP**
Connecting to **DOMAIN** (**DOMAIN**)|**SERVER_IP**|:80... connected.
HTTP request sent, awaiting response...
And while that's happening I get the traefik log:
time=\"2020-05-07T09:43:03Z\"
level=debug
msg=\"Retrieving the ACME challenge for token KT8HsuNSvwrzYO9_rrCaGTp-FxmULjE2t8z0ti8R_1c...\"
providerName=LetsEncrypt.acme
It eventually times out and returns a 404 status code but as far as I can tell it means the certificate resolver/ACME is configured correctly and accessible publically over the internet. I've double checked the DNS records have propagated and that there are no firewall rules blocking any incoming traffic on port 80/443 but I still end up with Traefik using the default certificates and the ACME connection refused error.