Hosting FreeDocStore - Zensical on Cloudflare
FreeDocStore publishes public knowledge bases from Zensical Markdown repos. The first hosting path is Cloudflare Pages, backed by source in GitHub. Private staff/customer docs are the ProDocStore product line, not the FreeDocStore default.
The two layers
Private docs hosting splits cleanly into two concerns: where the files live and who can read them. Cloudflare gives you both for free under realistic limits.
Cloudflare Pages
FreeGlobal hosting for the Zensical build output. Unlimited bandwidth, 500 builds per month, 20,000 files per site. Custom domains, automatic HTTPS, and atomic deploys via Git or CLI.
Cloudflare One (Access)
Free up to 50 usersZero-trust authentication in front of any Cloudflare-hosted site. Visitors hit a login page first, authenticate via SSO (Google, GitHub, OIDC, magic link), and only then see your content. No code changes - it's network-level enforcement.
Together: your docs deploy to a .pages.dev URL, and Cloudflare Access intercepts
every request to that URL until the visitor authenticates with an email your team allows. The
cost stays at $0 until you exceed 50 named users.
What you need before you start
- A Cloudflare account (free tier is fine; sign up at dash.cloudflare.com)
- Your KB in a GitHub repo with
docs/Markdown andzensical.toml - An email domain you control (e.g.
your-team.com) - this is what the Access policy will allow through
Step 1 - publish the Zensical KB (Cloudflare Pages)
From the Cloudflare dashboard, create a Pages project and connect it to your GitHub repo. Build configuration:
Build command: python3 -m pip install zensical && python3 -m zensical build --strict
Build output dir: site
Root directory: /
Push to main and Cloudflare deploys to your-project.pages.dev in under
a minute. At this point the site is publicly accessible. The Access layer comes next.
Or do it from the CLI
If you'd rather not click through the dashboard:
python3 -m zensical build --strict
npx wrangler pages project create your-project --production-branch main
npx wrangler pages deploy site --project-name=your-project
Step 2 - gate access (Cloudflare One)
From the Cloudflare dashboard, navigate to Zero Trust → Access → Applications and create a new self-hosted application:
- Application domain:
your-project.pages.dev(the URL Pages just gave you) - Session duration: 24 hours is a sane default
- Identity providers: at minimum, enable One-time PIN (email magic link). Optionally add Google, GitHub, or your corporate IdP.
Then add a policy to the application - this is the rule that decides who gets in:
- Action: Allow
- Include: Emails ending in
@your-team.com
Save. Visit the .pages.dev URL in a private window. You should hit a Cloudflare-hosted
login page, enter an email at @your-team.com, receive a one-time code, and only then see
your docs.
The most important check is the negative case. Try logging in with an email that does NOT match your allow rule - you should be denied. If anyone with any email gets through, the policy is misconfigured.
Step 3 - automate it (optional)
The FreeDocStore repo ships a reusable GitHub Actions workflow at
.github/workflows/deploy-pages.yml that does the whole pattern in one step: deploys to
Cloudflare Pages, ensures the Access app exists, syncs the policy, and rolls back if the post-deploy
check finds the site is publicly reachable.
To use it from your repo:
# .github/workflows/docs-deploy.yml
name: Docs Deploy
on: { push: { branches: [main] } }
jobs:
deploy:
uses: FreeDocStore/platform/.github/workflows/deploy-pages.yml@main
with:
project-name: your-project
email-domain: your-team.com
secrets: inherit
Required org secrets: CLOUDFLARE_API_TOKEN (scope: Pages Read/Write + Access Read/Write)
and CLOUDFLARE_ACCOUNT_ID. The workflow handles everything else.
What it costs
- Cloudflare Pages: $0 for the free tier - covers any reasonable docs site (unlimited bandwidth, 500 builds/month).
- Cloudflare One Access: $0 for up to 50 users. $7/user/month after that.
- Custom domain: the cost of the domain itself ($10-15/year for most TLDs). Cloudflare doesn't charge to point a domain at Pages.
For a typical engineering team well under 50 people, the running cost is the domain registration fee. That's it.
When this isn't the right fit
- More than 50 internal users - Access pricing kicks in. Still cheap relative to commercial alternatives, but no longer free.
- Already on a different cloud - if your team is deeply on AWS or Azure with SSO already wired into IAM, mirroring that into Cloudflare Access may not be worth the integration work. S3 + CloudFront + Cognito is an equivalent pattern (less convenient, sometimes preferred for compliance reasons).
- Public docs - skip Access entirely. Cloudflare Pages on a public repo is enough. No auth layer needed.
Common edge cases
Custom domain
After Pages is deployed, add a custom domain in the Pages project (e.g. docs.your-team.com).
Add a CNAME at your DNS provider pointing at the .pages.dev URL, wait for DNS to propagate,
then update the Access application's domain to match the custom domain. The policy continues to work
identically.
Multiple email domains
Add multiple Include → Emails ending in rules to the Access policy. Or add a second policy. Both approaches let in any email matching any rule.
Specific external collaborators
For one-off external access (a client, a contractor), add an explicit Include → Emails rule with their address. They sign in via magic link without needing an account on your domain.
Bypass for service-to-service traffic
If you have CI or scripts that need to fetch from the docs site, add a Bypass policy with a specific IP CIDR or service token. Bypass policies skip the auth flow.
Summary
Cloudflare Pages serves your docs. Cloudflare One Access gates them. Together, free up to 50 users. The FreeDocStore repo includes a workflow that wires the whole pattern up in CI - or you can do it by hand in 20 minutes from the dashboard.