Files
smallwebwaf/docs/settings.md
sneak 1dbe17e594
check / check (push) Waiting to run
README rewritten from scratch so a newcomer can follow it (closes #154, closes #155)
The old README opened with project history and one list of a hundred
settings. The new one leads with what smallwebwaf is, what it protects
against, how to build and deploy it, what happens to a request, the
settings most deployments touch, how to check it works, the entrypoints,
the rationale and the design, as REPO_POLICIES.md requires. The reference
lists, every setting, the rule file format, the endpoints, the request
log's fields, the alert events, the metrics, the state files, the image
and the gitea notes, move to files under docs/, each linked from the
README, with SPEC.md as the one place for behaviour. Every statement was
checked against the code on next.

Model: fable-5-1
2026-10-22 22:29:53 +00:00

16 KiB

Settings

Every setting, its default and the values it takes, in the groups of "Settings" in SPEC.md. That section gives the conventions, the settings that take off, the _FILE form, and what each group does and why.

Forms of values

  • A duration is Go's syntax, with d for days: 90s, 15m, 24h, 7d. Zero and negative durations are refused.
  • A size is a number of bytes with an optional K, M or G, which are powers of 1024, so 1K is 1024 bytes. Examples: 512K, 100M, 5G.
  • A count is a whole number of requests, such as 1000.
  • A list is comma separated, with spaces around items ignored. An empty item is refused.
  • A netblock is an address and a prefix length, such as 10.0.0.0/8. A bare address stands for itself alone.
  • A country is a two-letter code of ISO 3166-1, in either case: de and DE are the same. xk stands for Kosovo. A code that is not a country is refused, such as nk (North Korea is kp) or the withdrawn su.
  • An AS number is AS and the number, in either case, such as AS64496.
  • A percentage is a whole number from 0 to 100.
  • A path prefix starts with /, such as /assets/.

Core

  • SWWAF_UPSTREAM_URL (default http://127.0.0.1:8081): the app. An http or https URL with a host and an optional port, and nothing more.
  • SWWAF_LISTEN_ADDR (default :8080): where smallwebwaf listens: : and a port, such as :9000. Leave the host out (see "Ports" in SPEC.md).
  • SWWAF_INSTANCE_NAME (default: the container's host name): the instance name in every log line, alert and metric, such as fsn1app1/gitea. Valid UTF-8. No control character while SWWAF_ALERT_NTFY_URL is set. 1 to 48 printable ASCII characters without a space while SWWAF_LOG_REMOTE_URL is set and SWWAF_LOG_REMOTE_APP_NAME is not.
  • SWWAF_MODE (default enforce): enforce or observe.
  • SWWAF_TRUSTED_PROXIES (default 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16): the netblocks whose X-Forwarded-For is believed. Set but empty, it trusts nothing.
  • SWWAF_IPV6_GROUP_PREFIX (default 64): the prefix length of an IPv6 client's group, from 32 to 128.
  • SWWAF_MAX_TRACKED_CLIENTS (default 20000): the most clients kept, a whole number above zero.
  • SWWAF_MAX_BANS (default 5000): how many of its own bans smallwebwaf keeps, a whole number above zero.

Tokens

  • SWWAF_ADMIN_TOKEN (default unset): the token for the ban endpoints and /_smallwebwaf/clients/<ip>. At least 32 characters.
  • SWWAF_METRICS_TOKEN (default unset): the token for /_smallwebwaf/metrics. At least 32 characters.

State files

  • SWWAF_STATE_DIR (default /var/lib/smallwebwaf): the directory of the state files, an absolute path that exists and can be written.
  • SWWAF_STATE_WRITE_DELAY (default 10s): how long bans.json waits to be written after a ban is made, lifted or made permanent. A duration.
  • SWWAF_STATE_COUNTER_INTERVAL (default 15m): how often every state file is written. A duration.

Logging

  • SWWAF_LOG_LEVEL (default info): the least severe of smallwebwaf's own messages that are written: debug, info, warn or error.
  • SWWAF_LOG_REQUEST_HEADERS (default accept,accept-language,accept-encoding,content-type,origin,range): the request headers recorded in the log line, in either case. Host and Transfer-Encoding are refused; the host is the field host.
  • SWWAF_LOG_REMOTE_URL (default unset): a syslog server that also gets every line written to stdout: syslog+udp://, syslog+tcp:// or syslog+tls://, each with a host and a port and nothing more.
  • SWWAF_LOG_REMOTE_TLS_CA_FILE (default unset): a file of PEM certificates that a syslog+tls server's certificate must chain to, instead of the host's own. A file that cannot be read, or holds no certificate, is refused.
  • SWWAF_LOG_REMOTE_BUFFER (default 10000): the most lines held while they wait to be sent, a whole number above zero.
  • SWWAF_LOG_REMOTE_FACILITY (default local0): the syslog facility: kern, user, mail, daemon, auth, syslog, lpr, news, uucp, cron, authpriv, ftp, or local0 to local7.
  • SWWAF_LOG_REMOTE_APP_NAME (default: SWWAF_INSTANCE_NAME): the app name in each syslog record, 1 to 48 printable ASCII characters without a space.

Metrics

  • SWWAF_METRICS_TOP_N (default 50): how many AS numbers and how many countries get series of their own. A whole number above zero.

Static lists

  • SWWAF_ALLOW_NETS (default empty): netblocks you trust, such as your monitoring. Their clients are refused only for a size or time limit or a missing or wrong token.
  • SWWAF_RATE_LIMIT_EXEMPT_NETS (default empty): netblocks whose clients are exempt from rate limiting and the byte limits.
  • SWWAF_DENY_NETS (default empty): netblocks whose clients are always refused.

Request rate limits, per client

  • SWWAF_RATE_LIMIT_PER_MINUTE (default 1000), SWWAF_RATE_LIMIT_PER_HOUR (default 10000) and SWWAF_RATE_LIMIT_PER_DAY (default 50000): the most requests a client may make in each window. A count or off.
  • SWWAF_RATE_LIMIT_EXEMPT_PATHS (default empty): path prefixes exempt from rate limiting and the byte limits, such as /assets/.

Byte limits, per client

  • SWWAF_BYTES_LIMIT_PER_MINUTE (default 10G), SWWAF_BYTES_LIMIT_PER_HOUR (default 20G) and SWWAF_BYTES_LIMIT_PER_DAY (default 50G): the most bytes counted for a client in each window. A size or off.
  • SWWAF_BYTES_COUNT (default both): which body bytes the byte limits count: response, request or both.

Size and time limits

  • SWWAF_CLIENT_REQUEST_TIMEOUT (default 60s): how long a client may take to send its request line and headers, and then, from the end of the headers, its body. A duration or off.
  • SWWAF_CLIENT_REQUEST_HEADER_MAX_BYTES (default 32K): the largest request line and headers. A size over 4K; never off.
  • SWWAF_CLIENT_IDLE_TIMEOUT (default 120s): how long a kept-open connection may wait for its next request before it is closed. A duration or off.
  • SWWAF_CLIENT_RESPONSE_TIMEOUT (default 30m): how long the answer may take to reach the client, from the end of the request to the last byte. A duration or off.
  • SWWAF_UPSTREAM_REQUEST_TIMEOUT (default 60s): how long connecting to the app and sending it the whole request may take. A duration or off.
  • SWWAF_UPSTREAM_RESPONSE_TIMEOUT (default 30m): how long the app may take to send its whole answer. A duration or off.
  • SWWAF_REQUEST_MAX_BYTES (default 100M): the largest request body. A size or off.
  • SWWAF_RESPONSE_MAX_BYTES (default 5G): the largest response body. A size or off.

Lookup of AS number and country

  • SWWAF_LOOKUP_SOURCE (default geojs): geojs, file or off.
  • SWWAF_LOOKUP_DB_PATH (default empty): the IPinfo Lite database file, in its .mmdb form, for SWWAF_LOOKUP_SOURCE=file.
  • SWWAF_LOOKUP_TIMEOUT (default 1s): how long a request waits for its client's first answer from GeoJS, and how long a request to GeoJS may take. A duration; never off.
  • SWWAF_ADD_LOOKUP_HEADERS (default false): true passes the app the client's AS number in X-Client-ASN and its country in X-Client-Country.

Country lists

  • SWWAF_DENIED_COUNTRIES (default empty): countries whose clients are refused, such as cn,ru,kp.
  • SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES (default empty): when set, the only countries whose clients get through, such as us,de. A country on both lists stops the start.

Biased thresholds

  • SWWAF_ASN_LIMIT_PERCENT (default empty): a list of AS numbers, each with : and a percentage, such as AS14061:50,AS16276:50,AS45102:25. An AS number listed twice is refused.
  • SWWAF_COUNTRY_LIMIT_PERCENT (default empty): the same by country, such as cn:25,ru:50.
  • SWWAF_ASN_BYTES_PERCENT and SWWAF_COUNTRY_BYTES_PERCENT (default empty): the same, for the byte limits alone.
  • SWWAF_UNKNOWN_LIMIT_PERCENT (default 100): the percentage for a client the lookup cannot place.
  • SWWAF_ASN_LIMIT_PERCENT_URL (default unset): the http or https URL of a text file with one AS number and percentage on each line, such as AS64496:50. A URL that is also in SWWAF_BLOCKLIST_URLS is refused.

Attack detection

  • SWWAF_RULES_DIR (default /etc/smallwebwaf/rules.d): the directory of the rule files.
  • SWWAF_RULES_ENABLED (default true): false reads no rule file.
  • SWWAF_TRAP_PATHS (default empty): paths only scanners ask for, such as /wp-login.php,/xmlrpc.php. Each starts with / and holds no ?.
  • SWWAF_WAF_MODE (default block): off, detect or block.
  • SWWAF_WAF_PARANOIA_LEVEL (default 1): the Core Rule Set's paranoia level, from 1 to 4.
  • SWWAF_WAF_ANOMALY_THRESHOLD (default 5): the score at which a request is a match. A whole number above zero, or off.
  • SWWAF_WAF_DISABLED_RULES (default 920340,920420,920440,920640,930130,930140): the ids of Core Rule Set rules to switch off. Each a whole number above zero. An id from 900000 to 900999 is refused: those are the rules that set the Core Rule Set up, and smallwebwaf's own.
  • SWWAF_WAF_EXEMPT_PATHS (default empty): path prefixes the Core Rule Set does not inspect.
  • SWWAF_WAF_BODY_LIMIT (default off): off, or how much of a request body the Core Rule Set reads, a size of at most 1G.
  • SWWAF_ERROR_BURST_THRESHOLD (default 30): the most refusals of one client in a minute for a rule match, a trap path, a Core Rule Set match or a failed token check. A count or off.

Ban lengths, response and scope

  • SWWAF_BAN_RESPONSE (default 403): 403, 429 or close.
  • SWWAF_LIMIT_BAN_DURATION (default 1h): the ban for a first broken limit. A duration.
  • SWWAF_LIMIT_BAN_REPEAT_WINDOW (default 24h): the time after a ban ends within which breaking a limit again lengthens the next ban. A duration.
  • SWWAF_MAX_BAN_DURATION (default 7d): the longest ban for a broken limit; one that would be longer is permanent. A duration.
  • SWWAF_ATTACK_BAN_DURATION (default 7d): the ban for a first clear sign of attack. A duration.
  • SWWAF_BAN_SCOPE_V4_PREFIX (default 32): how much a ban on an IPv4 client covers: the prefix length of its netblock, from 0 to 32.

Reputation

  • SWWAF_BLOCKLIST_URLS (default empty): blocklists to fetch, such as https://www.spamhaus.org/drop/drop.txt. Each an http or https URL without a user or a fragment. A URL listed twice is refused.
  • SWWAF_BLOCKLIST_REFRESH (default 24h): how long a list waits after its last try before it is fetched again. A duration of 1h or more.
  • SWWAF_BLOCKLIST_ACTION (default deny): deny, limit:<percent> or log.
  • SWWAF_DNSBL_ZONES (default empty): the DNS blocklists to ask, such as dnsbl.dronebl.org. Each a DNS name of at most 189 characters. A Spamhaus zone carries its key, as in <key>.xbl.dq.spamhaus.net. A zone listed twice is refused, whatever its case or key.
  • SWWAF_DNSBL_RESOLVER (default unset): the resolver to ask the zones through, such as 192.0.2.53 or [2001:db8::53]:5353. An IP address with an optional port, 53 when none is given. Unset, the host's resolver is used.
  • SWWAF_ABUSEIPDB_KEY (default unset): the key of your AbuseIPDB account. A control character in it is refused.
  • SWWAF_ABUSEIPDB_MIN_SCORE (default 75): the least abuse confidence score, from 0 to 100, that is a hit.
  • SWWAF_ABUSEIPDB_DAILY_BUDGET (default 900): the most checks made in a day, a whole number above zero. AbuseIPDB's free accounts may make 1,000.
  • SWWAF_CROWDSEC_LAPI_URL (default unset): the local API of a CrowdSec engine you run, such as http://172.17.0.1:8080. An http or https URL without a user or a fragment; its decision list is at v1/decisions under it. Set without the key, it is refused. So is a decision list URL that is also in SWWAF_BLOCKLIST_URLS, or that is SWWAF_ASN_LIMIT_PERCENT_URL.
  • SWWAF_CROWDSEC_LAPI_KEY (default unset): the key the engine gave for smallwebwaf, as cscli bouncers add smallwebwaf prints it. Set without the URL, it is refused.
  • SWWAF_REPUTATION_ACTION (default limit:25): deny, limit:<percent> or log, for DNS blocklist and AbuseIPDB hits.
  • SWWAF_REPUTATION_CACHE_TTL (default 24h): how long a zone's verdict or AbuseIPDB's score is used. A duration.
  • SWWAF_REPUTATION_TIMEOUT (default 2s): how long a query to a zone or a check with AbuseIPDB may take. A duration.

Alerting

  • SWWAF_ALERT_WEBHOOK_URL (default unset): the webhook that receives each alert as a JSON object. An http or https URL without a user or a fragment.
  • SWWAF_ALERT_WEBHOOK_HEADERS (default empty): headers sent with each post, such as Authorization:Bearer 0123456789abcdef. A list of name, : and value. A value cannot hold a comma.
  • SWWAF_ALERT_SLACK_WEBHOOK_URL (default unset): the Slack incoming webhook that receives each alert as a message, checked as the webhook URL is.
  • SWWAF_ALERT_NTFY_URL (default unset): the ntfy topic that receives each alert, as the topic's full URL, such as https://ntfy.sh/my-alerts, checked as the webhook URL is.
  • SWWAF_ALERT_NTFY_TOKEN (default unset): an ntfy access token. A control character in it is refused.
  • SWWAF_ALERT_EVENTS (default ban,permanent_ban,waf_block,anomaly,reputation_hit,source_failure,file_error): the event types alerts are sent for, from those in alerts.md but summary. Any other name is refused.
  • SWWAF_ALERT_COOLDOWN (default 15m): how long after an alert is sent its repeats are held back. A duration or off.
  • SWWAF_ALERT_MAX_PER_HOUR (default 60): the most alerts sent in an hour. A whole number above zero, or off.

Anomaly thresholds

Each scope has four thresholds: the most requests and the most bytes counted in a minute and in an hour. Requests are counts, bytes are sizes. Each is off by default. The four thresholds per client are:

  • SWWAF_ANOMALY_CLIENT_REQUESTS_PER_MINUTE;
  • SWWAF_ANOMALY_CLIENT_REQUESTS_PER_HOUR;
  • SWWAF_ANOMALY_CLIENT_BYTES_PER_MINUTE;
  • SWWAF_ANOMALY_CLIENT_BYTES_PER_HOUR.

The other scopes' names have another prefix before the same four endings, such as REQUESTS_PER_MINUTE:

  • SWWAF_ANOMALY_NET_...: per netblock around a client. Two settings give the netblock's length:
    • SWWAF_ANOMALY_NET_V4_PREFIX (default 24, from 0 to 32) for an IPv4 client;
    • SWWAF_ANOMALY_NET_V6_PREFIX (default 48, from 0 to 128) for an IPv6 client.
  • SWWAF_ANOMALY_ASN_...: per AS number. Needs a lookup source.
  • SWWAF_ANOMALY_TOTAL_...: the whole service.
  • SWWAF_WATCH_...: each netblock in SWWAF_WATCH_NETS, as a whole. SWWAF_WATCH_NETS (default empty) is a list of name, = and netblock, such as office=203.0.113.0/24,scraper-x=198.51.100.0/22. An item without = or a name, or with a bad netblock, is refused. So is a name used twice.

Settings given as files

To give a token as a file, as "Tokens" under "Deployment" in SPEC.md describes, make the file on the host:

mkdir -p /srv/app/tokens
openssl rand -hex 32 > /srv/app/tokens/metrics
chown 65532:65532 /srv/app/tokens/metrics
chmod 0400 /srv/app/tokens/metrics

Then mount its directory into the container read-only, and name the file:

docker run \
    -v /srv/app/tokens:/etc/smallwebwaf/tokens:ro \
    -e SWWAF_METRICS_TOKEN_FILE=/etc/smallwebwaf/tokens/metrics \
    ...

Fixed limits

A few limits are fixed rather than settings:

  • at most 100,000 GeoJS answers are kept;
  • at most 100,000 DNS blocklist verdicts and 100,000 AbuseIPDB scores are kept;
  • at most 1,000 DNS blocklist queries are under way at once;
  • at most 20,000 anomaly counters are kept;
  • each alert destination's queue holds at most 1,000 alerts.