minimalistic setup
by intent not using docker and/or kube, aka plain brew install traefik
or even better download latest binary from Github
before proceeding to launchd and/or other stuff make sure you can run it manually
IMPORTANT: make sure there are no configuration files in working directory, they will override your command line arguments
huge thanks to @bluepuma77 for pointing this out
here is minimal providers.yml file:
http:
routers:
foo:
entryPoints:
- http # 👈 you may want to remove this as well in future
- https
service: foo
rule: Host(`foo.example.com`)
# 👆 note: we are not passing any tls here, instead, entrypoint tls is used
services:
foo:
loadBalancer:
servers:
- url: http://localhost:5000/
and here is how to run it:
CLOUDFLARE_DNS_API_TOKEN=xxxxx traefik \
--log.level=INFO \
--providers.file.filename=/opt/homebrew/etc/traefik/provider.yml \
--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare \
--certificatesResolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1:53,1.0.0.1:53 \
--certificatesresolvers.letsencrypt.acme.email=hello@gmail.com \
--certificatesresolvers.letsencrypt.acme.storage=/opt/homebrew/etc/traefik/acme.json \
--entrypoints.http.address=:80 \
--entrypoints.https.address=:443 \
--entrypoints.https.http.tls.certResolver=letsencrypt \
--entrypoints.https.http.tls.domains[0].main=example.com \
--entrypoints.https.http.tls.domains[0].sans=*.example.com
after a while, acme.json
will be filled with desired wildcard certificate, and you may start adding other routes
learning point
Traefik does not log if it did load some configurations from files, but it does log final configuration, to see it, make sure to switch log level to DEBUG
and you should see something like:
2025-03-13T11:13:09+02:00 DBG github.com/traefik/traefik/v3/cmd/traefik/traefik.go:114 > Static configuration loaded [json] staticConfiguration={...materialized json configuration will be here, have careful look if everything is configured as you expect}
launchd
note for macos users, brew will create its own plist file and override each time, for this setup to work you need modify it and pass environment variable for cloudflare
so instead of relying on brew services, just copy and modify /opt/homebrew/Cellar/traefik/3.3.4/homebrew.mxcl.traefik.plist
instead, aka:
cp /opt/homebrew/Cellar/traefik/3.3.4/homebrew.mxcl.traefik.plist ~/Library/LaunchAgents/traefik.plist
# vim traefik.plist # 👈 change label, add environment variables
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/traefik.plist
for environment variables, inside plist element add following:
<key>EnvironmentVariables</key>
<dict>
<key>CLOUDFLARE_DNS_API_TOKEN</key>
<string>xxxxx</string>
</dict>
also, depending on your preferences, pass cli params or config file
original question
Hello, trying to figure out how to get Traefik behind Cloudflare up and running and stuck with very first steps of wildcard certs
Here is what I'm trying to do
CLOUDFLARE_DNS_API_TOKEN=xxxxxxxxxxxx traefik \
--log.level=INFO \
--providers.file.filename=/opt/homebrew/etc/traefik/provider.yml \
--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare \
--certificatesResolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1:53,1.0.0.1:53 \
--certificatesresolvers.letsencrypt.acme.email=hello@gmail.com \
--certificatesresolvers.letsencrypt.acme.storage=/opt/homebrew/etc/traefik/acme.json \
--entrypoints.http.address=:80 \
--entrypoints.https.address=:443 \
--entrypoints.https.http.tls.certResolver=letsencrypt \
--entrypoints.https.http.tls.domains[0].main=example.com \
--entrypoints.https.http.tls.domains[0].sans=*.example.com
by intent running exactly like this no docker, no kube, no unrelevant config options
For provider, as you may gues I have something as simple as:
http:
routers:
foo:
entryPoints:
- http
- https
service: foo
rule: Host(`foo.example.com`)
bar:
entryPoints:
- http
- https
service: bar
rule: Host(`bar.example.com`)
tls:
certresolver: cloudflare
services:
foo:
loadBalancer:
servers:
- url: http://localhost:5000/
bar:
loadBalancer:
servers:
- url: http://192.168.105.109:3000/
I was expecting wildcard certificate to be created and reused for all routers but that's not a case, if we do not pass tls
route does not terminate ssl at all, if we do pass tls
it seems like it does override the one defined in entrypoint (which is also mentioned in the docs)
also there is:
--tls.stores.default.defaultGeneratedCert.resolver=letsencrypt \
--tls.stores.default.defaultGeneratedCert.domain.main=example.com \
--tls.stores.default.defaultGeneratedCert.domain.sans=*.example.com
which seems to do nothing
so, configuration it self is applied, I see that in the logs, certificate for bar.example.com is generatd, i see that in acme.json, so, technically, setup is working, but not the way expected - e.g. it will create certs for each and every route, which I want to bypass
temporary workaround
So far, I was able to achieve what i want with following setup:
CLOUDFLARE_DNS_API_TOKEN=xxxxxxxxxx traefik \
--log.level=INFO \
--providers.file.filename=/opt/homebrew/etc/traefik/provider.yml \
--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare \
--certificatesResolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1:53,1.0.0.1:53 \
--certificatesresolvers.letsencrypt.acme.email=hello@gmail.com \
--certificatesresolvers.letsencrypt.acme.storage=/opt/homebrew/etc/traefik/acme.json \
--entrypoints.http.address=:80 \
--entrypoints.https.address=:443
Note: I have removed domains and sans from entrypoint
and in my providers I do:
bar:
entryPoints:
- http
- https
service: bar
rule: Host(`bar.example.com`)
tls:
certresolver: cloudflare
domains:
- main: example.com
sans:
- "*.example.com"
baz:
entryPoints:
- http
- https
service: bar
rule: Host(`baz.example.com`)
tls:
certresolver: cloudflare
domains:
- main: example.com
sans:
- "*.example.com"
which is kind of fine, but i was wondering if I can keep it on entrypoint level so no need to copy paste it every time