Cloudflare
Cloudflare is the service I use for pretty much everything on the outside of the home network. It is the registrar for saxobroko.com, handles DNS, SSL, WAF, Cloudflare Tunnels (because I am behind CGNAT), and hosts SaxDocs on Cloudflare Pages.
How to login
- Go to dash.cloudflare.com
- Enter account details
- It should come up with a 2FA prompt. It'll use the Yubikey
- Now you're logged in
How homelab traffic works (CGNAT + tunnels)
I cannot port-forward from the internet anymore. Instead:
Most homelab subdomains use the block no aus WAF rule (Australia only). SaxDocs on Pages is public unless Cloudflare Access is enabled.
Full subdomain list: Network
Hosting SaxDocs on Cloudflare Pages
SaxDocs used to deploy to GitHub Pages and also ran locally on the PC behind NPM. The current setup builds in GitHub Actions and hosts on Cloudflare Pages instead.
One-time setup
1. Create a Cloudflare API token
- In Cloudflare, go to My Profile > API Tokens
- Click Create Token
- Use the Edit Cloudflare Workers template, or create a custom token with:
- Account > Cloudflare Pages > Edit
- Account > Account Settings > Read
- Zone > DNS > Edit (needed to remove old home-network DNS records)
- Zone > Zone > Read (optional fallback for DNS cleanup)
- Copy the token. You won't see it again.
2. Get your Account ID
- Open the Cloudflare dashboard
- Select any site (e.g. saxobroko.com)
- On the right sidebar under API, copy the Account ID
3. Add GitHub secrets
In github.com/saxobroko/SaxDocs/settings/secrets/actions, add:
| Secret | Value |
|---|---|
CLOUDFLARE_API_TOKEN |
The token from step 1 |
CLOUDFLARE_ACCOUNT_ID |
The account ID from step 2 |
CLOUDFLARE_ZONE_ID |
Optional. Zone ID for saxobroko.com if DNS cleanup fails |
4. Create the Pages project
Push to main once the secrets are set. GitHub Actions will run wrangler pages deploy and create a project called saxdocs automatically on the first successful deploy.
Or create it manually:
- Go to Workers & Pages > Create > Pages > Connect to Git
- Select the SaxDocs repo
- Set build command to
pip install -r requirements.txt && mkdocs build - Set build output directory to
site - Set
PYTHON_VERSIONenvironment variable to3.12
The GitHub Actions workflow is preferred because it keeps the build in one place and doesn't need Cloudflare to install Python dependencies on every deploy.
5. Attach the custom domain
- Open the saxdocs Pages project
- Go to Custom domains
- Add
docs.saxobroko.com - Cloudflare will create or update the DNS record for you since saxobroko.com is already on Cloudflare
6. Remove the old local proxy setup
If docs.saxobroko.com still points at the home network, fix the DNS:
- Go to Websites > saxobroko.com > DNS
- Find the
docsrecord - If it is a CNAME to
local.saxobroko.comor a tunnel hostname, delete it - Let Cloudflare Pages recreate it when you add the custom domain in step 5
Also remove the docs proxy host from NPM if it is still there. It is no longer needed.
7. WAF rules
Most of my subdomains use the block no aus rule. Public docs probably should not be geo-blocked. When adding docs.saxobroko.com to Cloudflare rules, skip the WAF geo rule for docs unless you actually want it restricted to Australia.
The localnet full strict ssl rule is for tunnel-backed services at home. Cloudflare Pages handles SSL on its own, so docs does not need that rule.
Consider Cloudflare Access on SaxDocs if personal pages should require login.
Checking deploys
- GitHub Actions: github.com/saxobroko/SaxDocs/actions
- Cloudflare Pages: Workers & Pages > saxdocs > Deployments
- Live site: docs.saxobroko.com
How to add a new homelab site (tunnel era)
The old workflow was CNAME → local.saxobroko.com. That does not work behind CGNAT. Use a tunnel instead.
1. Run the app on TrueNAS
Deploy via Docker/Apps on the NAS at 192.168.2.203. Note the internal hostname and port.
2. Add a Cloudflare Tunnel public hostname
- Cloudflare dashboard → Zero Trust → Networks → Tunnels
- Open the existing tunnel (or create one with
cloudflaredon TrueNAS) - Public Hostname → Add:
- Subdomain: e.g.
example - Domain:
saxobroko.com - Service: internal URL, e.g.
http://192.168.2.203:8080orhttp://npm:81if going through NPM - Save
Cloudflare creates DNS automatically for tunnel hostnames — no manual CNAME to local needed.
3. Optional — route through NPM
If the app needs a custom path, multiple backends, or a single entry point, add a Proxy Host in NPM first, then point the tunnel at NPM's internal port.
4. WAF rules
Add the new hostname to existing rules so SSL and geo-blocking match the rest of homelab:
- Websites → saxobroko.com → Rules → Configuration Rules → localnet full strict ssl
- Edit the expression — append:
- Security → WAF → Custom rules → block no aus
- Same append (skip this step for intentionally public sites like docs or blog)
Replace EXAMPLE with your subdomain.
Legacy: CNAME to local (pre-CGNAT)
If you ever regain a routable public IP, the old steps were:
- Add a CNAME record:
EXAMPLE→local.saxobroko.com - Add the hostname to localnet full strict ssl and block no aus as above

This is kept for reference only. Current setup uses tunnels — see Network.
Related
- Authentik / Cloudflare Access — protect SaxDocs and SSO
- Network — full subdomain table
- NPM — reverse proxy on TrueNAS
- This docs site — MkDocs build and page history