Skip to main content

Operations, Troubleshooting & Reference

Learning Focus

By the end of this module you will have a complete operational toolkit for running Cloudflare Pages in production — including incident response, rollback, cache management, and a comprehensive CLI/API quick-reference.

Production Operational Runbook

Checking Site Status

Quick health check
# 1. Check the live site responds
curl -I https://docs.yourdomain.com
# Expected: HTTP/2 200, server: cloudflare

# 2. Check certificate validity
curl -I https://docs.yourdomain.com 2>&1 | grep -i "SSL\|TLS\|certificate"

# 3. Check which deployment is active
curl "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PROJECT}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
| jq '.result.latest_deployment | {url, created_on, environment}'

# 4. Check the deployment status
curl "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PROJECT}/deployments?per_page=5" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
| jq '.result[] | {id, url, environment, created_on, latest_stage}'

Rollback Procedure

Emergency rollback
# Step 1: List recent deployments
curl -s "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PROJECT}/deployments" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
| jq '.result[] | "\(.id) | \(.created_on) | \(.latest_stage.status)"' -r

# Step 2: Pick the last known-good deployment ID, then rollback:
GOOD_DEPLOY_ID="previous-good-deployment-id"

curl -X POST \
"https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PROJECT}/deployments/${GOOD_DEPLOY_ID}/rollback" \
-H "Authorization: Bearer ${CF_API_TOKEN}" | jq .

# ✅ The old deployment is now live — no rebuild required (~5-10 seconds)

Dashboard Rollback:

  1. Workers & Pages → your-project → Deployments
  2. Find the deployment to restore
  3. Click the menu → Rollback to this deployment
  4. Confirm

Cache Purge

Purge Cloudflare cache after deployment issues
# Get your Zone ID from Cloudflare dashboard (for the custom domain's zone)
ZONE_ID="your-zone-id"

# Purge everything (use during incidents)
curl -X POST \
"https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"purge_everything": true}'

# Purge specific URLs (less disruptive)
curl -X POST \
"https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"files": [
"https://docs.yourdomain.com/",
"https://docs.yourdomain.com/docs/intro",
"https://docs.yourdomain.com/docs/intro/"
]
}'

Troubleshooting Matrix

Build Failures

ErrorCauseFix
Cannot find module 'X'Missing dependencynpm install X && git add package*.json && git push
command not found: docusaurus@docusaurus/core not installedEnsure package.json has Docusaurus as dependency
Build timeout (20 minutes)Site too large / memory leakSet NODE_OPTIONS=--max-old-space-size=4096
ENOSPC: no space left on deviceToo many files in outputAudit static/ for accidental large files
Error: baseUrl mismatchWrong baseUrl in configSet baseUrl: '/' in docusaurus.config.js
yarn.lock out of dateLock file conflictRun yarn install locally and commit updated lock
Node version mismatchWrong Node for DocusaurusSet NODE_VERSION=20 env var

Deployment Issues

SymptomCauseFix
Build succeeds but site 404sWrong output directoryVerify it's build (not dist, public, out)
CSS/JS assets 404Wrong baseUrlSet baseUrl: '/'
Old content showingCDN cachePurge cache (see above)
Custom domain stuck at "initializing"DNS not propagatedWait 5-10min, or check with dig
HTTPS shows warningSSL race conditionWait up to 15 min for cert issuance
Functions not runningfunctions/ in wrong locationMust be at repo root, not inside Docusaurus dir

DNS Issues

DNS debugging commands
# Check CNAME record
dig docs.yourdomain.com CNAME

# Expected:
# docs.yourdomain.com. 300 IN CNAME my-docs.pages.dev.

# Check propagation globally
# https://dnschecker.org/#CNAME/docs.yourdomain.com

# Check SSL certificate
echo | openssl s_client -connect docs.yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates

Pages Functions Debugging

Debug functions locally and in production
# Local debugging
wrangler pages dev build --log-level debug

# Production logs (real-time)
wrangler pages deployment tail \
--project-name my-docs \
--format pretty \
--status error # Show only errors

# Get logs from a specific deployment
DEPLOYMENT_ID="your-deployment-id"
curl "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PROJECT}/deployments/${DEPLOYMENT_ID}/history/logs" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
| jq '.result.logs[] | "\(.ts) \(.line)"' -r

Performance Optimization

Docusaurus Build Optimization for Pages

docusaurus.config.js — Pages optimizations
const config = {
// Enable trailing slash for better CDN cache hit rates
trailingSlash: true,

// Minify HTML in production
customFields: {
minifyHtml: true,
},

// Image optimization
themeConfig: {
image: 'img/social-card.jpg', // OG image for social sharing
},
};

Cache Control Headers

static/_headers — aggressive caching for immutable assets
# Hashed assets (Docusaurus adds hashes to JS/CSS filenames)
/assets/*
Cache-Control: public, max-age=31536000, immutable

# HTML pages — always revalidate
/*.html
Cache-Control: public, max-age=0, must-revalidate

# Root and clean URLs
/
Cache-Control: public, max-age=0, must-revalidate

Limits & Quotas Reference

Cloudflare Pages Limits

ResourceFreeProBusiness
ProjectsUnlimitedUnlimitedUnlimited
Builds/month5005,0005,000
Concurrent builds155
Build timeout20 min20 min20 min
Custom domains/projectUnlimitedUnlimitedUnlimited
BandwidthUnlimitedUnlimitedUnlimited
Max file size25 MB25 MB25 MB
Files per deployment20,00020,00020,000
Preview deploymentsUnlimitedUnlimitedUnlimited

Pages Functions Limits

ResourceFreePaid (Workers Paid)
Requests/day100,00010M included
CPU time/invocation10ms30s
Memory128 MB128 MB
Subrequests501,000
Script size1 MB10 MB

API Rate Limits

ActionLimit
API requests1,200/min
Deployments/day1,000
Domains per project100

CLI Quick Reference

Wrangler Pages — complete command cheatsheet
# ── Authentication ─────────────────────────────────────────
wrangler login # OAuth browser login
wrangler logout # Remove credentials
wrangler whoami # Show current user and accounts

# ── Project Management ──────────────────────────────────────
wrangler pages project list # List all projects
wrangler pages project create <name> # Create new project
wrangler pages project delete <name> # Delete project

# ── Deployments ─────────────────────────────────────────────
wrangler pages deploy <dir> # Deploy directory
--project-name <name> # Target project (required)
--branch <branch> # Branch for this deploy
--commit-message <msg> # Label in dashboard
--commit-dirty=true # Skip dirty repo check

wrangler pages deployment list # List deployments
--project-name <name> # For specific project

wrangler pages deployment view <id> # View deployment details
--project-name <name>

# ── Local Dev ───────────────────────────────────────────────
wrangler pages dev <dir|url> # Start local dev server
--port <port> # Default: 8788
--live-reload # Enable live reload
--log-level debug # Verbose output

# ── Secrets & Env ───────────────────────────────────────────
wrangler pages secret put <name> # Set a secret
--project-name <name>
--env production|preview

wrangler pages secret list # List secrets
--project-name <name>
--env production|preview

wrangler pages secret delete <name> # Delete a secret
--project-name <name>
--env production|preview

# ── Logs ────────────────────────────────────────────────────
wrangler pages deployment tail # Stream live logs
--project-name <name>
--format pretty|json
--status ok|error|canceled
--env production|preview

API Quick Reference

Cloudflare Pages REST API — complete endpoint map
BASE="https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects"
AUTH="-H 'Authorization: Bearer ${CF_API_TOKEN}'"

# ── Projects ────────────────────────────────────────────────
GET ${BASE} # List all projects
GET ${BASE}/${PROJECT} # Get project details
POST ${BASE} # Create project
PATCH ${BASE}/${PROJECT} # Update project settings
DELETE ${BASE}/${PROJECT} # Delete project

# ── Deployments ─────────────────────────────────────────────
GET ${BASE}/${PROJECT}/deployments # List deployments
GET ${BASE}/${PROJECT}/deployments/${ID} # Get deployment
POST ${BASE}/${PROJECT}/deployments # Trigger deployment
POST ${BASE}/${PROJECT}/deployments/${ID}/retry # Retry failed deployment
POST ${BASE}/${PROJECT}/deployments/${ID}/rollback # Rollback to deployment
DELETE ${BASE}/${PROJECT}/deployments/${ID} # Delete deployment
GET ${BASE}/${PROJECT}/deployments/${ID}/history/logs # Build logs

# ── Domains ─────────────────────────────────────────────────
GET ${BASE}/${PROJECT}/domains # List custom domains
POST ${BASE}/${PROJECT}/domains # Add custom domain
GET ${BASE}/${PROJECT}/domains/${DOMAIN} # Get domain status
DELETE ${BASE}/${PROJECT}/domains/${DOMAIN} # Remove custom domain

# ── Deploy Hooks ────────────────────────────────────────────
GET ${BASE}/${PROJECT}/deploy_hooks # List webhooks
POST ${BASE}/${PROJECT}/deploy_hooks # Create webhook
DELETE ${BASE}/${PROJECT}/deploy_hooks/${ID} # Delete webhook

Security Best Practices

  1. Use scoped API tokens — never use your Global API Key for automation.
  2. Rotate API tokens — create new tokens periodically (token management in CF dashboard).
  3. Protect preview deployments — use Cloudflare Access for team-only previews.
  4. Use encrypted secrets — mark sensitive values as encrypted in Pages settings.
  5. Enable branch protection — protect your main branch in GitHub to require PR reviews.
  6. Monitor deployments — check the deployments dashboard or set up Cloudflare email alerts.
  7. Audit deploy hooks — remove unused webhooks to prevent unauthorized builds.

Key Takeaways

  • Rollback is instant via API or dashboard — no rebuild required.
  • Cache purge via API solves most "old content" incidents.
  • Build failures are almost always caused by missing dependencies, wrong output directory, or memory limits.
  • DNS issues are diagnosed with dig — most resolve within 10 minutes.
  • Functions logs are streamed with wrangler pages deployment tail.
  • Free tier: 500 builds/month, 100k function requests/day, unlimited bandwidth.

What You've Learned

Congratulations — you've completed the Cloudflare Pages curriculum. You can now:

✅ Understand the JAMstack architecture and why it supersedes self-hosted servers
✅ Migrate a Docusaurus site from Docker/VPS to GitHub + Cloudflare Pages
✅ Use the Wrangler CLI for deployments, secrets, logs, and local development
✅ Call the Cloudflare Pages REST API for automation and scripting
✅ Configure build settings, environment variables, and framework presets
✅ Leverage preview deployments for staging and team review workflows
✅ Configure custom domains and automatic SSL
✅ Write Pages Functions (edge functions) for server-side logic
✅ Build GitHub Actions CI/CD pipelines with test gates
✅ Operate Pages in production — rollbacks, cache management, and troubleshooting


External Resources