# Cloudflare

> Query Cloudflare HTTP analytics AND manage security rules across zones.

Query Cloudflare HTTP analytics AND manage security rules across zones. Traffic investigation (top IPs, paths, user agents, bot scores, timelines, scrape analysis) plus export and port of Custom Rules + Rate Limit Rules between zones (e.g. civitai.com -> civitai.red).

- Page: https://ss33.ai/skills/civitai/cloudflare-76640384839
- Publisher: civitai
- Category: [Security](https://ss33.ai/skills/category/security-w9g95g) › [Cloud & infrastructure security](https://ss33.ai/skills/category/security-w9g95g/cloud-and-infrastructure-security-h7oqxp)
- License: Apache-2.0
- Source: https://github.com/civitai/civitai/blob/525355bc1e906f5da1732ea7202f95443a11db04/.claude/skills/cloudflare/SKILL.md

## Skill

SKILL.md: https://ss33.ai/api/v1/ss33/download/civitai/cloudflare-76640384839

# Cloudflare Analytics + Rule Management

Query Cloudflare HTTP traffic analytics and manage security rules (Custom Rules, Rate Limit Rules) across zones. The `CF_API_TOKEN` in `.env` needs **Zone Analytics: Read** for analytics, and **Zone WAF: Edit** for rule management.

## Running Commands

```bash
node .claude/skills/cloudflare/query.mjs <command> [options]
```

### Commands

| Command | Description |
|---------|-------------|
| `top-clients` | Top IPs by request count |
| `top-paths` | Top request paths |
| `top-agents` | Top user agents |
| `timeline` | Requests per minute timeline (bar chart) |
| `ip <addr>` | Full breakdown for a specific IP (paths, UAs, statuses, geo) |
| `scrape` | Full scrape analysis — top IPs, paths, UAs + detail on high-volume IPs |
| `bot-scores` | Bot score distribution |
| `bot-clients` | Top clients with low bot scores (likely bots) |
| `firewall` | Recent firewall/WAF events |
| `rate-limits` | Current rate limit rules |
| `waf-rules` | Current WAF custom rules |
| `list-zones` | List all accessible zones (id, name, plan) |
| `export-rules <zone>` | Dump Custom Rules + Rate Limit Rules from a zone |
| `port-rules` | Copy rules between zones (dry-run by default) |

### Flags

| Flag | Description |
|------|-------------|
| `--start`, `--from` | Start time: relative (`-1h`, `-2d`, `-30m`), time (`16:41`), or ISO datetime |
| `--end`, `--to` | End time (default: now) |
| `--limit` | Max results (default: 20) |
| `--path` | Filter by path pattern using SQL LIKE (`/api/%`, `/api/trpc/%`) |
| `--ip` | Filter by client IP |
| `--score` | Max bot score for `bot-clients` (default: 10) |
| `--source`, `--target` | Zone name or id (used by `port-rules`) |
| `--phase` | `custom`, `ratelimit`, or `all` (default) for rule commands |
| `--out` | Write `export-rules` output to a JSON file |
| `--skip-disabled` | When porting, skip rules with `enabled: false` |
| `--skip-hosts` | Comma-separated list of hosts; rules referencing them are skipped |
| `--rewrite-host FROM:TO` | Replace `"FROM"` with `"TO"` in rule expressions during port |
| `--only` | Comma-separated substrings; only port rules whose description matches |
| `--pro-compat` | Strip Enterprise-only syntax to fit Pro/Free target zones (see below) |
| `--apply` | Actually write. Without this, `port-rules` is a dry run |

Only `--skip-disabled`, `--pro-compat` and `--apply` carry no value; each also accepts an explicit
`--apply true` / `--apply false`. Every other flag must be given one — a bare flag, or one whose value
starts with `--`, is an error rather than the string `'true'` it used to become. Use `--flag=value` for a
value that legitimately starts with `--`.

### Examples

```bash
# Full scrape analysis for a time window
node .claude/skills/cloudflare/query.mjs scrape --start "2026-03-24 16:41" --end "2026-03-24 19:08"

# Top IPs hitting API endpoints in the last 2 hours
node .claude/skills/cloudflare/query.mjs top-clients --start -2h --path "/api/%"

# What paths is a specific IP hitting?
node .claude/skills/cloudflare/query.mjs ip 1.2.3.4 --start -6h

# Traffic timeline for API/trpc routes
node .claude/skills/cloudflare/query.mjs timeline --start -1h --path "/api/trpc/%"

# Find likely bots (low bot score) hitting API
node .claude/skills/cloudflare/query.mjs bot-clients --start -3h --score 5 --path "/api/%"

# Top user agents on search-related paths
node .claude/skills/cloudflare/query.mjs top-agents --start -2h --path "/api/trpc/image%"

# Check current rate limit rules
node .claude/skills/cloudflare/query.mjs rate-limits

# List all zones (id, name, plan)
node .claude/skills/cloudflare/query.mjs list-zones

# Export civitai.com rules (custom + rate limit) to a file
node .claude/skills/cloudflare/query.mjs export-rules civitai.com --out com-rules.json

# Dry-run a port from civitai.com to civitai.red — preview only
node .claude/skills/cloudflare/query.mjs port-rules \
  --source civitai.com --target civitai.red \
  --skip-disabled \
  --skip-hosts api.civitai.com,metrics.civitai.com,education.civitai.com,image.civitai.com,meilisearch-v1-9.civitai.com,meilisearch-v1-6.civitai.com,meilisearch-metrics.civitai.com \
  --rewrite-host civitai.com:civitai.red \
  --pro-compat

# Same thing, but actually write it (REPLACES target rulesets wholesale)
node .claude/skills/cloudflare/query.mjs port-rules \
  --source civitai.com --target civitai.red \
  --skip-disabled \
  --skip-hosts api.civitai.com,metrics.civitai.com,education.civitai.com,image.civitai.com,meilisearch-v1-9.civitai.com,meilisearch-v1-6.civitai.com,meilisearch-metrics.civitai.com \
  --rewrite-host civitai.com:civitai.red \
  --pro-compat \
  --apply

# Port only specific rules (match by description substring)
node .claude/skills/cloudflare/query.mjs port-rules \
  --source civitai.com --target civitai.red --phase ratelimit \
  --only "Global Limit,Rate limit trpc (No Regex)" \
  --rewrite-host civitai.com:civitai.red \
  --pro-compat --apply
```

## Porting Security Rules Between Zones

`port-rules` replaces the target zone's Custom Rules ruleset and/or Rate Limit Rules entrypoint with a filtered + transformed copy of the source zone's rules. It **overwrites** the target ruleset — existing rules on the target are wiped.

### What gets ported

The Cloudflare "Security Rules" surface maps to two phase entrypoints:

| Phase | UI name | Flag value |
|-------|---------|-----------|
| `http_request_firewall_custom` | Custom Rules | `--phase custom` |
| `http_ratelimit` | Rate Limit Rules | `--phase ratelimit` |

Managed Rules, IP Access Rules, Zone Lockdown, and User Agent Blocking are **not** ported.

### Filters

Without filters, every rule from the source is copied as-is.

- `--skip-disabled` drops rules where `enabled: false`.
- `--skip-hosts host1,host2` drops any rule whose expression literal-matches one of the listed hosts (useful for source-only subdomains that don't exist on the target zone).
- `--only pat1,pat2` keeps only rules whose description contains one of the given substrings.
- `--rewrite-host FROM:TO` rewrites `"FROM"` → `"TO"` inside rule expressions after the skip filter runs. Use this to point apex-host rules at the new zone (`civitai.com:civitai.red`).

### Pro-plan / Free-plan compatibility (`--pro-compat`)

Cloudflare Pro zones reject several Enterprise-only rule features that are commonly used on Business/Enterprise source zones. When the target zone plan is `pro` or `free`, `--pro-compat` is applied automatically; otherwise pass it explicitly. Transforms:

- **IP list exclusions**: `and not ip.src in {…}` / `and ip.src in {…}` clauses are stripped. Pro zones don't support `ip.src in` expressions in rate-limit rules.
- **Bot management checks**: `and not cf.bot_management.verified_bot` / `and cf.bot_management.verified_bot` clauses are stripped (Bot Management is an Enterprise feature).
- **Rate-limit period**: Pro only allows periods in `[10, 15, 20, 30, 40, 45, 60]` seconds. Rules with longer periods (e.g. 300s) are scaled to 60s and the `requests_per_period` is scaled proportionally to preserve the same req/s rate.
- **`requests_to_origin`**: stripped (Enterprise-only).

Each transform is reported in the dry-run output as a `~` line so you can review them before applying.

### Rule-count limits

Target zone plans cap the number of rules per phase. If the port exceeds the cap, Cloudflare returns `exceeded the maximum number of rules in the phase X: N out of M`. Common caps:

| Plan | Custom Rules | Rate Limit Rules |
|------|--------------|------------------|
| Free | 5 | 1 |
| Pro | 20 | 2 |
| Business | 100 | 15 |
| Enterprise | 1000+ | 1000+ |

Use `--only` or manually trim the source rule list if you hit the cap.

### Known constraints

- `ref` is stripped on write so rules are re-id'd on the target. This means subsequent ports between the same two zones replace wholesale, not diff-and-merge.
- Managed Rules, IP Access Rules, Zone Lockdown, User Agent Blocking, and legacy Firewall Rules are **not** ported.
- Account-scoped custom lists (e.g. `$attackers`, `$bandwidth_theft`) work across zones in the same account with no change.

## Investigation Workflow

For scraping investigations:

1. **Start broad**: `scrape --start ... --end ...` to see top IPs, paths, and UAs
2. **Identify suspects**: Look for IPs with disproportionate request counts
3. **Deep dive**: `ip <addr>` to see what specific IP is doing
4. **Check bots**: `bot-clients --score 5` to find CF-detected bots
5. **Timeline**: `timeline --ip <addr>` to see traffic pattern over time
6. **Review defenses**: `rate-limits` and `firewall` to see what's in place
