Files
smallwebwaf/docs/settings.md
T
sneak fbb5158377
check / check (push) Failing after 14m17s
rproxy, the proxy in front of each app, asks servewaf and fails open (closes #171)
`smallwebwaf rproxy` reads the first 64 KiB of each body, asks servewaf, and
passes what servewaf allows to the app within its own size and time limits.
It reports each request servewaf answered. SWRP_DEFAULT_DISPOSITION decides
when servewaf gives no answer.

Duplication: internal/rproxy copies passing-on code from internal/proxy until
#172 removes the originals.
Rule suppressed: gosec G704 on servewaf's URL, a setting.
Rule suppressed: gosec G705 on the answer written to the visitor.
Judgement call: the SWRP_ size and time limits take off; SWRP_TIMEOUT_MS does not.

Model: opus-5-5
2026-11-05 00:08:53 +00:00

19 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 (see step 3 in SPEC.md).
  • 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 refused (see step 3 in SPEC.md).

Request rate limits, per client

  • SWWAF_RATE_LIMIT_PER_MINUTE (default 500, about 8 a second): the most requests a client may make in a minute. A count or off. The default catches, within seconds, a client firing requests as fast as it can. It leaves room for a fleet of about 20 agents at its busiest, about 120 requests a minute. It also leaves room for a few quick first visits to gitea with an empty cache, about 40 files each.
  • SWWAF_RATE_LIMIT_PER_HOUR (default 20000, about 5.5 a second): the most requests a client may make in an hour. A count or off. The default leaves room for an automation fleet at work. It catches a client that keeps up more than about 5.5 a second for an hour.
  • SWWAF_RATE_LIMIT_PER_DAY (default 300000, about 3.5 a second): the most requests a client may make in a day. A count or off. The default catches a scraper that keeps up 4 a second around the clock.
  • Counting cannot catch a client that stays under all three limits (see "Request rate limits, per client" in SPEC.md).
  • 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 4G), SWWAF_BYTES_LIMIT_PER_HOUR (default 20G) and SWWAF_BYTES_LIMIT_PER_DAY (default 200G): 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 1G): the largest response body. A size or off.

Lookup of AS number and country

  • SWWAF_LOOKUP_SOURCE (default geojs): geojs, file or off. off stops the start while a setting that needs a lookup is set:
    • the two country lists;
    • SWWAF_ADD_LOOKUP_HEADERS;
    • the four biased threshold lists and SWWAF_ASN_LIMIT_PERCENT_URL;
    • SWWAF_UNKNOWN_LIMIT_PERCENT below 100;
    • an anomaly threshold per AS number.
  • 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 (see "Attack detection" in SPEC.md). 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.
  • 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;
  • servewaf holds at most 10,000 answered requests awaiting their reports;
  • rproxy takes a request line and headers of at most 32 KiB, closes a kept-open connection idle for 120 seconds, and reads at most 1 MiB of the body of servewaf's answer.

servewaf

smallwebwaf servewaf uses every setting here but these, which it ignores:

  • SWWAF_UPSTREAM_URL and SWWAF_TRUSTED_PROXIES;
  • the five timeouts under "Size and time limits";
  • SWWAF_CLIENT_REQUEST_HEADER_MAX_BYTES, SWWAF_REQUEST_MAX_BYTES and SWWAF_RESPONSE_MAX_BYTES.

An invalid value of one of these still stops the start, and the line of settings at start still shows them.

SWWAF_ADD_LOOKUP_HEADERS puts the headers on the answer to rproxy, not on a request to an app. SWWAF_WAF_BODY_LIMIT has an effect up to 64 KiB less one byte, whatever its value. A question carries no more of a body than 64 KiB (see "servewaf" in SPEC.md).

rproxy

smallwebwaf rproxy reads the settings below and no others, and nothing else reads them. They are read once at start, and an invalid value stops the start. None can be given as a file, since rproxy never touches disk. "rproxy" in SPEC.md says what they do.

A time here is a whole number of milliseconds above zero, such as 2000.

  • SWRP_WAF_BACKEND (required, no default): servewaf's URL. An http or https URL with a host and an optional port, and nothing more.
  • SWRP_TIMEOUT_MS (default 2000): how long rproxy waits for servewaf's answer, to a question and to a report. A time; never off.
  • SWRP_DEFAULT_DISPOSITION (default allow): what is done with a request servewaf gives no answer about. allow passes it to the app, and deny answers 503.
  • SWRP_MAX_REQUEST_SIZE (default 100M): the largest request body. A size or off.
  • SWRP_MAX_RESPONSE_SIZE (default 1G): the largest response body. A size or off.
  • SWRP_MAX_REQUEST_TIME_MS (default 60000): how long the visitor may take to send its request line and headers. It then also bounds, from the end of the headers, the time until the app has been sent the whole request. A time or off.
  • SWRP_MAX_RESPONSE_TIME_MS (default 1800000): how long the answer may take, from the end of the request to its last byte reaching the visitor. A time or off.
  • SWRP_LISTEN_ADDR (default :8080): where rproxy listens, such as :9000.
  • SWRP_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.
  • SWRP_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.