Configuration
Configuration
Learn about the JSON configuration file format, rules, conditions, and actions.
Vercel Doorman uses a JSON configuration file to define your firewall rules. The configuration is validated using JSON Schema and provides full TypeScript support.
Schema URL
Add the schema reference to your config file for editor autocompletion and validation:
json
{
"$schema": "https://doorman.griffen.codes/schema.json"
}Basic Structure
Vercel Configuration
json
{
"$schema": "https://doorman.griffen.codes/schema.json",
"projectId": "prj_abc123",
"teamId": "team_xyz789",
"rules": [],
"ips": []
}Cloudflare Configuration
json
{
"$schema": "https://doorman.griffen.codes/schema.json",
"provider": "cloudflare",
"providers": {
"cloudflare": {
"zoneId": "zone_abc123",
"accountId": "acc_xyz789"
}
},
"rules": [],
"ips": []
}Multi-Provider Configuration
json
{
"$schema": "https://doorman.griffen.codes/schema.json",
"provider": "cloudflare",
"providers": {
"vercel": {
"projectId": "prj_abc123",
"teamId": "team_xyz789"
},
"cloudflare": {
"zoneId": "zone_abc123",
"accountId": "acc_xyz789"
}
},
"rules": [],
"ips": []
}Root Properties
| Property | Type | Required | Description |
|---|---|---|---|
$schema | string | No | JSON Schema URL for validation |
provider | string | No | Default provider ("vercel" or "cloudflare") |
projectId | string | Vercel Only | Vercel project ID |
teamId | string | Vercel Only | Vercel team ID (optional) |
providers | object | Multi-Provider | Provider-specific configurations |
rules | array | Yes | Array of firewall rules |
ips | array | No | Array of IP blocking rules |
version | number | No | Configuration version |
firewallEnabled | boolean | No | Enable/disable firewall |
Rules
Rule Structure
json
{
"id": "rule_block_bots",
"name": "Block Bad Bots",
"description": "Block malicious bots and crawlers",
"active": true,
"conditionGroup": [
{
"conditions": [
{
"type": "user_agent",
"op": "sub",
"value": "bot",
"neg": false
}
]
}
],
"action": {
"mitigate": {
"action": "deny"
}
}
}Rule Properties
| Property | Type | Required | Description |
|---|---|---|---|
id | string | No | Unique rule identifier |
name | string | Yes | Human-readable rule name |
description | string | No | Rule description |
active | boolean | Yes | Whether rule is enabled |
conditionGroup | array | Yes | Array of condition groups (OR logic) |
action | object | Yes | Action to take when rule matches |
Condition Groups
Condition groups use OR logic between groups and AND logic within groups:
json
{
"conditionGroup": [
{
"conditions": [
{ "type": "path", "op": "pre", "value": "/admin" },
{ "type": "method", "op": "eq", "value": "POST" }
]
},
{
"conditions": [
{ "type": "ip_address", "op": "eq", "value": "192.168.1.1" }
]
}
]
}This translates to: (path starts with "/admin" AND method equals "POST") OR (IP equals "192.168.1.1")
Condition Types
| Type | Description | Vercel | Cloudflare |
|---|---|---|---|
host | Hostname | ✅ | ✅ |
path | URL path | ✅ | ✅ |
method | HTTP method | ✅ | ✅ |
header | HTTP header | ✅ | ✅ |
query | Query parameter | ✅ | ✅ |
cookie | Cookie value | ✅ | ✅ |
user_agent | User agent string | ✅ | ✅ |
ip_address | IP address | ✅ | ✅ |
geo_country | Country code | ✅ | ✅ |
geo_continent | Continent code | ✅ | ✅ |
geo_city | City name | ✅ | ✅ |
protocol | Protocol | ✅ | ✅ |
scheme | URL scheme | ✅ | ✅ |
environment | Deployment environment | ✅ | ❌ |
region | Vercel region | ✅ | ❌ |
Operators
| Operator | Description | Vercel | Cloudflare |
|---|---|---|---|
eq | Equals | ✅ | ✅ |
pre | Starts with | ✅ | ✅ |
suf | Ends with | ✅ | ✅ |
sub | Contains | ✅ | ✅ |
inc | Is any of (array) | ✅ | ✅ |
re | Regex match | ✅ | ⚠️ Enterprise |
ex | Exists | ✅ | ✅ |
nex | Does not exist | ✅ | ✅ |
Actions
| Action | Description | Vercel | Cloudflare |
|---|---|---|---|
log | Log only | ✅ | ✅ |
deny | Block request | ✅ | ✅ |
allow | Allow request | ✅ | ✅ |
challenge | CAPTCHA challenge | ✅ | ✅ |
bypass | Skip other rules | ✅ | ✅ |
rate_limit | Rate limiting | ✅ | ✅ |
redirect | HTTP redirect | ✅ | ✅ |
Rate Limiting
json
{
"action": {
"mitigate": {
"action": "rate_limit",
"rateLimit": {
"requests": 100,
"window": "60s"
}
}
}
}Redirect
json
{
"action": {
"mitigate": {
"action": "redirect",
"redirect": {
"location": "https://example.com/blocked",
"permanent": false
}
}
}
}IP Blocking Rules
json
{
"ips": [
{
"id": "ip_block_suspicious",
"ip": "192.168.1.100/32",
"hostname": "suspicious-host",
"action": "deny",
"notes": "Blocked due to suspicious activity"
}
]
}| Property | Type | Required | Description |
|---|---|---|---|
ip | string | Yes | IP address or CIDR range |
hostname | string | No | Hostname for documentation |
action | string | Yes | Action (currently only "deny") |
notes | string | No | Notes about the block |
Environment Variables
Vercel
bash
VERCEL_TOKEN="your_vercel_token"
VERCEL_PROJECT_ID="prj_abc123"
VERCEL_TEAM_ID="team_xyz789"Cloudflare
bash
CLOUDFLARE_API_TOKEN="your_api_token"
CLOUDFLARE_ZONE_ID="zone_abc123"
CLOUDFLARE_ACCOUNT_ID="acc_xyz789"Provider Selection
bash
DOORMAN_PROVIDER="cloudflare" # or "vercel"Best Practices
- Use descriptive names for rules and IPs
- Add descriptions to explain rule purposes
- Group related conditions logically
- Use CIDR notation for IP ranges
- Order rules by frequency (most common first)
- Test rules in staging before production
- Start with log actions before blocking
- Keep backups of working configurations
Related Pages
- Getting Started — Quick setup guide
- Commands Overview — CLI command reference
- Examples — Real-world configuration examples
This content is sourced from the GitHub Wiki.