MacOS Traefik Cloudflre
Keeping an note of exposing local MacOS with Traefik behind Cloudflare
By intent, in my setup I did not use Docker or Kubernetes.
Notes:
- only HTTP traffic is allowed
- requests are allowed only from Cloudflare
- requests are verified with mTLS
- obviously for this to work, port forwarding and static IP should be configured in home router
- remember that Cloudflare can proxy only http traffic, so it is not possible to proxy lets say Postgresql
brew install traefik
yep, that's it :)
defaults:
- plist -
/opt/homebrew/Cellar/traefik/3.3.4/homebrew.mxcl.traefik.plist
- config -
/opt/homebrew/etc/traefik/traefik.toml
- logs -
/opt/homebrew/var/log/traefik.log
in my case, I need CLOUDFLARE_DNS_API_TOKEN
environment variable and brew will override plist, so going to have my own configurations
~/.config/traefik/static.yml
log:
# we need this for debugging, talke closer look at
# DBG github.com/traefik/traefik/v3/cmd/traefik/traefik.go:114 > Static configuration loaded [json] staticConfiguration={
# it will print actual configuration that Traefik uses
level: DEBUG
accessLog:
format: common
providers:
file:
filename: /Users/mini/.config/traefik/dynamic.yml
certificatesResolvers:
cloudflare:
acme:
email: [email protected]
storage: /Users/mini/.config/traefik/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- 1.1.1.1:53
- 1.0.0.1:53
metrics:
prometheus:
{}
#addEntryPointsLabels: true
#addRoutersLabels: true
#addServicesLabels: true
entryPoints:
# note: we have only https entrypoint, no http at all
https:
address: :443
# and it is set as default, so no need to specify it in routers
# as well as configuring redirects here and there
asDefault: true
http:
# here we are configuring default wildcard certificate
tls:
certResolver: cloudflare
domains:
- main: mac-blog.org.ua
sans:
- "*.mac-blog.org.ua"
# we need this one for traefik to log client ip
forwardedHeaders:
trustedIPs:
# https://www.cloudflare.com/ips-v4
- 173.245.48.0/20
- 103.21.244.0/22
- 103.22.200.0/22
- 103.31.4.0/22
- 141.101.64.0/18
- 108.162.192.0/18
- 190.93.240.0/20
- 188.114.96.0/20
- 197.234.240.0/22
- 198.41.128.0/17
- 162.158.0.0/15
- 104.16.0.0/13
- 104.24.0.0/14
- 172.64.0.0/13
- 131.0.72.0/22
# https://www.cloudflare.com/ips-v6
- 2400:cb00::/32
- 2606:4700::/32
- 2803:f800::/32
- 2405:b500::/32
- 2405:8100::/32
- 2a06:98c0::/29
- 2c0f:f248::/32
# quite simple but awesome plugin to protect some services
experimental:
plugins:
google-oidc-auth-middleware:
moduleName: github.com/andrewkroh/google-oidc-auth-middleware
version: v0.1.0
~/.config/traefik/dynamic.yml
http:
routers:
# note how simple routers are - just define host and service and you are ready to go
foo:
rule: Host(`foo.mac-blog.org.ua`)
service: foo
bar:
rule: Host(`bar.mac-blog.org.ua`)
service: bar
middlewares:
- auth
services:
foo:
loadBalancer:
servers:
- url: http://localhost:3000/
bar:
loadBalancer:
servers:
- url: http://localhost:9090/
middlewares:
# just as example, we can use built in basic asuth
basicauth:
basicAuth:
users:
# htpasswd -nb hello world
- hello:$apr1$xwaBOwva$/FgrbWFvzTIRvm4p9LK4h1
# added in static.yml
auth:
plugin:
google-oidc-auth-middleware:
authorized:
emails:
- [email protected]
cookie:
secret: some_random_string_at_least_32_characters_longs
# insecure: true
name: google
oidc:
clientID: xxx.apps.googleusercontent.com
clientSecret: GOCSPX-xxxxxxxxxxxxxxxxxxx
tls:
options:
default:
# require SNI to be present and valid
sniStrict: true
# cloudflare origin pull certificate
clientAuth:
caFiles:
# https://developers.cloudflare.com/ssl/static/authenticated_origin_pull_ca.pem
- /Users/mini/.config/traefik/authenticated_origin_pull_ca.pem
clientAuthType: RequireAndVerifyClientCert
~/.config/traefik/traefik.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>traefik</string>
<key>LimitLoadToSessionType</key>
<array>
<string>Aqua</string>
<string>Background</string>
<string>LoginWindow</string>
<string>StandardIO</string>
<string>System</string>
</array>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/opt/traefik/bin/traefik</string>
<string>--configfile=/Users/mini/.config/traefik/static.yml</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>CLOUDFLARE_DNS_API_TOKEN</key>
<string>TODO_PASTE_CLOUDFLARE_ACCESS_TOKEN_HERE</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/opt/homebrew/var/log/traefik.log</string>
<key>StandardOutPath</key>
<string>/opt/homebrew/var/log/traefik.log</string>
<key>WorkingDirectory</key>
<string>/opt/homebrew/var</string>
</dict>
</plist>
Cloudflare access token should have Zone Read and DNS Edit permissions
While you are configuring everything you always may test it like so:
CLOUDFLARE_DNS_API_TOKEN=xxxxxxxx traefik --configfile=/Users/mini/.config/traefik/static.yml
And finally:
ln -s ~/.config/traefik/traefik.plist ~/Library/LaunchAgents/traefik.plist
launchctl load ~/Library/LaunchAgents/traefik.plist
Other commands used often:
ln -s ~/.config/traefik/traefik.plist ~/Library/LaunchAgents/traefik.plist
launchctl load ~/Library/LaunchAgents/traefik.plist
launchctl unload ~/Library/LaunchAgents/traefik.plist
rm ~/Library/LaunchAgents/traefik.plist
tail -f /opt/homebrew/var/log/traefik.log
ps aux | grep traefik