Skip to content
BRAND

Hosting Plan

Where each public surface lives. Cloudflare Pages for static; Cloudflare Access for private docs; the preview-deployment-access gotcha that bites everyone once.

The hosting plan is small on purpose. Three Cloudflare Pages projects cover the entire 5-year brand surface: the public portfolio + blog at abukix.dev, the private ROOT docs at root.abukix.dev, and the Year-5 Studio demo at studio.abukix.dev. Everything else (DNS, email routing, private-doc auth) is Cloudflare-native and free at the scale a solo operator needs. The whole architecture is designed so that the daily workflow is git push and nothing else.

The one trap worth surfacing immediately is the preview-deployment-access default. Cloudflare Pages serves preview URLs publicly even when a zone-level Access policy is configured — the policy doesn’t enforce on <commit>.<project>.pages.dev until you flip a setting that’s off by default. Anyone who’s been bitten by this remembers it; everyone else needs the warning before they connect their first private repo.


Architecture

abukix.dev → Custom HTML portfolio + blog (public)
Repo: github.com/abukix/portfolio (public)
Build: bash build.sh; output: _site/
abukix.dev/blog → MkDocs Material blog (public)
Repo: github.com/abukix/portfolio (public)
Source: posts/
studio.abukix.dev → Abukix Studio public surface (Y5 P29 launch)
Repo: github.com/abukix/studio-frontend (public)
Stack: Next.js + Tailwind on Cloudflare Pages
root.abukix.dev → ROOT private docs (private; behind Cloudflare Access)
Repo: github.com/abukix/root (private — this repo)
Build root: /
Stack: TBD (Astro + Tailwind candidate)

The studio.abukix.dev surface is the public face of the Studio Plan and the demo home for the composition recipes. It’s the only one of the four with a moving backend (Cloud Run / Fargate); the others are static.


Stack per surface

ComponentToolWhy
Domain + DNSCloudflareAlready planned for email routing
Static hostingCloudflare PagesFree, fast, deploys from GitHub on every push
Private docs authCloudflare Access (Zero Trust)Free for <50 users, email OTP login
PortfolioCustom HTML / vanilla CSS+JSTerminal-style brand, no framework
BlogMkDocs MaterialRenders posts/ markdown, RSS feed
ROOT privateAstro + Tailwind (planned)More flexibility than MkDocs
Studio frontendNext.js + Tailwind on PagesProduction-shape demo surface

Cloudflare Pages auto-sync behavior

Once a project is connected to a GitHub repo:

EventWhat Cloudflare does
Push to main (production branch)Builds + deploys to live URL automatically (~30-90s)
Push to other branchesCreates preview deployment at <commit-hash>.<project>.pages.dev
Build script failsSkips deploy, previous version stays live
Manual rebuild neededClick “Retry deployment” in dashboard

Daily workflow: git push. No manual deploy steps.


CRITICAL: Preview deployment access (the gotcha)

When you create a Cloudflare Pages project AND apply a Cloudflare Access policy at the zone level (e.g., root.abukix.dev), the Access app DOES NOT enforce on preview deployments by default.

The default for “Preview deployment access” is Public. Pages serves all your <commit-hash>.<project>.pages.dev URLs publicly even though the zone-level Access app exists. Without changing this setting, your private content is publicly accessible at the preview URL.

Fix it:

Cloudflare Dashboard → Pages → <project> → Settings → Deployments → Deployment access
Change "Preview deployment access" from "Public" to:
⊙ "Private — require Access policy"
Save.

Without this, the zone-level Access app does NOT enforce on preview deployments — Pages bypasses it, serving traffic publicly even though the Access app exists. This single setting is the most common reason “my Access policy isn’t working” — no error, just public.

Verify after setting: visit a preview URL in incognito → should see Access login screen.


Cloudflare Pages setup: per project

Project 1: Portfolio + Blog (abukix.dev)

Cloudflare Pages project: abukix-portfolio
GitHub repo: abukix/portfolio
Build settings:
Build command: bash build.sh
Output directory: _site
Root directory: /
Custom domain: abukix.dev (apex) + www.abukix.dev (redirect to apex)
Access policy: none (public)
Preview deployment: (default Public is fine — public anyway)

Project 2: ROOT private docs (root.abukix.dev)

Cloudflare Pages project: abukix-root
GitHub repo: abukix/root (this repo)
Build settings:
Build command: (depends on chosen stack — Astro: npm run build; MkDocs: bash build.sh)
Output directory: (Astro: dist; MkDocs: site)
Root directory: /
Custom domain: root.abukix.dev
Access policy: Cloudflare Zero Trust → Access → Application → root.abukix.dev
Identity: One-time PIN (email OTP)
Allow: me@abukix.dev (add backups if desired)
★★★ Preview deployment access: PRIVATE — require Access policy ★★★

Project 3: Abukix Studio (studio.abukix.dev: Y5 P29)

Cloudflare Pages project: abukix-studio
GitHub repo: abukix/studio-frontend (public)
Build settings:
Build command: npm run build
Output directory: .next (or out for static export)
Root directory: /
Custom domain: studio.abukix.dev
Access policy: none (public, but rate-limited)
Backend: Cloud Run / Fargate (separate; not Pages)

Setup checklist (when each project goes live)

Pre-Phase-1 — Domain:
[ ] Buy abukix.dev on Cloudflare Registrar (or transfer)
[ ] Confirm Cloudflare DNS is the active nameserver
[ ] Set up email routing (Google Workspace MX records)
Pre-Phase-1 — ROOT private docs (root.abukix.dev):
[ ] Confirm abukix/root pushed to GitHub (private)
[ ] Cloudflare Pages → Create project → Connect to GitHub
[ ] Select repo: abukix/root
[ ] Build command + output directory (per chosen stack)
[ ] Save → first build runs (verify on *.pages.dev URL)
[ ] Custom domain: root.abukix.dev
[ ] Cloudflare Zero Trust → Access → Applications → New
[ ] Self-hosted, Domain: root.abukix.dev
[ ] Identity provider: One-Time PIN
[ ] Policy: Allow me@abukix.dev
[ ] ★★★ Pages → Settings → Deployment access → "Private — require Access policy" ★★★
[ ] Test: visit root.abukix.dev → login screen → OTP → docs render
[ ] Test: visit a preview URL (find in Pages dashboard) → login required
Y2 P9 — Portfolio + Blog (abukix.dev):
[ ] Confirm abukix/portfolio pushed to GitHub (public)
[ ] Cloudflare Pages → Create project → Connect to GitHub
[ ] Build command: bash build.sh
[ ] Output directory: _site
[ ] Root directory: /
[ ] Save → first build
[ ] Custom domain: abukix.dev (apex) + www redirect
[ ] Test: visit abukix.dev → portfolio
[ ] Test: visit abukix.dev/blog → blog index
[ ] Test: visit abukix.dev/blog/01-terralabs-launch → first post renders
Y5 P29 — Abukix Studio (studio.abukix.dev):
[ ] Confirm abukix/studio-frontend pushed (public)
[ ] Cloudflare Pages → new project
[ ] Build: npm run build
[ ] Custom domain: studio.abukix.dev
[ ] Cloud Run / Fargate backend deployed separately
[ ] Rate limit: per-IP via Cloudflare Workers
[ ] Cost cap: budget alert at $50/month
[ ] Demo data seeded (sanitized)

Cost

Cloudflare Pages: Free (unlimited sites, 500 builds/month per project)
Cloudflare Access: Free (up to 50 users)
abukix.dev domain: ~$10-12/year
Google Workspace: ~$72/year (Business Starter, 1 user)
Studio backend (Y5): ~$30-50/month, capped (Cloud Run + scheduled cleanup)
Total before Y5: ~$80-85/year
Total during Y5 demo: ~$80 + $360-600 = ~$440-680

When to actually deploy

Per the brand strategy, the portfolio repo lives publicly on GitHub from day 1 but the Cloudflare Pages connection is deferred until:

  • 5+ blog posts in posts/
  • At least one shipped Year 1 project (ops-handbook with real runbooks)
  • ROOT Phase 1-3 complete or in progress

Avoids launching abukix.dev as a brochure for work that hasn’t started.

The private root.abukix.dev can be deployed earlier (it’s behind Access, no public-visibility risk) — useful for accessing your own docs from any device once homelab is rich enough to need them.


Cross-references