---
# System prepended metadata

title: Cloudflare WAF Rules

---

# 用 Claude Code + Cloudflare MCP 自動設定 WAF 防火牆規則

透過 nginx log 觀察，我的網站都會收到大量探測請求：掃 `.env`、掃 `wp-admin`、掃 `xmlrpc.php`。這些請求不只浪費頻寬，還是攻擊的前哨。

然後我就想到了 Cloudflare 有出 MCP plugin，可以用 Claude Code 透過對話直接把防火牆規則設定到 Cloudflare，完全不用進 Dashboard 手動操作，超讚！
>除了設定權限和產 API Key 需要人工授權

---

## 安裝 Cloudflare Plugin

Claude Code 支援 plugin 生態系。Cloudflare 官方有提供 plugin，整合了 Cloudflare MCP Server，讓 Claude 能直接呼叫 Cloudflare API。

先打開你的 claude code 對話視窗，依序輸入下面官方提供的指令：

```
# 加入資源
/plugin marketplace add cloudflare/skills

# 安裝
/plugin install cloudflare@cloudflare

# 在這個 session 重載 plugin
/reload-plugins
```

安裝後 Claude 會多出以下幾個工具：

- `cloudflare-api` — 執行 Cloudflare API 請求
- `cloudflare-docs` — 搜尋官方文件
- Cloudflare 相關 skills（WAF、Workers、D1 等）

---

## 先查文件，再動手

我習慣在做任何 Cloudflare 設定前先問文件，避免用到過時的 API：

```
調整 cloudflare 防火牆規則，阻止惡意的連線，
例如 URI 包含 /^\./|wp-/ 之類的請求
```

Claude 會透過 `cloudflare-docs` 搜尋工具拉取最新文件，確認目前的 WAF 規則語法。

**重要發現**：Cloudflare 的 regex 支援（`matches` operator）只在 Business 和 Enterprise 方案才有。Free 方案只能用：

| Operator | 說明 |
|----------|------|
| `starts_with()` | 路徑開頭比對 |
| `ends_with()` | 路徑結尾比對 |
| `contains()` | 包含字串 |
| `wildcard` | 萬用字元（`*`） |
| `eq` | 完全相等 |

---

## OAuth 認證與權限問題

Cloudflare plugin 使用 OAuth 流程認證。Claude 會產生一個授權連結，在瀏覽器完成後，MCP Server 取得 token。

但這裡有個問題：**OAuth token Permission 我不敢全開，所以只有給系統建議的 read only 權限**，呼叫 WAF Rulesets API 會拿到 `Authentication error (10000)`。

解法是手動建立一個有 WAF 寫入權限的 API Token：

1. 前往 Cloudflare Dashboard → **My Profile → API Tokens → Create Token**
2. 選 **Custom Token**，設定：
   - **Permissions**：`Zone → WAF → Edit`
   - **Zone Resources**：選擇你的 zone
3. 建立後複製 token

![截圖 2026-04-15 下午6.49.20](https://hackmd.io/_uploads/HyXbxl6hWg.png)

---

## 另一個坑：Rulesets API vs. 舊版 Firewall Rules API

Cloudflare 有兩套 WAF API：

| API | 路徑 | 狀態 |
|-----|------|------|
| 舊版 Firewall Rules | `/zones/{id}/firewall/rules` | 已棄用但仍可用 |
| 新版 Rulesets | `/zones/{id}/rulesets/phases/http_request_firewall_custom/entrypoint` | 現行標準 |

即使 token 有 `#waf:edit` 權限，呼叫新版 Rulesets API 仍然會拿到 `Authentication error`。原因是新版 Rulesets API 要求的內部權限範圍（`#com.cloudflare.api.account.zone.ruleset:edit`）並非一般 WAF token 能覆蓋的。

實際測試後，用**舊版 API** 完全可行，且 Free 方案也支援。

---

## 實際使用的 API 流程 (這裡都是 AI 在操作，我只有按確認)

舊版 Firewall Rules API 需要兩步：先建 **Filter**，再建 **Rule**。

### Step 1：建立 Filters

```python
import json, urllib.request

zone_id = 'YOUR_ZONE_ID'
token = 'YOUR_API_TOKEN'

filters = [
    {
        'expression': '(starts_with(http.request.uri.path, "/."))',
        'description': 'Block dotfiles and hidden paths'
    },
    {
        'expression': (
            '(http.request.uri.path wildcard "/wp-*") or '
            '(http.request.uri.path wildcard "/*/wp-*") or '
            '(http.request.uri.path eq "/xmlrpc.php")'
        ),
        'description': 'Block WordPress probes'
    }
]

body = json.dumps(filters).encode()
req = urllib.request.Request(
    f'https://api.cloudflare.com/client/v4/zones/{zone_id}/filters',
    data=body,
    headers={
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    },
    method='POST'
)

with urllib.request.urlopen(req) as resp:
    result = json.loads(resp.read())
    print(json.dumps(result, indent=2))
```

回傳會包含每個 filter 的 `id`，下一步會用到。

### Step 2：建立 Firewall Rules

```python
rules = [
    {
        'filter': {'id': 'FILTER_ID_1'},   # dotfiles filter id
        'action': 'block',
        'description': 'Block dotfiles and hidden paths',
        'paused': False
    },
    {
        'filter': {'id': 'FILTER_ID_2'},   # wordpress filter id
        'action': 'block',
        'description': 'Block WordPress probes',
        'paused': False
    }
]

body = json.dumps(rules).encode()
req = urllib.request.Request(
    f'https://api.cloudflare.com/client/v4/zones/{zone_id}/firewall/rules',
    data=body,
    headers={
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    },
    method='POST'
)

with urllib.request.urlopen(req) as resp:
    result = json.loads(resp.read())
    print(json.dumps(result, indent=2))
```

---

## 最終建立的規則

| 規則名稱 | Expression | 涵蓋範圍 |
|---------|-----------|---------|
| Block dotfiles | `starts_with(uri.path, "/.")` | `.env`, `.git`, `.htaccess`, `.DS_Store` |
| Block WordPress probes | `wildcard "/wp-*"` 或 `eq "/xmlrpc.php"` | `wp-admin`, `wp-login.php`, `wp-content`, `xmlrpc.php` |

建立後可在 Dashboard → **Security → WAF → Firewall rules** 看到並管理。

---

## 心得

整個流程用對話完成，省掉了翻文件和手動點 Dashboard 的時間。最有價值的部分是 Claude 幫忙即時查 Cloudflare 文件確認 Free 方案支援的 operator，避免我寫出跑不動的 regex 規則。

唯一要注意的是 **API Token 的安全管理**：建立用完即可刪除，不要讓 token 長期存在。Cloudflare Dashboard 的 API Tokens 頁面可以隨時撤銷。
