Skip to content

Configuration Keys

Every key the code reads, in one place. This page answers "what was that key called again" — press Cmd+F and search it.

For what a setting means and why you would change it, follow the link in the last column. Nothing here explains anything; that is deliberate.

The single most common mistake

FileStorage reads storage_file. FileRateLimitStorage reads file. They are different keys for the same idea, and getting it wrong does not error — the backend falls back to a hashed filename in the system temp directory, so the firewall appears to work while keeping its block list somewhere you did not choose and may lose on reboot.

Top level

Key Type What it holds
configs list Other files to merge in — paths, globs, URLs, {config_dir} / {presets_dir} tokens. Loading & Includes
global map Site-wide behaviour. Table below
storage map Where blocks are persisted. Table below
logger list Monolog handlers. Logging
challenge map Challenge flow settings. Table below
tarpit map max_concurrent (default 5) and max_seconds (default 30) — see Tarpit
plugins list The rules. Table below

A configs: entry naming a file that does not exist empties the whole document

A missing include is a load failure, not a skipped line — every rule stops being configured. global.require_config: true turns that into a startup exception instead.

global:

Key Type Default
mode string block block, log, exception, disabled, lockdown Mode
panic_file string unset A file that overrides mode when it exists Panic Switch
banning_status_code int 400 Status sent when a rule blocks Status Code
banning_message string built-in Body template; {{request.id}} is substituted Banning Message
repeat_offender_status int 0 Status for a client already on the block list Global
add_to_expire int 3600 Seconds added to a ban on each repeat hit Global
blocking_escalation list [] Window/offense/duration rules that lengthen bans Multiple Offenses
behind_proxy bool unset Assert whether a proxy sits in front Trusted Proxies
require_trusted_proxies bool false Refuse to start without setTrustedProxies() Trusted Proxies
require_config bool false Refuse to start if any config input failed to load Loading
lockdown bool false Refuse everyone but lockdown_allow Lockdown
lockdown_allow list (empty) Addresses and CIDRs still served. Empty serves nobody Lockdown
lockdown_status int 503 Lockdown
lockdown_retry_after int 300 Seconds in Retry-After; 0 omits it Lockdown
lockdown_message string built-in Supports {{request.id}} Lockdown
stale_source_error_after int 0 (off) Seconds before an unrefreshed source is an error Stale Rule Sources

storage:

Key Type
type class FileStorage, DatabaseStorage, RedisStorage, InMemoryStorage
config map Backend-specific, below
Backend config keys
FileStorage storage_file, offense_file Paths; relative resolves against the YAML file
DatabaseStorage connection, storage_table, offenses_table, schema_check_probability Storage
RedisStorage redis, instance Requires ext-redis

Every block-list backend also accepts record_request, which decides what a block record keeps of the visitor's cookies, headers, query and body. It defaults to an allowlist rather than everything. | InMemoryStorage | — | Per-process; nothing survives the request | | SharedStorage | shared, local | A fleet-wide list with a local copy underneath. Each is a {type, config} block — Storage |

Rate-limit counters are stored separately, under the RateLimit plugin's own metadata:

Backend config keys
FileRateLimitStorage file
DatabaseRateLimitStorage connection, schema_check_probability
RedisRateLimitStorage redis, instance, ttl
CacheRateLimitStorage adaptor, args, ttl
InMemoryRateLimitStorage

challenge:

Key Type Default
provider string required math, altcha, turnstile, recaptcha, or a FQCN Challenges
secret string required HMAC key for pass tokens. Startup fails if empty Challenges
path string /_firewall/challenge The path a submission is recognised at, matched against getPathInfo() Add a Challenge
submit_url string path, prefixed with the request's base path Where the interstitial's form POSTs to. Only set it if a proxy rewrites paths Add a Challenge
cookie_name string '' Pass-token cookie; empty disables cookie delivery Challenges
header_name string '' Header an SPA can send the token in Challenges
ttl int 3600 How long a pass lasts: the default for rules naming none, and the ceiling for every rule and every submission How long a pass lasts
audience string provider name aud claim, to scope tokens between instances Scoping tokens
passes_valid_from int or date unset Refuse every pass issued before this moment. One value, no storage Withdrawing a pass
revocable bool false Consult the per-nonce revocation list, at one storage read per valid pass Withdrawing a pass
provider_options map [] Per-provider settings, keyed by provider name Challenges

plugins: — one entry

Key Type Default
plugin class required The rule class
response string block allow, block, challenge, record, redirect, mark, tarpit — decides the bucket, and buckets beat weights
weight int 0 Order within its bucket; lower runs first
enable bool true
metadata map [] How the rule behaves. Below
config list [] The rule's own entries — addresses, paths, patterns

metadata: — common to every plugin

Key Type Default
name string class name What the log calls it. Name every rule Plugins
mode string enforce log observes this one rule without enforcing it Observe mode
status_code int banning_status_code Per-rule override Status Code
default_expiration_time int challenge.ttl on a challenge rule, else 3600 Ban length, or pass-token TTL. On a challenge rule it is capped by challenge.ttl Global
record bool true false refuses without writing to the block list. On a redirect rule the default is false and true opts in Evaluation Order
mark_as string the rule's name The signal response: mark raises, so several rules can raise one
mark_header string Also set this header on the request when marking
redirect_to string Required by response: redirect. Never built from the request, so it cannot become an open redirect
redirect_status int 302 301, 302, 307 or 308
default_key list [client_ip, rule_pattern] What rate limits count by, for rules declaring no key:
active map unset timezone (default UTC), days, hours, from, until — when this rule is awake Time Windows
sources list [] Pull this rule's entries from elsewhere Rule Sources
challenge_provider string challenge.provider Per-rule provider override Per-plugin providers
tarpit_seconds int Required by response: tarpit. Capped by tarpit.max_seconds Tarpit
config list Legacy alias for the entry's config: Legacy format

Identity-verifying plugins (User Agent, and any implementing IdentityVerificationInterface) add verify, verify_cache, verify_ttl, verify_negative_ttl, verify_suffixes, verify_claim_wait_ms and verify_slow_threshold_ms — see User Agent.

Every sources: option is its own table in Rule Sources, including allow_catch_all, which decides whether a source may contribute an entry matching every address, max_size / max_entries, which bound how much a refresh may bring in, and checksum / signature, which decide whether the fetched bytes are checked against what the publisher asserted.

metadata: — edge signal rules

EdgeSignal reads what a CDN decided. See Edge Signals.

Key Type Default
provider string custom cloudflare, fastly, custom
headers map [] Signal to header name; layers over the profile

Signals: bot_score, verified_bot, ja3, ja4.

config: — reputation rules

Reputation and AbuseIpdb take a map rather than a rule list. See Reputation.

Key Type Default
provider string http (abuseipdb on AbuseIpdb) abuseipdb, http, or a class implementing ReputationProviderInterface
threshold float 75 Score at or above which the rule matches, on the provider's scale
cache_ttl int provider's How long a verdict is reused
error_cache_ttl int provider's How long a failed lookup is remembered
cache_dir string temp dir Where verdicts are cached
on_error string fail_open fail_open, last_known_good
subject string client_ip What to score: client_ip, post.*, header.*, query.*, cookie.*
subject_hash string unset Send a digest of the subject instead of the value, e.g. sha256
block_status int 403 Status returned when the rule blocks
block_duration int 3600 How long the address is remembered
api_key string unset abuseipdb: required, or the rule is inert
max_age_in_days int 30 abuseipdb: how far back reports count
when list unset Conditions gating the lookup — same syntax as any rule
upstream string or map required http: the endpoint, as a source declares one. Must contain {ip}
format string json http: json, txt, csv, tsv, ndjson, yaml, xml
score_path string http: dot path to the score in the decoded body
score_pattern string http: or a regex with one capturing group, read from the raw body
trusted_path string unset http: dot path to an "allow this one" flag
trusted_pattern string unset http: or a regex for the same
content_type string application/json http: sent with an upstream.body
provider_name string see docs http: what log lines call the service
public_only bool true http: false also looks up private addresses
timeout float 2.0 Seconds to wait before giving up

PHP constants

Set before Firewall::create(). These exist because they must be readable before any YAML is parsed.

Constant Default
KANOPI_FIREWALL_CACHE_DIR system temp Where compiled config and source caches are written
KANOPI_FIREWALL_CACHE_TTL 3600 Default rule-source TTL, when a source names none
KANOPI_FIREWALL_CACHE_MAX_AGE 30 days Compiled-config entries older than this are swept; 0 disables
KANOPI_FIREWALL_CACHE_MAX_STALE How long a stale cached source may still be served
KANOPI_FIREWALL_CACHE_TIMEOUT Fetch timeout for remote sources
KANOPI_FIREWALL_REQUIRE_CONFIG false Same as global.require_config
KANOPI_FIREWALL_SOURCES_OFFLINE false Never fetch on the request path

Environment Variables covers %env(...)% substitution, which works in any value above.