Web Hosting Primer · Make-Me-An-Expert · 2026-05-11

Ad-Hoc Web Deploy Primer

Quickly deploying bespoke pages to the live web — what your options are, what they cost, how to keep them safe, and how to do it in 60 seconds once you're set up.

Author: Sai Audience: Lou (and any future-Lou) Companion to: Agentic Cloudflare Pipeline
Contents 1 · TL;DR — the one-paragraph version 2 · Platform comparison (who hosts your HTML) 3 · Costs — what you actually pay 4 · Deploy methods — the 5 levels of agency 5 · The supporting stack (storage, db, auth, domains) 6 · Security — public, soft-private, real-auth 7 · Workflow patterns (when to use what) 8 · What "expert" looks like (cheatsheet) 9 · Common footguns & fixes

1 · TL;DR — the one-paragraph version

If you only read this section

For ad-hoc bespoke web pages, Cloudflare Pages is the right default: unlimited bandwidth, free SSL, free CDN, free custom domains, free preview deploys, edge functions for dynamic stuff. The total monthly cost for personal-scale projects is $0 — your only spend is domain registration (~$9–30/yr per domain) plus an optional $5/mo Workers Paid plan if you blow past 100k Function invocations/day. Get good at: (a) npx wrangler pages deploy from CLI, (b) connecting a GitHub repo for declarative deploys, (c) functions/_middleware.js for password gates, (d) Cloudflare Access for real auth, (e) R2 for media. That's the whole game.

2 · Platform comparison

The "who hosts my HTML" decision. Below: the platforms that matter, ranked by fit for ad-hoc bespoke work.

Cloudflare Pages RECOMMENDED
Free forever for personal scale · paid tier $5/mo only if Functions exceed limit

Static hosting + edge Functions on Cloudflare's CDN. What you deployed tonight.

Strengths Unlimited bandwidth, unlimited requests, free SSL/HTTPS, 100 custom domains per project, instant cache invalidation, preview deploys per branch, no cold starts at edge, R2/D1/KV integration, generous Workers free tier (100k req/day).
Weaknesses 25MB max file size (heavy media needs R2), 20,000 files/deployment max, build minutes capped (500/mo on free), Functions cold-start ~5ms (fine for HTML, slow for heavy compute), DNS lives in same dashboard (good for auto-ops, bad if you fear vendor lock).
Vercel EXCELLENT FOR NEXT.JS
Hobby: free (100GB bandwidth/mo) · Pro: $20/user/mo

Made by the people who built Next.js. Optimized for React/Next workflows.

Strengths Best-in-class Next.js DX, automatic image optimization, preview deploys, analytics, Edge Functions, KV/Postgres/Blob services.
Weaknesses Bandwidth caps that can surprise you at scale (people get hit with $1000+ bills from viral posts), proprietary Next.js features tie you in, free tier "non-commercial use only" clause, more expensive at every tier than CF.
Netlify SOLID, MATURE
Starter: free (100GB/mo, 300 build min) · Pro: $19/mo

The original Jamstack platform. Battle-tested, great auth/forms/Identity built in.

Strengths Best built-in Forms (no backend needed), Netlify Identity (gitignore-style auth), Edge Functions, A/B split testing, robust CLI.
Weaknesses Bandwidth caps softer than CF, Functions cold-start slower than CF Workers, smaller free Worker tier, marketing positioning shifted to "Composable Web" (jargon).
GitHub Pages SIMPLE STATIC, NO FUNCTIONS
Free with any GitHub account · no real limits at personal scale

Pure static. Deploy by pushing to a branch. No backend, no auth, no preview deploys.

Strengths Already part of your Git workflow, zero new accounts needed, public sites + private repos work, Jekyll built-in for blogs.
Weaknesses No edge functions, no auth gate, custom domains require manual CNAME, public sites only on free (private repo + private site = $4/mo Pro), slow propagation.
Surge.sh OLD-SCHOOL, STILL GREAT
Free for unlimited deploys · $30/yr for custom domains

OG one-command static deploy. surge ./dist and you have a URL.

Strengths Truly one command, no auth setup, no project creation step, anonymous-friendly, custom subdomains free (foo.surge.sh).
Weaknesses No functions / backend, custom domains paid, no preview deploys, no SSL on apex domains without paid plan.
Bunny.net CHEAP CDN, NOT FOR HTML
Pay-as-you-go: ~$0.01/GB bandwidth · $0.01/GB storage

A CDN, not a hosting platform — useful as a media side-car for any platform above.

AWS S3 + CloudFront MAX FLEXIBILITY, MAX CONFIG
Pay-as-you-go: ~$0.023/GB storage, $0.085/GB egress (ouch)

The "I want full control and don't mind 30 pages of config" option.

Strengths Industry standard, fits any compliance regime, Lambda@Edge for everything, scales to enterprise infinity.
Weaknesses Egress fees can destroy you on media-heavy sites, IAM is a learning curve, no preview deploys without extra setup, no free SSL on apex without ACM dance.
My ranking for "ad-hoc personal stuff"

1. Cloudflare Pages · 2. Vercel · 3. Netlify · 4. GitHub Pages · 5. Surge.sh. AWS is overkill unless you're hitting enterprise scale or compliance requirements.

3 · Costs — what you actually pay

The "free forever" zone (Cloudflare Pages free tier)

ResourceFree tier limitWhat it means for you
BandwidthUnlimitedNo cap. Your Mother's Day site could serve 10,000 visitors a month and still be $0.
Requests/moUnlimitedSame — unmetered.
Builds500/monthYou'd need to deploy 16 times/day to hit this.
Files per deploy20,000Plenty for any sane static site.
File size25 MBTight for video; fine for HTML/images. Use R2 for big files.
Custom domains100 per projectYou can have foo.loudog.uno, bar.loudog.uno, ... all in one project.
Function invocations100,000/day~3M/month. Plenty for password-gated sites or light APIs.
Worker CPU time10ms per requestGenerous for HTML/JSON. Heavy compute needs paid.
R2 storage10 GB/mo freePlenty for personal photos / media archives.
R2 egressFree (always)The killer feature. Serve all the photos you want, no bandwidth bill ever.
D1 (SQLite)5 GB free, 5M reads/daySolid for any personal app DB.
KV (key-value)100k reads/day, 1k writes/dayFor session tokens, feature flags, etc.
Access (auth gate)50 users freeReal SSO/email-OTP for free. Per-user audit log included.

What you'd pay if you exceed free tier

Tier / itemCostWhen you'd hit it
Workers Paid plan$5/mo>100k Function calls/day OR >10ms CPU. Personal site never hits this.
Beyond Workers Paid$0.30 per 1M reqOnly after 10M req/mo on paid plan.
R2 storage beyond 10GB$0.015/GB/mo1TB = $15/mo.
R2 Class A (writes)$4.50 per millionYou'd need to upload millions of files.
R2 Class B (reads)$0.36 per millionPricing here means R2 wins for any media site.
Cloudflare Access >50 users$3/user/mo (Zero Trust Standard)Family sites stay free here.
Domain registrationat-cost, no markup.com ≈ $10/yr · .uno ≈ $30/yr · .dev ≈ $13/yr
Where bills surprise people

The classic horror story is egress fees on S3 or Vercel bandwidth caps. A viral blog post can cost $200 on AWS overnight. Cloudflare's R2 + Pages combo eliminates this risk entirely — bandwidth is unmetered. If you stay on CF, the only way to get an unexpected bill is to invoke Workers very heavily on the paid plan.

Real-world cost projection — Lou's hub vision

If loudog.uno/share/{person}/{project} hosts 10 personal projects with ~500 visitors/mo each and 10GB of total media:

ItemMonthly cost
Cloudflare Pages hosting$0
R2 storage (10GB)$0 (under free tier)
R2 egress$0 (always free)
Functions for routing/auth$0 (well under 100k/day)
Cloudflare Access for 5 family members$0 (under 50)
Domain (loudog.uno) — annualized~$2.50/mo
Total~$30/year

4 · Deploy methods — the 5 levels of agency

1Drag-and-drop

Netlify Drop (drop a folder onto netlify.app/drop), Surge (surge ./dist). Zero config. Best for one-off "send Mom a thing" deploys. No version history, no API access. 30 seconds to live URL.

2CLI imperative

wrangler pages deploy, vercel deploy, netlify deploy. Scriptable. State lives on your machine. Great for "I'm building a site right now and want to iterate fast." This is what you did tonight. 5–60 seconds per deploy after one-time auth.

3Git-connected (declarative)

Connect a GitHub repo to Pages/Vercel/Netlify. Every push auto-deploys. Each branch gets a preview URL. PR comments show preview links. This is the gold standard for any project you'll touch more than once. Add it once, never run a deploy command again. 20–60 seconds per push (build time).

4Infrastructure-as-Code (Terraform / Pulumi)

Define your CF setup (DNS, Pages projects, R2 buckets, Workers, Access policies) in version-controlled config. terraform apply reconciles state. Overkill for personal stuff; essential for teams. Setup: hours. Operation: instant + auditable.

5Fully agentic (AI agent → live URL)

You say "spin up X" → agent generates site → deploys → returns URL. Requires: broad CF API token in env, optionally the Cloudflare MCP server. Tonight we did Level 2 with a Level 5 wrapper. One sentence → minutes to live.

Recommended progression for you

For throwaway / one-off: stay at Level 2 (CLI). For anything you'll touch twice: move to Level 3 (GitHub-connected). For infra you really care about (your main loudog.uno setup): Level 4 (Terraform). Level 5 wraps all of these — it doesn't replace them.

5 · The supporting stack

HTML hosting is one piece. Real sites need more. Here's the full Cloudflare stack — you can mix-and-match per project.

RoleCloudflare optionWhen to use
Static HTML / SPAPagesAlways your starting point
Server-side logicPages Functions (inside Pages) or Workers (standalone)Auth, API endpoints, dynamic rendering
Large file storageR2Photos >100KB, video, archives. Use signed URLs for private files.
Structured dataD1 (SQLite)User accounts, blog posts, anything relational
Key-value cacheKVSession cookies, feature flags, rate limit counters
Real-time stateDurable ObjectsWebSockets, presence, collaborative editing
Queue jobsQueuesBackground tasks, retries, fan-out
AI inferenceWorkers AILlama, embeddings, image gen at the edge
Auth gateAccess (Zero Trust)Real user auth via email-OTP, GitHub, Google SSO
DNS / RegistrarCloudflare RegistrarCheapest at-cost domains, integrates with everything above
ObservabilityAnalytics (built into Pages)Free, privacy-preserving, no cookies

An "expert" site recipe for the loudog.uno hub:

// Mom hub at loudog.uno/share/mom/
Cloudflare Registrar → loudog.uno              # $30/yr
Cloudflare Pages    → loudog-uno project       # static HTML + JSON index
Pages Functions     → routing, signed URLs     # dynamic mom/* routes
Cloudflare R2       → media bucket             # photos, videos, audio
Cloudflare Access   → email-OTP gate           # mom + 5 family emails
D1                  → site_metadata.db         # content index, when added

6 · Security

The three privacy levels for the URL you ship

Level A · Public

No auth. Anyone with the URL sees everything. Get indexed by Google. Good for: marketing, public docs, open portfolio. What this primer doc is on.

Level B · Soft-private (cookie/password gate)

One shared password. Anyone who has it gets in. Cookie persists. Easy to share but also easy to leak. Add robots.txt Disallow + <meta noindex> so search engines don't crawl it. Good for: family albums, draft work, internal-team-only. What the Mother's Day site uses.

Level C · Real auth (Cloudflare Access)

Per-user identity. Email-OTP, GitHub, Google login. Audit log shows who saw what. Revoke per user. Good for: anything with PII, internal tools, paid content. Free for <50 users. The right answer for the loudog.uno/share hub.

Token hygiene (what you're setting up right now)

The "robots.txt is not security" reality check

Some agents and crawlers ignore robots.txt. Internet Archive (Wayback) historically respected it; some AI scrapers don't. If the content can't ever be seen by strangers, use real auth. robots.txt + URL obscurity is "soft" privacy at best.

Headers and CORS

Cloudflare Pages defaults are pretty open. If your project has data endpoints or scripts that you don't want loaded from other domains, add a _headers file at the root of your deploy:

# _headers
/*
  X-Frame-Options: DENY
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Content-Security-Policy: default-src 'self'

/api/*
  Access-Control-Allow-Origin: https://loudog.uno

7 · Workflow patterns

Pattern P1 · Throwaway one-off ("here, look at this")

Best for: ephemeral demos, prototypes, "remember when I showed you that thing?"

Pattern P2 · Iterative dev with previews

Best for: any site you'll touch more than once over weeks.

Pattern P3 · Personal hub (your loudog.uno vision)

Best for: a long-lived "infrastructure for sharing" that grows over years.

Pattern P4 · Media-heavy site (photo essays, videos)

Best for: the Mom site once you add the long videos, any portfolio with hi-res images.

Pattern P5 · Agentic burst-deploy (where we're heading)

Best for: bespoke gifts, ad-hoc dashboards, micro-projects, party-trick demos.

8 · What "expert" looks like (cheatsheet)

The mental model of someone who can deploy any bespoke page in under 60 seconds:

Environment

# In ~/.zshrc:
export CLOUDFLARE_API_TOKEN="..."      # broad token, see Agentic Pipeline doc §5A
export CF_ACCOUNT_ID="..."           # your account id
alias cfdeploy="npx wrangler pages deploy . --project-name=$(basename $(pwd))"

The starter template (keep this around)

# ~/templates/static-site/
.
├── index.html        # your page
├── _headers          # security headers
├── robots.txt        # Disallow: / if private
├── functions/
│   └── _middleware.js   # password gate, if needed
└── README.md         # notes for future-you

The five commands you actually need

## 1. New deploy
npx wrangler pages project create $NAME --production-branch=main
npx wrangler pages deploy . --project-name=$NAME --commit-dirty=true

## 2. Custom domain (once CF token has Zone:DNS:Edit)
curl -X POST -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/pages/projects/$NAME/domains \
  -d '{"name":"sub.loudog.uno"}'
curl -X POST -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records \
  -d '{"type":"CNAME","name":"sub","content":"$NAME.pages.dev","proxied":true}'

## 3. Tail logs (debugging Functions)
npx wrangler pages deployment tail --project-name=$NAME

## 4. Delete project (clean up throwaways)
npx wrangler pages project delete $NAME

## 5. List everything
npx wrangler pages project list

Decision tree

Need a public page now?
  → YES: Pages, no functions, deploy

Need auth?
  → 1 password OK: add functions/_middleware.js cookie gate
  → real user identity: switch to Cloudflare Access (free < 50 users)

Need dynamic logic (API, form, db read)?
  → Light: Pages Functions
  → Heavy: standalone Worker

Need to store files > 1MB?
  → Public: R2 public bucket + Cache-Control
  → Private: R2 + signed URLs via Worker

Need a custom domain?
  → On Cloudflare: register via Registrar, auto-bind via Pages domains API
  → Elsewhere: add CNAME at your DNS host pointing to project.pages.dev

Going to maintain this for > 1 month?
  → Git-connect the project, never run wrangler again

9 · Common footguns & fixes

FootgunSymptomFix
wrangler pages deploy scans CWD for functions/ Deploying project A inherits middleware from project B that you were working in earlier Always deploy from a clean dir, or use --cwd /path/to/clean
Project must exist before first deploy "Project not found" on first deploy Run wrangler pages project create <name> first
OAuth token has zone:read only Can register custom domain on Pages, but DNS CNAME fails Create API token with Zone DNS · Edit (see Agentic Pipeline doc §5A)
CF Pages caches aggressively You re-deploy but old version still shows Hard refresh (Cmd+Shift+R) or use the https://<hash>.<project>.pages.dev preview URL
Function unset-token requirement "Authentication error" when deploying to Pages with CLOUDFLARE_API_TOKEN set Either: (a) (unset CLOUDFLARE_API_TOKEN; wrangler ...), or (b) make sure your token has Cloudflare Pages · Edit
HEIC images don't render in browsers Photos show as broken icons Filter to .jpeg derivatives only, or convert HEIC → JPEG at copy time
iCloud "Optimize Mac Storage" Originals not on disk, only thumbnails Use resources/derivatives/masters/ for ~1024px web-ready JPEGs
Pages Function template literals + apostrophes Build error: "Expected ':' but found 't'" Use backticks throughout, or rephrase ("was not" instead of "wasn't")
25 MB per-file limit Single big asset (PDF, video) fails to upload Move to R2 — embed via https://r2-bucket.r2.dev/... URL
Pages preview URLs aren't cached Slow first load on dev iteration Expected. Use the <project>.pages.dev (production alias) for testing if you need cache.

What I'd do in your shoes

  1. Finish the CF API token setup (the screen you're on right now). That unblocks fully agentic operation.
  2. Pick a default workflow: for ad-hoc personal stuff = CLI imperative (Level 2). For loudog.uno hub = Git-connected (Level 3) + Terraform later (Level 4).
  3. Make a starter template at ~/templates/static-site/ with the files listed in §8. Future deploys start as cp -r ~/templates/static-site/ ./my-thing.
  4. Install the Cloudflare MCP server — see Agentic Pipeline doc §5B. After this, "deploy a private page about X" is one sentence to me.
  5. For the hub vision: Pages (HTML) + R2 (media) + Access (auth) + D1 (metadata) + Worker (routing). All under one domain, all free at personal scale.

Document built 2026-05-11 · for Lou DeSantis · by Sai (claude-opus-4-7).
Companion to Agentic Cloudflare Pipeline.
Pricing/limits are current as of 2026-01 and may change — verify on each vendor's pricing page before committing infrastructure decisions.