cloudflare-best-practices
Best practices for deploying and debugging Cloudflare Workers and Pages
Cloudflare Deployment & Debugging Guide
This guide captures critical learnings from debugging complex routing, DNS, and deployment issues in the Legends of Hastinapur infrastructure.
1. Routing & Domains
Custom Domains vs. Routes
- Preferred: Use
custom_domain = trueinwrangler.tomlfor dedicated subdomains.routes = [ { pattern = "api.example.com", custom_domain = true } ]- Why: Cloudflare automatically creates the DNS record and TLS certificate.
- Result: No manual DNS configuration needed.
- Legacy/Specific: If using
routes(e.g., sharing a domain between workers), you MUST ensure a DNS record exists.routes = [ { pattern = "example.com/api/*", zone_name = "example.com" } ]- Target: The DNS record (A/AAAA/CNAME) for
example.commust exist and be Proxied (Orange Cloud). - Pitfall: If you delete the Worker that "owned" the CNAME, the DNS record might disappear. If you then try to route traffic to that subdomain using another worker's
routesconfig, it will fail withError 530 / 1016(Origin DNS Error) orName Not Resolvedbecause there is no DNS entry to attach the route to. - Fix: Manually add a "dummy" A record (e.g., pointing to
192.0.2.1) with Proxy enabled to revive the route.
- Target: The DNS record (A/AAAA/CNAME) for
Routing Conflicts
- Rule: More specific routes take precedence, but wildcards are dangerous.
- Issue: A worker with
routes = [{ pattern = "api.example.com/*" }]will swallow ALL traffic to that subdomain, even if meant for another worker. - Fix: Be extremely specific (e.g.,
api.example.com/auth/*) or use dedicated subdomains.
2. Environment Variables & Secrets
Next.js / Frontend
- Build-Time Injection:
NEXT_PUBLIC_variables are inlined into the JavaScript bundle at build time. - Pitfall: Changing
.envand runningwrangler pages deploy(without rebuilding) will deploy the OLD code with the OLD variables. - Fix: Always run the full build command (
npm run buildornext build) after changing environment variables.
Workers
- Secrets: Secrets (API Keys, private keys) are NOT stored in
wrangler.toml. - Pitfall: Deploying to a new environment (e.g.,
production) often fails because secrets weren't set for that specific environment. - Fix: Use
npx wrangler secret put NAME --env productionto set them explicitly.
3. Debugging Checklist
- 404 Not Found:
- Check
wrangler.tomlroutes. - Check if another worker is intercepting the path.
- Check if the path has a trailing slash (add normalization logic).
- Check
- 530 / 1016 Origin DNS Error:
- The Worker Route exists, but the underlying DNS record is missing.
- Fix: Create a Proxied A Record for the host.
- 401 Unauthorized (on Health Checks):
- Check if a "catch-all" worker (like a KB bot) is intercepting the request and demanding a token.
- General:
- Use
dig @1.1.1.1 domain.comto verify global propagation. - Use
curl -vto check headers and resolution status.
- Use
4. Current System Architecture (As of Jan 2026)
We have migrated to a Dedicated Subdomain Architecture to eliminate routing conflicts.
Production Endpoints
Frontends & Consumers
5. Maintenance Manual
How to Deploy
Always deploy from the specific worker directory.
1. Account API
cd loh-cf-workers/account-api
npm run deploy
# If changing secrets:
npx wrangler secret put GOOGLE_CLIENT_ID2. Website
cd loh-website
# MUST rebuild to update env vars
npm run deploy # (Runs build + wrangler pages deploy)3. Ops Tools
cd loh-ops-tools
npx wrangler pages deploy .Common Gotchas Resolved
- "Invalid Service Token": This usually comes from
kb-api. If you see this on other subdomains, it meanskb-apihas a wildcard route (*) and is "shadowing" the other workers. Fix: Delete the rogue worker or restrict its route. - "Name Not Resolved": You added
custom_domain = truebut the DNS A-record doesn't exist. Fix: Add a dummy A-record (192.0.2.1) proxied in Cloudflare. - Pending Updates: Pages updates are atomic, but Worker code updates propagate instantly. Worker Theory updates (Routes/DNS) takes ~1-2 mins to propagate globally.