MkDocs + Cloudflare Pages: Full Installation Guide¶
End-to-end setup for the eco|monetize internal documentation platform. Covers nameserver migration, Pages project creation, GitHub Actions wiring, and Cloudflare Access. Written from a live install completed 2026-04-22 — UI descriptions match the actual Cloudflare interface as of that date.
Deployment targets¶
| Site | Cloudflare project | URL | Auth |
|---|---|---|---|
| Internal ops docs (Phase 1) | eco-docs-internal |
docs.ecomonetize.com |
Cloudflare Access — invite only |
| Public ERI docs (Phase 2) | eco-docs-public |
help.ecomonetize.com |
Public |
This guide covers Phase 1. Phase 2 follows the same steps with different project name and domain.
Part 1 — GoDaddy → Cloudflare Nameserver Migration¶
This is the single blocking dependency for everything else. Both subdomains and Cloudflare Access require Cloudflare to be authoritative for ecomonetize.com.
Time: 15 min setup + up to 48 hrs propagation (typically 1–4 hrs)
1.1 Add the domain to Cloudflare¶
- Log in to dash.cloudflare.com as
info@ecomonetize.com - Click Add a domain (top of the home dashboard)
- Enter
ecomonetize.com→ Continue - Select Free plan → Continue
Cloudflare auto-scans your GoDaddy DNS records and imports them.
1.2 Review imported DNS records¶
Cloudflare shows you the records it found. Before continuing, verify:
- A records — your existing root/www entries are present
- MX records — Google Workspace mail records are present (
aspmx.l.google.comand alternates). If missing, add them manually now — email will break after the nameserver switch if these are absent. - TXT records — SPF, DKIM, DMARC, Google site verification all imported
When satisfied, click Continue.
1.3 Get your Cloudflare nameservers¶
Cloudflare assigns two nameservers unique to your account. They look like:
Copy both. You need them in the next step.
1.4 Update nameservers in GoDaddy¶
- Log in to godaddy.com → My Products → find
ecomonetize.com→ DNS - Scroll to Nameservers → click Change
- Select Enter my own nameservers (advanced)
- Delete GoDaddy's nameservers, enter your two Cloudflare nameservers
- Click Save and confirm the warning
1.5 Wait for propagation¶
- Typical: 1–4 hours. Maximum: 48 hours.
- Check status: whatsmydns.net → search
ecomonetize.comtypeNS - Cloudflare sends a confirmation email to
info@ecomonetize.comwhen the zone goes Active
1.6 Verify the zone is Active¶
- dash.cloudflare.com → click
ecomonetize.com - Domains list shows
ecomonetize.comwith status Active - The domain overview page shows "Your domain is now protected by Cloudflare"
1.7 Add DNS records for docs subdomains¶
Once Active, go to DNS → Records → Add record and add:
| Type | Name | Content | Proxy |
|---|---|---|---|
| CNAME | docs |
eco-docs-internal.pages.dev |
Proxied (orange cloud) |
| CNAME | help |
eco-docs-public.pages.dev |
Proxied (orange cloud) — add when Phase 2 is ready |
Proxied is required. Non-proxied CNAMEs bypass Cloudflare Access.
Part 2 — Create the Cloudflare Pages Project¶
Important: Do NOT use the Git-connected path. Cloudflare's new UI requires a "Deploy command" for Git-connected projects, which conflicts with our GitHub Actions deploy approach. Use Direct Upload (drag and drop) to create the project shell, then GitHub Actions takes over all future deploys.
2.1 Navigate to Pages creation¶
- dash.cloudflare.com → left sidebar → Workers & Pages
- Click Create (top right)
- You land on "Ship something new" — this is the Workers creation screen by default
- Scroll to the bottom and click "Get started" next to "Looking to deploy Pages?"
2.2 Choose Direct Upload¶
You'll see: "Get started with Pages. How would you like to begin?"
- Import an existing Git repository — do NOT use this
- Drag and drop your files — click this
2.3 Name the project¶
Enter project name: eco-docs-internal
You'll see: "Your project will be deployed to eco-docs-internal.pages.dev"
2.4 Create a placeholder zip to satisfy the upload requirement¶
Cloudflare requires at least one file to create the project. Run this in your terminal to create a placeholder zip:
mkdir -p ~/Desktop/eco-docs-placeholder && \
echo '<html><body>eco-docs-internal placeholder</body></html>' > ~/Desktop/eco-docs-placeholder/index.html && \
cd ~/Desktop && \
zip -r eco-docs-placeholder.zip eco-docs-placeholder && \
rm -r ~/Desktop/eco-docs-placeholder
This puts eco-docs-placeholder.zip on your Desktop.
2.5 Upload and deploy¶
- Drag
eco-docs-placeholder.zipfrom your Desktop into the Cloudflare upload area - Click Deploy site
You land on the project dashboard showing:
- Workers & Pages / eco-docs-internal
- Production deployment at eco-docs-internal.pages.dev — status: success
The placeholder content doesn't matter. GitHub Actions will overwrite it on the first real deploy.
Part 3 — Attach the Custom Domain¶
3.1 Open Custom Domains¶
On the eco-docs-internal project page: click the Custom domains tab at the top.
3.2 Enter the domain¶
Click Set up a custom domain → enter docs.ecomonetize.com → Continue
3.3 Confirm the DNS record¶
Cloudflare shows a "Confirm new DNS record" screen. It detects your existing CNAME (from Part 1 Step 1.7) and confirms:
| Type | Name | Content | TTL |
|---|---|---|---|
| CNAME | docs | eco-docs-internal.pages.dev | Auto |
Click Activate domain.
Cloudflare verifies the CNAME and activates the custom domain. https://docs.ecomonetize.com will route to the Pages project once DNS propagation is complete.
Part 4 — Wire Up GitHub Actions¶
This is what makes future deploys automatic. Every push to main that changes docs content will build and deploy to Cloudflare Pages without any manual steps.
4.1 Get your Cloudflare API token¶
Create a minimal-scope token dedicated to Pages deploys. Do NOT use the "Edit Cloudflare Workers" template — it includes unrelated permissions and the resulting token may lack the correct Pages scope.
- dash.cloudflare.com → top-right profile icon → My Profile → left sidebar → API Tokens
- Click + Create Token → scroll to bottom → Create Custom Token → Get started
- Token name:
MkDocs Deploy - Under Permissions, add one row:
- Dropdown 1:
Account - Dropdown 2:
Cloudflare Pages - Dropdown 3:
Edit - Under Account Resources:
Include→ selectecomonetize - Click Continue to summary → Create Token
- Copy the token value — shown only once
- Save to 1Password → item name:
Cloudflare-MkDocs-Deploy→ paste token into the credential field
To retrieve later: open 1Password → search Cloudflare-MkDocs-Deploy → copy the credential field value.
Security: Never paste the token value into chat or a terminal command that will be logged. If a token is accidentally exposed, rotate it immediately: My Profile → API Tokens → find the token → Roll. Update the 1Password item and the GitHub secret with the new value.
4.2 Get your Account ID¶
- dash.cloudflare.com → click
ecomonetize.comzone - Scroll to the bottom of the zone overview page — Account ID and Zone ID are listed there
- Copy the Account ID (Zone ID is not needed)
Alternatively, read it from your browser URL bar: dash.cloudflare.com/{account_id}/...
4.3 Add GitHub secrets¶
In the GitHub repo (eco-monetize/claude):
- Click the Settings tab (top nav bar)
- Left sidebar → scroll to "Security and quality" section → click Secrets and variables (has a dropdown arrow) → click Actions
- To add a new secret: click New repository secret → enter name and value → Add secret
- To update an existing secret: find the secret row → click the pencil icon on the right → paste new value → Update secret
| Secret name | Value |
|---|---|
CLOUDFLARE_API_TOKEN |
Token from Step 4.1 (retrieve from 1Password → Cloudflare-MkDocs-Deploy → credential field) |
CLOUDFLARE_ACCOUNT_ID |
Account ID from Step 4.2 |
Add or update each secret separately.
4.4 Verify the GitHub Actions workflow¶
The workflow file at .github/workflows/docs.yml should deploy via npx wrangler@latest with env vars set directly — do not use cloudflare/wrangler-action, which pins an old wrangler version (3.90.0) with broken auth handling for token-scoped deploys. The deploy step should look like:
- name: Deploy to Cloudflare Pages
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: npx --yes wrangler@latest pages deploy site --project-name=eco-docs-internal --commit-dirty=true
The workflow should NOT contain:
- actions/upload-pages-artifact
- actions/deploy-pages
- permissions: pages: write
- cloudflare/wrangler-action (pins old wrangler — see troubleshooting)
4.5 Trigger the first real deploy¶
Push any change to main on a docs-relevant path. The GitHub Actions workflow runs, builds the MkDocs site, and deploys to Cloudflare Pages. The placeholder content gets replaced.
Part 5 — Configure Cloudflare Access (Phase 1 only)¶
This gates docs.ecomonetize.com behind email-based one-time PIN login. Invited users get a code emailed to them — no VPN, no Tailscale, no password required.
5.1 Open Zero Trust¶
dash.cloudflare.com → left sidebar → Zero Trust (under "Protect & Connect")
First-time setup only: If this is your first time in Zero Trust, you'll be prompted to:
1. Choose your team name — enter ecomonetize → Next. This creates ecomonetize.cloudflareaccess.com as your login domain.
2. Choose a plan — select Free (covers up to 50 users, sufficient for team + investors + contractors)
3. You'll land on a "Get started with Zero Trust" screen with 4 options.
5.2 Navigate to Applications¶
From the Zero Trust "Get started" screen: - Click Get started next to "Set up secure access to private apps from any browser" - On the next screen ("What type of application are you securing?"), click Continue next to "Connect a private web application"
Or navigate directly: left sidebar → Access → Applications → Add an application
5.3 Choose application type¶
Select Self-hosted and private → Continue with Self-hosted and private
Do NOT use the "Tunnel" wizard that appears in some navigation paths — it asks for internal hostname and port, which is for self-hosted servers, not Cloudflare Pages.
5.4 Configure the application destination¶
The form uses split Subdomain + Domain fields (not a single domain field):
- Subdomain:
docs - Domain:
ecomonetize.com(select from dropdown) - Path: leave blank
5.5 Create the access policy¶
Scroll to Access policies → click Create new policy:
- Policy name:
Team + Approved External - Action: Allow
- Include rule: Emails → add each authorized email address (team, investors, contractors)
Click Save Policy. The policy appears in the list with Action: ALLOW.
5.6 Authentication settings¶
In the Authentication section: - Accept all available identity providers — leave as-is (toggles based on your identity provider config) - Apply instant authentication — ON (skips provider selection when only one method is available)
This configures one-time PIN via email as the login method. Users receive a code at their authorized email address.
5.7 Save the application¶
Details section (bottom of page):
- Name: docs (auto-generated from subdomain — leave as-is)
- Session duration: 24 hours
Click Create. The Applications list shows docs → docs.ecomonetize.com → SELF-HOSTED with 1 policy assigned.
Adding a new user later: Zero Trust → Access → Applications → docs → Edit → Access policies → edit Team + Approved External → add their email.
Post-install checklist¶
- [ ]
ecomonetize.comzone Active in Cloudflare Domains list - [ ] Email still working — send test to/from
info@ecomonetize.com - [ ] DNS Records show
docsCNAME →eco-docs-internal.pages.dev(Proxied) - [ ]
eco-docs-internalPages project exists and has a production deployment - [ ] Custom domain
docs.ecomonetize.comactivated in Pages project - [ ] GitHub secrets
CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_IDset - [ ] GitHub Actions workflow deploys successfully on push
- [ ] Cloudflare Access policy configured on
docs.ecomonetize.com - [ ]
docs.ecomonetize.comloads site and Access gate appears on first visit
Troubleshooting¶
| Problem | Fix |
|---|---|
| Cloudflare UI shows Workers creation instead of Pages | Scroll to bottom of "Ship something new" screen → click "Get started" next to "Looking to deploy Pages?" |
| Git-connected path requires a Deploy command | Don't use the Git path. Use "Drag and drop your files" instead. Our deploys are handled by GitHub Actions. |
| Cloudflare requires a folder or zip, not a single file | Create a zip: mkdir tmp && echo '<html><body>placeholder</body></html>' > tmp/index.html && zip -r placeholder.zip tmp |
| Email stopped working after nameserver migration | MX records didn't import. Add manually in Cloudflare DNS: aspmx.l.google.com (priority 1), alt1–alt4.aspmx.l.google.com (priority 5–10) |
docs.ecomonetize.com not resolving |
Check CNAME is Proxied (orange cloud). Non-proxied bypasses Cloudflare Access and won't route correctly. |
| Main site (ecomonetize.com) broken after nameserver migration | ecomonetize.com is hosted on Lovable. Lovable requires the root A record and www A record to be DNS only (not Proxied) in Cloudflare. Set both to DNS only — Lovable handles SSL directly. Only the docs CNAME should be Proxied. |
| Turning off proxy breaks docs Access gate | When Lovable support says "turn off proxy," that applies only to the root A records. The docs CNAME must stay Proxied (orange cloud) for Cloudflare Access to intercept requests. |
GitHub Actions deploy fails — Authentication error [code: 10000] |
Three possible causes: (1) Token missing Account → Cloudflare Pages → Edit permission — edit the token and add it. (2) cloudflare/wrangler-action pins wrangler 3.90.0 which has broken auth for token-scoped deploys — replace with npx --yes wrangler@latest per Step 4.4. (3) Wrong token in GitHub secret — verify CLOUDFLARE_API_TOKEN matches the value in 1Password → Cloudflare-MkDocs-Deploy → credential field. GitHub blanks the field when editing; just paste the correct value again to confirm. |
GitHub Actions deploy fails — Invalid access token [code: 9109] |
The token value in the GitHub secret is wrong or stale. Open 1Password → Cloudflare-MkDocs-Deploy → copy the credential field → GitHub → Settings → Security and quality → Secrets and variables → Actions → CLOUDFLARE_API_TOKEN → pencil → paste → Update secret. Note: editing a Cloudflare token's permissions does NOT change its value; only Rolling does. |
| Multiple similar tokens in 1Password causing confusion | Keep only one token for Pages deploy: Cloudflare-MkDocs-Deploy. Delete any old rotated tokens from both 1Password and the Cloudflare API Tokens dashboard (My Profile → API Tokens). The broad-scope "Cloudflare Agent Token" is auto-generated for MCP integrations — leave it alone. |
Deploy fails — search_index.json is 33.5 MiB |
Cloudflare Pages rejects files over 25 MiB. The MkDocs search index bloats when large content (e.g. session transcript archives) is included. Remove the offending content from the docs build — do not copy session archives into docs/ in the workflow. |
| GitHub Actions deploy fails | Check CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets are set. Verify project name matches exactly: eco-docs-internal. |
| Access gate not appearing | Check Zero Trust → Access → Applications. Confirm docs.ecomonetize.com is listed with an active Allow policy. |
| Cloudflare zone stuck on "Pending" | Nameserver propagation not complete. Check whatsmydns.net for NS records. Wait and recheck. |
Phase 2 differences (help.ecomonetize.com)¶
- Cloudflare Pages project name:
eco-docs-public - CNAME:
help→eco-docs-public.pages.dev - No Cloudflare Access policy — public site
- Separate GitHub Actions workflow targeting different content paths
- Requires CMO (Michelle) to author initial ERI content before first deploy
Related¶
Last verified¶
2026-04-23 — documentation.engineering. First successful deploy confirmed. Step 4.4 rewritten: cloudflare/wrangler-action replaced with npx --yes wrangler@latest — wrangler-action pins 3.90.0 which has broken auth for token-scoped deploys; wrangler 4.84.1 resolves correctly. Troubleshooting expanded: code: 9109 (invalid token value), multiple-token confusion, wrangler-action version issue. workflow_dispatch trigger added to workflow for manual reruns.