IRONCREED

I standWhen everythingLies down.

IRONCREED / SYSTEM ENTRY

Welcome to IRONCREED

IRONCREED is the IT practice of Zhovten Games: web development, infrastructure, automation, security, research, and technical publishing within one traceable engineering process.

IRONCREED · CLOUDFLARE OPERATIONS · CASE 001Material seriesThe Great and Terrible Cloudflare1/1

Case 001. Cloudflare Crawler Surface Policy: Controlling Bot Access to URLs

A 22-site case: crawler identity and URL surface, profiles, explicit writes, drift, and a portable PHP tool.

Engineering case; portable code and verification boundaries1.1 · 8 September 2026Age rating: 0+
IRONCREED / CLOUDFLARE-001-CRAWLER-SURFACE-POLICY

Site edition

Case 001. Cloudflare Crawler Surface Policy: Controlling Bot Access to URLs

The Great and Terrible Cloudflare series. Cloudflare Operations — policy, security and fleet management.

How can a store close transactional URLs to crawlers, retain access to public content, and verify the result across a fleet of sites? This case describes a solution that developed from a particular production incident and client infrastructure.

According to the author’s account, the fleet covered 22 sites with a combined daily audience of approximately 400,000 unique users. These figures provide author-supplied context; the aggregate metrics and pilot results below have not undergone an independent audit. Client domains, credentials, and private snapshots are excluded from publication.

The management tools initially ran on the client’s shared hosting and were written in PHP: the environment already existed alongside the sites, and the operator needed no separate server. A new independent installation can use a local environment such as WSL. The architectural principle remains consistent: configuration and policy have a reviewable state, secrets and private overlays stay local, and Cloudflare changes pass through a separate controlled write path.

Standalone code and examples: IRONCREED/cloudflare, under Case 001. Every instruction below uses that repository’s structure.

A useful bot on a transactional surface

On a WooCommerce site, crawler traffic repeatedly requested routes and parameters serving the cart, checkout, and customer account:

/cart/
/checkout/
/my-account/
?add-to-cart=
?remove_item=
?wc-ajax=

These requests can invoke PHP, WooCommerce, sessions, and cart operations. Meta-WebIndexer was one conspicuous participant. Globally blocking that User-Agent would also remove its access to product pages and articles that may have search and linking value.

comparisonFrom incident to policy

Observed load opens two options: a global identity block or a restriction on a particular surface; this case selects the latter.

  • source: Crawler on transactional URLs
  • boundary: Global identity block
  • state: Surface restriction
  • state: Public content outside the rule
  • incident references global
  • incident derives surface
  • surface produces content
Observed load opens two options: a global identity block or a restriction on a particular surface; this case selects the latter.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g01 · authorial model

The decision unit becomes crawler identity × request surface × profile × zone configuration.

flowDecision components

Identity, URL class, profile, and local conditions converge in the zone’s effective policy.

  • state: Crawler identity
  • state: Request surface
  • state: Profile
  • state: Zone conditions
  • artifact: Effective policy
  • identity requires effective
  • surface requires effective
  • profile requires effective
  • zone requires effective
Identity, URL class, profile, and local conditions converge in the zone’s effective policy.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g02 · authorial model

Three URL classes

SurfaceExamplesDecision in this case
Public contentHomepage, product, category, articleThis policy leaves the request outside its block rule
Transactional hard-denyCart, checkout, account, operational query parametersThe selected crawler class is blocked at the edge
CombinatorialFilters, faceted navigation, internal search, parameter combinationsHostname-specific SEO review before a policy change

The example paths match /cart, /checkout, /my-account, and descendants with a / after the name. A similar prefix such as /cartography is outside that list. Translated WooCommerce slugs, language prefixes, URL encoding, and query behaviour require testing on each actual site.

The demonstration rule searches for add-to-cart=, remove_item=, and wc-ajax= as query substrings. This simple example may also match another parameter’s value. Its matching precision needs review before production use. Filters and search remain outside the shared example: a useful SEO landing page on one store may resemble an unnecessary combination on another.

Identity and scope

Using all of cf.client.bot as this case’s crawler list would be too broad. Verified automation also includes monitoring, security checks, and other services. The demonstration uses narrower cf.verified_bot_category values:

Search Engine Crawler
AI Search
AI Crawler
Page Preview

It adds User-Agent fallbacks for Meta-WebIndexer, Googlebot, and Bingbot. These strings can be spoofed: a fallback classifies a request but does not authenticate its origin. As checked on 6 September 2026, Cloudflare retains these legacy categories for WAF compatibility, while its new taxonomy classifies bot behaviour differently. Verified bots

gateIdentity and surface

A request is blocked only when both the selected crawler identity and the transactional surface match.

  • state: Crawler identity match
  • state: Transactional surface match
  • decision: Both conditions
  • boundary: Block at edge
  • state: Outside this block rule
  • identity requires and
  • surface requires and
  • and rejects block: Yes
  • and returns other: No
A request is blocked only when both the selected crawler identity and the transactional surface match.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g03 · authorial model
RequestResult of Crawler Surface Policy itself
Meta-WebIndexer → /Not blocked by this rule
Meta-WebIndexer → /product/...Not blocked by this rule
Meta-WebIndexer → /cart/Block
Meta-WebIndexer → /checkout/Block

Other Cloudflare rules and the origin can change the final response. Failure to match one block rule does not create a global allow.

Why the edge

The restriction could be implemented in WordPress, Apache, nginx, or the application. Choosing Cloudflare places rejection before the origin: a crawler matching the defined transactional surface should not invoke WooCommerce. Custom Rules execute in their own ruleset-engine phase. Cloudflare Custom Rules

The initial production model combined a global baseline, site profile, and hostname exceptions. The portable tool generalises that model through explicit policy composition.

flowFrom profile to effective state

Profile policies, additional policies, disabled policies, and inline rules determine logical rules; the compiler turns them into physical rules.

  • state: Profile policies
  • state: Additional policies
  • boundary: Disabled policies
  • state: Inline rules
  • state: Logical rules
  • state: Physical rules
  • artifact: Effective managed state
  • profile produces logical
  • additional produces logical
  • disabled rejects logical: Remove from composition
  • inline produces logical
  • logical derives physical
  • physical produces state
Profile policies, additional policies, disabled policies, and inline rules determine logical rules; the compiler turns them into physical rules.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g04 · authorial model

From production workspace to a standalone repository

The original shared-hosting workspace contained policies, profiles, exceptions, scripts, backups, and reports. It produced the compiler, diff, dry-run, audit, deployment, snapshots, and edge smoke. The standalone repository contains the reusable mechanism, fixtures, and demonstration configurations. Private client overlays remain outside it.

Path in IRONCREED/cloudflarePurpose
CONSTITUTION.md, governance/PROFILE.mdAdopted normative source and release-candidate profile
LICENSE.mdLicensing map for code, prose, and branding
code-constitution/Normative-corpus submodule pinned to a commit
repository-licensing-policy/Licensing-policy submodule pinned to a commit
cases/001-crawler-surface-policy/bin/compile, plan, apply, audit, export, rollout
cases/001-crawler-surface-policy/src/PHP API client, compiler, and Ruleset Manager
cases/001-crawler-surface-policy/examples/Inventory, profiles, policies, and zone fixtures
cases/001-crawler-surface-policy/tests/Offline checks without Cloudflare tokens
cases/001-crawler-surface-policy/runtime/Local output excluded from Git

The relocation preserves the case ID, licences, and exact submodule revisions. A provenance record identifies the source tree and subsequent changes. Repository preparation and automated checks leave the final release decision with a human.

Case 001’s boundaries

The tool manages zone-level WAF Custom Rules in http_request_firewall_custom. DNS, Workers, Zero Trust, cache rules, billing, account membership, and origin configuration remain outside this case.

flowCase 001 operating cycle

Explicit inventory leads to compilation, live-state inspection, a plan preserving the unmanaged portion, a separate operator decision, and result verification.

  • source: Explicit inventory
  • process: Compile
  • process: Read live phase
  • process: Preserve unmanaged
  • artifact: Plan / diff
  • human-decision: Operator decision
  • process: Apply and snapshots
  • process: Readback and audit
  • inventory derives compile
  • compile derives live
  • live derives preserve
  • preserve derives plan
  • plan derives review
  • review derives apply
  • apply derives verify
Explicit inventory leads to compilation, live-state inspection, a plan preserving the unmanaged portion, a separate operator decision, and result verification.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g05 · authorial model

The files bot-example.json, country-policy.json, crawler-surface.json, named-ip-list.example.json, and scanner-user-agents.json demonstrate the mechanism’s capabilities. For example, the commerce fixture additionally includes bot-example; reproducing the pilot’s surface-only restriction requires separately reviewing and, where appropriate, removing that extra policy. The examples are not a production baseline.

Inventory, profiles, and exceptions

The inventory explicitly lists zones, phase, ownership prefix, and budget:

{
	"schema_version": 1,
	"phase": "http_request_firewall_custom",
	"managed_prefix": "[CFOPS]",
	"max_physical_rules": 5,
	"zones": ["domain-01.example", "domain-02.example", "domain-03.example"]
}

5 is an example parameter tied to the pilot’s conditions. Check it against actual zone limits; the budget must also count unmanaged rules. Custom Rules availability

ProfilePolicies
defaultscanner-user-agents
commercescanner-user-agents, crawler-surface
restricted-geoscanner-user-agents, country-policy

A zone configuration selects a profile and modifies its composition:

{
	"zone": "domain-02.example",
	"profile": "commerce",
	"additional_policies": ["bot-example"],
	"disabled_policies": []
}
topologyCommerce fixture

Two profile policies and one zone policy form three logical components.

  • source: Commerce profile
  • state: scanner-user-agents
  • state: crawler-surface
  • source: Zone additional_policies
  • state: bot-example
  • profile requires scanner
  • profile requires surface
  • additional produces bot
Two profile policies and one zone policy form three logical components.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g06 · authorial model

An inline rule can handle one hostname without creating another shared profile. The compiler also requires id and name:

{
	"zone": "domain-03.example",
	"profile": "restricted-geo",
	"inline_rules": [
		{
			"id": "forum-example",
			"name": "Forum hostname example",
			"action": "managed_challenge",
			"physical_group": "challenge",
			"expression": "(http.host eq \"forum.domain-03.example\" and ip.src.country ne \"UA\")"
		}
	]
}

The geographic restriction demonstrates an exception mechanism. Its suitability depends on the actual site’s audience.

Logical and physical rules

PolicyCompiler collects profile policies, adds additional_policies, removes disabled_policies, and appends inline_rules. Simple rules with the same action and physical_group are joined with or into one physical rule. Their logical files remain separate.

flowLogical → physical

Several logical block policies form one physical block rule; challenge remains a separate group.

  • state: Logical block policy A
  • state: Logical block policy B
  • state: Logical block policy C
  • artifact: One physical block
  • state: Logical challenge policy
  • artifact: Separate physical challenge
  • scanner derives block
  • surface derives block
  • bot derives block
  • challenge derives challenge-out
Several logical block policies form one physical block rule; challenge remains a separate group.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g07 · authorial model
(crawler_surface_condition) or (bot_condition)

This is an explanatory formula, not a deployable Cloudflare expression. Grouping requires compatible actions and a review of execution order. The current compiler serves the demonstrated simple rules; it does not guarantee preservation of arbitrary action_parameters in managed policies.

The managed/unmanaged boundary

The tool owns only rules whose description begins with [CFOPS]. A new managed block replaces the first previous managed rule’s position; when none exists, it is appended. Unmanaged rules retain their relative order.

gateOwnership boundary

The prefix defines ownership; managed rules are replaced, while the remainder enters the plan with its relative order preserved.

  • source: Live rules
  • decision: Description starts with prefix?
  • process: Replace managed block
  • process: Preserve unmanaged relative order
  • artifact: Final plan
  • live references prefix
  • prefix executes managed: Yes
  • prefix returns unmanaged: No
  • managed produces plan
  • unmanaged produces plan
The prefix defines ownership; managed rules are replaced, while the remainder enters the plan with its relative order preserved.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g08 · authorial model

If managed and unmanaged rules were interleaved, collecting the managed portion into one block may change their positions relative to each other. Review the plan for that change. Another writer using the same prefix breaks the ownership boundary. Sequential rollout inside one process also provides no lock against simultaneous dashboard edits or another tool.

A local WSL environment

On Windows, WSL can be installed from PowerShell:

wsl --install -d Ubuntu

The command and prerequisites are described in Microsoft’s documentation. Inside Ubuntu, install Git, PHP 8.1+, and cURL:

sudo apt update
sudo apt install -y git php-cli php-curl
git clone https://github.com/IRONCREED/cloudflare.git
cd cloudflare
git submodule update --init --recursive
cd cases/001-crawler-surface-policy
php tests/run.php
cp -R examples local
export CFOPS_CONFIG_DIR="$PWD/local"
export CFOPS_RUNTIME_DIR="$PWD/runtime"

local/ is excluded from Git and holds real zones and private overlays. runtime/ holds snapshots and reports. Access to normative submodules follows their own repositories’ policies; offline engine tests do not require downloading them. Copy examples during the first installation, before editing local configuration.

Creating and storing API tokens

In Cloudflare, open your profile → API Tokens → Create Token → Create Custom Token. Read operations in this case require Zone / Zone / Read for zone-ID lookup and Zone / WAF / Read for rulesets. Give a separate write token Zone / Zone / Read and Zone / WAF / Edit; it is also used for inspection before and after writing. Restrict both tokens to the required zones and, where practical, an expiry and the operator’s IP. Check permission names and availability in the current interface. Create a token, permission reference

For a single Bash session, enter the read token without displaying it or placing its value in command history:

read -rsp 'Cloudflare read token: ' CLOUDFLARE_READ_TOKEN
printf '\n'
export CLOUDFLARE_READ_TOKEN

Enter the write token in the same way as CLOUDFLARE_WRITE_TOKEN immediately before an approved operation, then remove it from the environment:

read -rsp 'Cloudflare write token: ' CLOUDFLARE_WRITE_TOKEN
printf '\n'
export CLOUDFLARE_WRITE_TOKEN
# Run the reviewed apply command here.
unset CLOUDFLARE_WRITE_TOKEN

For reuse, use a secrets manager or a file outside the checkout, for example under ~/.config/ironcreed/cloudflare/, with directory permissions 700 and file permissions 600. Enter values through an editor or secrets manager; .gitignore cannot remove a secret already committed to Git history. Revoke and replace an exposed token. Environment variables are inherited by child processes, so load the write token only for the operation.

gateCredential separation

A read token supports observation; a write token together with an explicit decision opens the apply path.

  • source: Read token
  • process: Plan / audit / export
  • source: Write token
  • human-decision: Review and --apply
  • process: API write
  • read requires observe
  • write requires apply
  • human validates apply
A read token supports observation; a write token together with an explicit decision opens the apply path.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g09 · authorial model

Fixtures, compile, and plan

php tests/run.php checks the local compilation model without API tokens. These tests do not execute expressions at the Cloudflare edge. Compilation is also local:

php bin/compile.php --zone=domain-02.example

Plan uses the read token and an actual zone’s configuration. Replace example.com in the following commands with a zone from your own inventory:

php bin/plan.php --zone=example.com

Ruleset Manager resolves the zone ID, reads the phase entry point, separates managed rules, compiles desired state, constructs the final list, checks the budget, and identifies a change. It performs no write. Expression comparison preserves whitespace inside strings; a formatting difference can produce a conservative review signal.

Apply and evidence

php bin/apply.php --zone=example.com --apply

Without --apply, the CLI refuses before creating an API client. With that flag, it uses the separate write token. Before writing, the tool reads the current state again and checks the limit. An unchanged result returns NO_CHANGE.

gateWrite boundary

Plan and budget checks precede the snapshot; ruleset write is followed by readback, and a mismatch stops the operation.

  • process: Fresh inspection
  • decision: Within budget?
  • artifact: Before snapshot
  • process: Ruleset write
  • process: Readback / after snapshot
  • decision: Expected state?
  • state: Verified
  • boundary: Stop with error
  • inspect produces budget
  • budget validates snapshot: Yes
  • budget rejects stop: No
  • snapshot requires write
  • write produces readback
  • readback validates match
  • match validates success: Yes
  • match rejects stop: No
Plan and budget checks precede the snapshot; ruleset write is followed by readback, and a mismatch stops the operation.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g10 · authorial model

A change creates a unique runtime/deployments/<timestamp-random>--<zone>/ directory containing before.json, write-response.json, and after.json. An existing entry point is updated through one ruleset operation; otherwise, a zone ruleset is created for the phase. Rulesets API

Live state is read again after the write. Remaining drift ends the operation with Post-write verification failed. A successful HTTP response alone does not establish a correct deployment. Case 001 provides no automatic rollback; restoration from a snapshot is a separate reviewed operator action.

Fleet rollout, audit, and export

CommandOperation
php bin/rollout.phpSequential dry-run over the inventory
php bin/rollout.php --applySequential writes; an exception stops subsequent zones
php bin/audit.phpCompare live and desired state across the inventory
php bin/export.phpSave current phase entry points locally
lifecycleFleet control

Zones are checked sequentially; changes are limited by assigned policies, and an error terminates rollout.

  • source: Inventory zones
  • state: Current zone
  • decision: Plan: change needed?
  • human-decision: Has --apply?
  • process: Write and verify
  • process: Next zone
  • boundary: Error: stop
  • inventory produces zone
  • zone references plan
  • plan requires review: Yes
  • plan returns next: NO_CHANGE
  • review validates write: Yes
  • review returns next: Dry-run
  • write produces next: Success
  • write rejects stop: Error
Zones are checked sequentially; changes are limited by assigned policies, and an error terminates rollout.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g11 · authorial model
comparisonDetecting drift

Live state and compiled desired state meet in a comparison returning either agreement or divergence.

  • source: Live state
  • source: Compiled desired state
  • process: Comparison
  • state: Match
  • boundary: DRIFT: review
  • live references compare
  • desired requires compare
  • compare validates ok
  • compare rejects drift
Live state and compiled desired state meet in a comparison returning either agreement or divergence.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g12 · authorial model

Audit reports drift and retains the read-only boundary. Snapshots, reports, and exports stay local. Traversing the entire inventory is also useful for demonstrating that most zones require no changes.

The original pilot’s results

The pilot ran on the earlier private EMBO tools before Case 001 was extracted. The following numbers come from the author’s pilot account; they are not results of a new production run of the standalone code.

StageCustom Rule count
Before: baseline Block, Asia Challenge, Meta-WebIndexer hotfix3
Remove / keep / add2 / 1 / 1
After moving the hotfix’s function into compiled policy2 of the 5 available in the pilot
Smoke requestRecorded HTTP status
Normal /200
Meta /200
Normal /cart/200
Meta /cart/403
Googlebot /cart/403
Meta /checkout/403
Meta /my-account/403
Meta add-to-cart403
Meta remove_item403
Meta wc-ajax403

The author’s smoke summary was 10 PASS, 0 FAIL. Meta and Googlebot name test-request profiles; a substituted User-Agent alone does not test a real verified identity. The homepage’s 200 records access in that test rather than a guarantee for every future request.

Fleet check after the pilotAuthor-reported result
Audit22 OK, 0 DRIFT, 0 ERROR
Diff22 OK, 0 CHANGES, 0 OVER LIMIT, 0 ERROR
Fleet dry-run22 NO_CHANGE

According to the pilot account, the commerce change was assigned to one zone; the other 21 retained their previous expected configuration. These aggregate results express the intended acceptance criterion. Independent reproduction requires your own configuration, a reviewed plan, and an edge smoke.

From pilot to portable pipeline

Earlier tooling functionCase 001 boundary
policy-compiler.phpcompile.php
diff.phpplan.php
deploy.phpapply.php --apply
audit.phpaudit.php
complete-export.phpexport.php
rollout.phprollout.php, separate --apply
validate-expression.php, crawler-surface-smoke.phpSeparate deployment checks; not ported into the current Case 001
flowPortable pipeline

Local configuration and fixtures lead to compile, plan, dry-run, operator review, apply, readback, and audit; site-specific edge smoke remains a separate deployment check.

  • source: Local paths and credentials
  • process: Fixtures
  • process: Compile
  • process: Plan / diff
  • process: Fleet dry-run
  • human-decision: Operator review
  • process: Apply / snapshot / readback
  • process: Separate edge smoke
  • process: Audit / export
  • setup derives fixtures
  • fixtures derives compile
  • compile derives plan
  • plan derives dry
  • dry derives review
  • review derives apply
  • apply derives smoke
  • smoke derives audit
Local configuration and fixtures lead to compile, plan, dry-run, operator review, apply, readback, and audit; site-specific edge smoke remains a separate deployment check.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g13 · authorial model

The operational discipline follows compile → diff/plan → dry-run → apply → smoke → audit. Different commands test different claims: compilation checks the model, plan identifies divergence from live state, smoke tests request behaviour, and audit checks the expected state after a change. Readback does not replace edge smoke.

Telemetry and an analytical LLM layer

Crawler telemetry can report a new traffic class across several hostnames or a zone’s departure from its usual profile. That observation becomes a proposal for a policy revision. Authority to perform a security write remains a separate operator responsibility.

flowFrom telemetry to authorised change

Telemetry opens a proposal; tests, plan, and human review precede explicit apply and verification.

  • source: Telemetry / LLM observation
  • artifact: Policy proposal
  • process: Compile and tests
  • artifact: Plan / diff
  • human-decision: Human review
  • process: Explicit apply
  • process: Verification
  • observe derives proposal
  • proposal derives compile
  • compile derives plan
  • plan derives human
  • human derives apply
  • apply derives verify
Telemetry opens a proposal; tests, plan, and human review precede explicit apply and verification.IRONCREED semantic-core · asset.cloudflare-001-crawler-surface-policy.g14 · authorial model

The analytical layer receives no write token. This allows observation to be automated while changes to site availability remain explicit, reviewable actions.

Boundaries and result

The case addresses a bounded task: express crawler access through identity and surface, assign the policy to the intended zone, and check the rest of the inventory. Faceted navigation, filters, and search require separate decisions; a commerce profile is assigned only after reviewing the actual site.

The result is a shared policy-management system with different effective states for individual zones. The repository separates a reusable mechanism from client data: demonstration domains use domain-N.example, private overlays and tokens stay local, and writes follow a separate controlled path.

Case author and source of the original production account: Sam Starling. Translation, editorial adaptation, questions, public-documentation verification, and standalone-code preparation were assisted by AI. Platform sources were checked on 6 September 2026; preparing this article involved no repeat deployment to the client’s Cloudflare account.

Questions about this material · 12
What is Crawler Surface Policy, and how does it differ from globally blocking a crawler?

It is a policy combining an automated client’s identity with the requested URL class. In this case, crawlers are blocked on WooCommerce’s transactional surface while public pages remain outside that block rule. A global identity block would cover every URL. Other WAF rules and the origin still affect the final response.

Open in the registry
Why should a verified or useful crawler not automatically have access to every site URL?

Authenticated origin and indexing value do not determine whether every operation is appropriate. Cart, account, or operational endpoints may generate load without indexing value. Verified automation also includes services outside this case’s crawler class. Decisions must consider both client purpose and surface; a User-Agent fallback alone does not verify identity.

Open in the registry
Which WooCommerce URLs are candidates for a transactional hard-deny surface for crawlers?

Initial candidates are cart, checkout, account, and add-to-cart, remove_item, and wc-ajax operations. Verify actual slugs, descendant paths, language prefixes, and query semantics. A parameter substring may match inside another value. Filters, faceted navigation, and search need a separate hostname-specific SEO decision.

Open in the registry
How should crawler identity and request surface be separated in a Cloudflare WAF policy?

Express identity as a separate category or explicit User-Agent condition and surface as a separate path-and-parameter condition. Blocking requires both through and; alternatives within each group use or. Parentheses and negative examples should demonstrate that public content and ordinary visitors remain outside this particular restriction.

Open in the registry
How can profiles and hostname exceptions manage different Cloudflare policies across several sites?

An explicit inventory lists zones. Each selects a profile, adds or disables policies, and may contain an inline hostname-specific rule. The compiler produces a separate effective state for every zone. Changing one commerce zone should not assign commerce policy to all others; plans and a fleet dry-run check that boundary.

Open in the registry
Why should security deployment follow compile → diff → dry-run → apply → smoke → audit?

The stages test different claims: compile checks the model; diff/plan compares live state; dry-run checks fleet scope; apply writes explicitly; smoke tests request behaviour; audit checks desired state. Pre-write snapshots and post-write readback preserve evidence. Case 001 implements readback, while site-specific edge smoke remains a separate deployment check.

Open in the registry
Why separate read-only and write API tokens in Cloudflare automation?

Inspecting state does not require permission to modify WAF. Separate scopes and environment variables reduce the authority of routine diagnostics. Load a write token before a reviewed operation and unset it afterwards. The --apply flag complements credential separation; it neither changes token permissions nor prevents every mistake.

Open in the registry
How can a Cloudflare API token be created and stored safely for local work through WSL?

Create a custom token in your Cloudflare profile and restrict it to required zones and operations. Case 001 uses Zone Read plus Zone WAF Read for reading, and Zone Read plus Zone WAF Edit for writing. In Bash, enter values with read -rsp to avoid command history. Store them in a secrets manager or outside the checkout in a 600-permission file within a 700-permission directory. Unset the write token after use; revoke and replace it after exposure. This contract is reusable by future series articles.

Open in the registry
How can a limited Cloudflare Custom Rule budget be used while keeping logical policies separate?

Keep logical policies in separate files and merge compatible simple rules with the same action and physicalgroup during compilation. Count unmanaged rules in the budget too. Grouping can affect order, so review the plan; arbitrary actionparameters are not supported merely by assumption. The fixture’s value of 5 is an example parameter to check against the actual zone.

Open in the registry
What is configuration drift across Cloudflare zones, and how can it be detected?

Drift is divergence between live state and the compiled expectation for a particular zone. Audit reads the inventory and compares state within the model; different profiles may legitimately produce different rules. Detecting drift does not authorise automatic remediation. A comparison also cannot prove that the desired policy itself is correct.

Open in the registry
Which Cloudflare infrastructure data can belong in a public monorepo, and which should remain local?

This project publishes the engine, tests, safe fixtures, demonstration policies, and normative references. Tokens, client inventory, zone IDs, private hostname overlays, and production snapshots are excluded. A zone ID is not an authentication secret, but belongs to this case’s protected operational map. Examples use reserved domains; .gitignore complements checks of tracked files and history.

Open in the registry
Why can crawler telemetry be automated while security writes remain explicit operator actions?

Telemetry produces observations and candidate explanations; a WAF write changes availability for people and integrations. A policy diff, tests, plan, and human decision separate the two. An analytical LLM layer has no write token, while approved apply follows a separate path with evidence and verification. This separates authority to propose from authority to execute.

Open in the registry

A useful crawler still needs a defined access surface.