Read every setting through viper and rename the settings (closes #211)
check / check (push) Failing after 3m27s

Every setting of discriminator and rproxy is read through viper, in place
of the os.LookupEnv function Main passed down. NewViper turns AutomaticEnv
and AllowEmptyEnv on, so a setting that is set but empty reads as set. A
setting may also be given as a file, the _FILE form, which rproxy's
settings now have too; rproxy still writes nothing to disk.

The settings are renamed. Discriminator's take the prefix SWW_WAF_,
rproxy's take SWW_RPROXY_, and the shared SWW_COMMAND keeps SWW_. The Core
Rule Set's settings take SWW_WAF_CORE_RULE_SET_ rather than SWW_WAF_WAF_.
Every place a name appeared changed: the code, the viper keys, tests,
documents, examples, the README's settings table and the image files.

Model: deepseek-v4-pro
This commit is contained in:
sneak committed 2026-11-07 06:41:11 +00:00
1 parent beb503b233
commit 68da92f414
89 files changed
+2027 -1916

No files matched your search

+219 -213
View File
@@ -4,9 +4,9 @@ Every setting, its default and the values it takes, in the groups of "Settings"
in [`SPEC.md`](../SPEC.md). That section gives the conventions, the settings
that take `off`, the `_FILE` form, and what each group does and why.
The settings that start with `SWW_` are `discriminator`'s. Those that start with
`SWRP_` are `rproxy`'s, and are under "`rproxy`" below. `SWW_COMMAND` chooses
between the two (see "The image's command" below).
The settings that start with `SWW_WAF_` are `discriminator`'s. Those that start
with `SWW_RPROXY_` are `rproxy`'s, and are under "`rproxy`" below. `SWW_COMMAND`
chooses between the two (see "The image's command" below).
## Forms of values
@@ -28,251 +28,256 @@ between the two (see "The image's command" below).
## Core
- `SWW_LISTEN_ADDR` (default `:8080`): where `discriminator` listens: `:` and a
port, such as `:9000`. Leave the host out (see "Ports" in
- `SWW_WAF_LISTEN_ADDR` (default `:8080`): where `discriminator` listens: `:`
and a port, such as `:9000`. Leave the host out (see "Ports" in
[`SPEC.md`](../SPEC.md)).
- `SWW_INSTANCE_NAME` (default: the container's host name): the `instance` name
in each line `discriminator` logs, and in each alert and metric, such as
- `SWW_WAF_INSTANCE_NAME` (default: the container's host name): the `instance`
name in each line `discriminator` logs, and in each alert and metric, such as
`fsn1/discriminator`. Valid UTF-8. No control character while
`SWW_ALERT_NTFY_URL` is set. 1 to 48 printable ASCII characters without a
space while `SWW_LOG_REMOTE_URL` is set and `SWW_LOG_REMOTE_APP_NAME` is not.
- `SWW_MODE` (default `enforce`): `enforce` or `observe`.
- `SWW_IPV6_GROUP_PREFIX` (default `64`): the prefix length of an IPv6 client's
group, from 32 to 128.
- `SWW_MAX_TRACKED_CLIENTS` (default `20000`): the most clients kept, a whole
number above zero.
- `SWW_MAX_BANS` (default `5000`): how many of its own bans `discriminator`
`SWW_WAF_ALERT_NTFY_URL` is set. 1 to 48 printable ASCII characters without a
space while `SWW_WAF_LOG_REMOTE_URL` is set and `SWW_WAF_LOG_REMOTE_APP_NAME`
is not.
- `SWW_WAF_MODE` (default `enforce`): `enforce` or `observe`.
- `SWW_WAF_IPV6_GROUP_PREFIX` (default `64`): the prefix length of an IPv6
client's group, from 32 to 128.
- `SWW_WAF_MAX_TRACKED_CLIENTS` (default `20000`): the most clients kept, a
whole number above zero.
- `SWW_WAF_MAX_BANS` (default `5000`): how many of its own bans `discriminator`
keeps, a whole number above zero.
## Tokens
- `SWW_ADMIN_TOKEN` (default unset): the token for the ban endpoints and
- `SWW_WAF_ADMIN_TOKEN` (default unset): the token for the ban endpoints and
`/_sww/clients/<ip>`. At least 32 characters.
- `SWW_METRICS_TOKEN` (default unset): the token for `/_sww/metrics`. At least
32 characters.
- `SWW_WAF_METRICS_TOKEN` (default unset): the token for `/_sww/metrics`. At
least 32 characters.
## State files
- `SWW_STATE_DIR` (default `/var/lib/sww`): the directory of the state files, an
absolute path that exists and can be written.
- `SWW_STATE_WRITE_DELAY` (default `10s`): how long `bans.json` waits to be
- `SWW_WAF_STATE_DIR` (default `/var/lib/sww`): the directory of the state
files, an absolute path that exists and can be written.
- `SWW_WAF_STATE_WRITE_DELAY` (default `10s`): how long `bans.json` waits to be
written after a ban is made, lifted or made permanent. A duration.
- `SWW_STATE_COUNTER_INTERVAL` (default `15m`): how often every state file is
written. A duration.
- `SWW_WAF_STATE_COUNTER_INTERVAL` (default `15m`): how often every state file
is written. A duration.
## Logging
- `SWW_LOG_LEVEL` (default `info`): the least severe of `discriminator`'s own
messages that are written: `debug`, `info`, `warn` or `error`.
- `SWW_LOG_REQUEST_HEADERS` (default
- `SWW_WAF_LOG_LEVEL` (default `info`): the least severe of `discriminator`'s
own messages that are written: `debug`, `info`, `warn` or `error`.
- `SWW_WAF_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`.
- `SWW_LOG_REMOTE_URL` (default unset): a syslog server that also gets every
- `SWW_WAF_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.
- `SWW_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.
- `SWW_LOG_REMOTE_BUFFER` (default `10000`): the most lines held while they wait
to be sent, a whole number above zero.
- `SWW_LOG_REMOTE_FACILITY` (default `local0`): the syslog facility: `kern`,
- `SWW_WAF_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.
- `SWW_WAF_LOG_REMOTE_BUFFER` (default `10000`): the most lines held while they
wait to be sent, a whole number above zero.
- `SWW_WAF_LOG_REMOTE_FACILITY` (default `local0`): the syslog facility: `kern`,
`user`, `mail`, `daemon`, `auth`, `syslog`, `lpr`, `news`, `uucp`, `cron`,
`authpriv`, `ftp`, or `local0` to `local7`.
- `SWW_LOG_REMOTE_APP_NAME` (default: `SWW_INSTANCE_NAME`): the app name in each
syslog record, 1 to 48 printable ASCII characters without a space.
- `SWW_WAF_LOG_REMOTE_APP_NAME` (default: `SWW_WAF_INSTANCE_NAME`): the app name
in each syslog record, 1 to 48 printable ASCII characters without a space.
## Metrics
- `SWW_METRICS_TOP_N` (default `50`): how many AS numbers and how many countries
get series of their own. A whole number above zero.
- `SWW_WAF_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
- `SWW_ALLOW_NETS` (default empty): netblocks you trust, such as your monitoring
(see step 3 in [`SPEC.md`](../SPEC.md)).
- `SWW_RATE_LIMIT_EXEMPT_NETS` (default empty): netblocks whose clients are
- `SWW_WAF_ALLOW_NETS` (default empty): netblocks you trust, such as your
monitoring (see step 3 in [`SPEC.md`](../SPEC.md)).
- `SWW_WAF_RATE_LIMIT_EXEMPT_NETS` (default empty): netblocks whose clients are
exempt from rate limiting and the byte limits.
- `SWW_DENY_NETS` (default empty): netblocks whose clients are refused (see step
3 in [`SPEC.md`](../SPEC.md)).
- `SWW_WAF_DENY_NETS` (default empty): netblocks whose clients are refused (see
step 3 in [`SPEC.md`](../SPEC.md)).
## Request rate limits, per client
- `SWW_RATE_LIMIT_PER_MINUTE` (default `120`, 2 a second): the most requests a
client may make in a minute. A count or `off`. The default leaves room for a
- `SWW_WAF_RATE_LIMIT_PER_MINUTE` (default `120`, 2 a second): the most requests
a client may make in a minute. A count or `off`. The default leaves room for a
person opening two pages at once with an empty cache, up to 60 files each.
- `SWW_RATE_LIMIT_PER_HOUR` (default `1500`): the most requests a client may
- `SWW_WAF_RATE_LIMIT_PER_HOUR` (default `1500`): the most requests a client may
make in an hour. A count or `off`. It is the main limit against scrapers. A
person reading a site for an hour, a page every 20 seconds, makes about 900. A
scraper making one request every 2 seconds makes 1,800 an hour, more than the
limit.
- `SWW_RATE_LIMIT_PER_DAY` (default `6000`): the most requests a client may make
in a day. A count or `off`. The default is four hours at the hour limit. A
scraper making one request every 10 seconds makes 8,640 a day, more than the
- `SWW_WAF_RATE_LIMIT_PER_DAY` (default `6000`): the most requests a client may
make in a day. A count or `off`. The default is four hours at the hour limit.
A scraper making one request every 10 seconds makes 8,640 a day, more than the
limit.
- A CI runner asks its code forge for work all day and can pass the limits. Put
the runners' addresses in `SWW_RATE_LIMIT_EXEMPT_NETS`. Do the same for a
the runners' addresses in `SWW_WAF_RATE_LIMIT_EXEMPT_NETS`. Do the same for a
network where many people share one address, such as an office.
- Counting cannot catch a client that stays under all three limits (see "Request
rate limits, per client" in [`SPEC.md`](../SPEC.md)).
- `SWW_RATE_LIMIT_EXEMPT_PATHS` (default empty): path prefixes exempt from rate
limiting and the byte limits, such as `/assets/`.
- `SWW_WAF_RATE_LIMIT_EXEMPT_PATHS` (default empty): path prefixes exempt from
rate limiting and the byte limits, such as `/assets/`.
## Byte limits, per client
- `SWW_BYTES_LIMIT_PER_MINUTE` (default `off`), `SWW_BYTES_LIMIT_PER_HOUR`
(default `50G`) and `SWW_BYTES_LIMIT_PER_DAY` (default `100G`): the most bytes
counted for a client in each window. A size or `off`.
- `SWW_BYTES_COUNT` (default `both`): which body bytes the byte limits count:
`response`, `request` or `both`.
- `SWW_WAF_BYTES_LIMIT_PER_MINUTE` (default `off`),
`SWW_WAF_BYTES_LIMIT_PER_HOUR` (default `50G`) and
`SWW_WAF_BYTES_LIMIT_PER_DAY` (default `100G`): the most bytes counted for a
client in each window. A size or `off`.
- `SWW_WAF_BYTES_COUNT` (default `both`): which body bytes the byte limits
count: `response`, `request` or `both`.
## Lookup of AS number and country
- `SWW_LOOKUP_SOURCE` (default `geojs`): `geojs`, `file` or `off`. `off` stops
the start while a setting that needs a lookup is set:
- `SWW_WAF_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;
- `SWW_ADD_LOOKUP_HEADERS`;
- the four biased threshold lists and `SWW_ASN_LIMIT_PERCENT_URL`;
- `SWW_UNKNOWN_LIMIT_PERCENT` below `100`;
- `SWW_WAF_ADD_LOOKUP_HEADERS`;
- the four biased threshold lists and `SWW_WAF_ASN_LIMIT_PERCENT_URL`;
- `SWW_WAF_UNKNOWN_LIMIT_PERCENT` below `100`;
- an anomaly threshold per AS number.
- `SWW_LOOKUP_DB_PATH` (default empty): the IPinfo Lite database file, in its
`.mmdb` form, for `SWW_LOOKUP_SOURCE=file`.
- `SWW_LOOKUP_TIMEOUT` (default `800ms`): how long a request waits for its
- `SWW_WAF_LOOKUP_DB_PATH` (default empty): the IPinfo Lite database file, in
its `.mmdb` form, for `SWW_WAF_LOOKUP_SOURCE=file`.
- `SWW_WAF_LOOKUP_TIMEOUT` (default `800ms`): 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`.
- `SWW_ADD_LOOKUP_HEADERS` (default `false`): `true` has `rproxy` pass the app
the client's AS number in `X-Client-ASN` and its country in
- `SWW_WAF_ADD_LOOKUP_HEADERS` (default `false`): `true` has `rproxy` pass the
app the client's AS number in `X-Client-ASN` and its country in
`X-Client-Country`.
## Country lists
- `SWW_DENIED_COUNTRIES` (default empty): countries whose clients are refused,
such as `cn,ru,kp`.
- `SWW_EXCLUSIVELY_ALLOWED_COUNTRIES` (default empty): when set, the only
- `SWW_WAF_DENIED_COUNTRIES` (default empty): countries whose clients are
refused, such as `cn,ru,kp`.
- `SWW_WAF_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
- `SWW_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
- `SWW_WAF_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.
- `SWW_COUNTRY_LIMIT_PERCENT` (default empty): the same by country, such as
- `SWW_WAF_COUNTRY_LIMIT_PERCENT` (default empty): the same by country, such as
`cn:25,ru:50`.
- `SWW_ASN_BYTES_PERCENT` and `SWW_COUNTRY_BYTES_PERCENT` (default empty): the
same, for the byte limits alone.
- `SWW_UNKNOWN_LIMIT_PERCENT` (default `100`): the percentage for a client the
lookup cannot place.
- `SWW_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 `SWW_BLOCKLIST_URLS` is refused.
- `SWW_WAF_ASN_BYTES_PERCENT` and `SWW_WAF_COUNTRY_BYTES_PERCENT` (default
empty): the same, for the byte limits alone.
- `SWW_WAF_UNKNOWN_LIMIT_PERCENT` (default `100`): the percentage for a client
the lookup cannot place.
- `SWW_WAF_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 `SWW_WAF_BLOCKLIST_URLS` is refused.
## Attack detection
- `SWW_RULES_DIR` (default `/etc/sww/rules.d`): the directory of the rule files.
- `SWW_RULES_ENABLED` (default `true`): `false` reads no rule file.
- `SWW_TRAP_PATHS` (default empty): paths only scanners ask for, such as
- `SWW_WAF_RULES_DIR` (default `/etc/sww/rules.d`): the directory of the rule
files.
- `SWW_WAF_RULES_ENABLED` (default `true`): `false` reads no rule file.
- `SWW_WAF_TRAP_PATHS` (default empty): paths only scanners ask for, such as
`/wp-login.php,/xmlrpc.php`. Each starts with `/` and holds no `?`.
- `SWW_WAF_MODE` (default `block`): `off`, `detect` or `block`.
- `SWW_WAF_PARANOIA_LEVEL` (default `1`): the Core Rule Set's paranoia level,
from 1 to 4.
- `SWW_WAF_ANOMALY_THRESHOLD` (default `5`): the score at which a request is a
match. A whole number above zero, or `off`.
- `SWW_WAF_DISABLED_RULES` (default
- `SWW_WAF_CORE_RULE_SET_MODE` (default `block`): `off`, `detect` or `block`.
- `SWW_WAF_CORE_RULE_SET_PARANOIA_LEVEL` (default `1`): the Core Rule Set's
paranoia level, from 1 to 4.
- `SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD` (default `5`): the score at which a
request is a match. A whole number above zero, or `off`.
- `SWW_WAF_CORE_RULE_SET_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.
- `SWW_WAF_EXEMPT_PATHS` (default empty): path prefixes the Core Rule Set does
not inspect.
- `SWW_WAF_BODY_LIMIT` (default `off`): `off`, or how much of a request body the
Core Rule Set reads, a size of at most `64K`. A question carries no more of a
body than 64 KiB, and the Core Rule Set reads at most 64 KiB less one byte of
it, whatever the value (see "The answer" in [`SPEC.md`](../SPEC.md)).
- `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` (default unset): a file of Core Rule Set
exclusions, written as Coraza directives. It is loaded before the Core Rule
Set's rules, so it holds only `SecAction` and `SecRule` lines that exclude
with `ctl:ruleRemoveTargetById` or `ctl:ruleRemoveById`. A file that cannot be
read or does not parse stops the start, whatever `SWW_WAF_MODE` is. So does a
file that names a number from 900000 to 900999 outside a comment, alone or in
a range. So does a directive that removes or changes rules as the file loads,
such as `SecRuleRemoveById`, since none of the Core Rule Set's rules is loaded
yet. It has no `_FILE` form.
- `SWW_ERROR_BURST_THRESHOLD` (default `30`): the most refusals of one client in
a minute (see "Attack detection" in `SPEC.md`). A count or `off`.
- `SWW_WAF_CORE_RULE_SET_EXEMPT_PATHS` (default empty): path prefixes the Core
Rule Set does not inspect.
- `SWW_WAF_CORE_RULE_SET_BODY_LIMIT` (default `off`): `off`, or how much of a
request body the Core Rule Set reads, a size of at most `64K`. A question
carries no more of a body than 64 KiB, and the Core Rule Set reads at most 64
KiB less one byte of it, whatever the value (see "The answer" in
[`SPEC.md`](../SPEC.md)).
- `SWW_WAF_CORE_RULE_SET_EXCLUSIONS_FILE` (default unset): a file of Core Rule
Set exclusions, written as Coraza directives. It is loaded before the Core
Rule Set's rules, so it holds only `SecAction` and `SecRule` lines that
exclude with `ctl:ruleRemoveTargetById` or `ctl:ruleRemoveById`. A file that
cannot be read or does not parse stops the start, whatever
`SWW_WAF_CORE_RULE_SET_MODE` is. So does a file that names a number from
900000 to 900999 outside a comment, alone or in a range. So does a directive
that removes or changes rules as the file loads, such as `SecRuleRemoveById`,
since none of the Core Rule Set's rules is loaded yet. It has no `_FILE` form.
- `SWW_WAF_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
- `SWW_BAN_RESPONSE` (default `403`): `403`, `429` or `close`.
- `SWW_LIMIT_BAN_DURATION` (default `1h`): the ban for a first broken limit. A
duration.
- `SWW_LIMIT_BAN_REPEAT_WINDOW` (default `24h`): the time after a ban ends
- `SWW_WAF_BAN_RESPONSE` (default `403`): `403`, `429` or `close`.
- `SWW_WAF_LIMIT_BAN_DURATION` (default `1h`): the ban for a first broken limit.
A duration.
- `SWW_WAF_LIMIT_BAN_REPEAT_WINDOW` (default `24h`): the time after a ban ends
within which breaking a limit again lengthens the next ban. A duration.
- `SWW_MAX_BAN_DURATION` (default `7d`): the longest ban for a broken limit; one
that would be longer is permanent. A duration.
- `SWW_ATTACK_BAN_DURATION` (default `7d`): the ban for a first clear sign of
attack. A duration.
- `SWW_BAN_SCOPE_V4_PREFIX` (default `32`): how much a ban on an IPv4 client
- `SWW_WAF_MAX_BAN_DURATION` (default `7d`): the longest ban for a broken limit;
one that would be longer is permanent. A duration.
- `SWW_WAF_ATTACK_BAN_DURATION` (default `7d`): the ban for a first clear sign
of attack. A duration.
- `SWW_WAF_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
- `SWW_BLOCKLIST_URLS` (default empty): blocklists to fetch, such as
- `SWW_WAF_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.
- `SWW_BLOCKLIST_REFRESH` (default `24h`): how long a list waits after its last
try before it is fetched again. A duration of `1h` or more.
- `SWW_BLOCKLIST_ACTION` (default `deny`): `deny`, `limit:<percent>` or `log`.
- `SWW_DNSBL_ZONES` (default empty): the DNS blocklists to ask, such as
- `SWW_WAF_BLOCKLIST_REFRESH` (default `24h`): how long a list waits after its
last try before it is fetched again. A duration of `1h` or more.
- `SWW_WAF_BLOCKLIST_ACTION` (default `deny`): `deny`, `limit:<percent>` or
`log`.
- `SWW_WAF_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.
- `SWW_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.
- `SWW_ABUSEIPDB_KEY` (default unset): the key of your AbuseIPDB account. A
- `SWW_WAF_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.
- `SWW_WAF_ABUSEIPDB_KEY` (default unset): the key of your AbuseIPDB account. A
control character in it is refused.
- `SWW_ABUSEIPDB_MIN_SCORE` (default `75`): the least abuse confidence score,
from 0 to 100, that is a hit.
- `SWW_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.
- `SWW_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
`SWW_BLOCKLIST_URLS`, or that is `SWW_ASN_LIMIT_PERCENT_URL`.
- `SWW_CROWDSEC_LAPI_KEY` (default unset): the key the engine gave for
- `SWW_WAF_ABUSEIPDB_MIN_SCORE` (default `75`): the least abuse confidence
score, from 0 to 100, that is a hit.
- `SWW_WAF_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.
- `SWW_WAF_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
`SWW_WAF_BLOCKLIST_URLS`, or that is `SWW_WAF_ASN_LIMIT_PERCENT_URL`.
- `SWW_WAF_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.
- `SWW_REPUTATION_ACTION` (default `limit:25`): `deny`, `limit:<percent>` or
- `SWW_WAF_REPUTATION_ACTION` (default `limit:25`): `deny`, `limit:<percent>` or
`log`, for DNS blocklist and AbuseIPDB hits.
- `SWW_REPUTATION_CACHE_TTL` (default `24h`): how long a zone's verdict or
- `SWW_WAF_REPUTATION_CACHE_TTL` (default `24h`): how long a zone's verdict or
AbuseIPDB's score is used. A duration.
- `SWW_REPUTATION_TIMEOUT` (default `2s`): how long a query to a zone or a check
with AbuseIPDB may take. A duration.
- `SWW_WAF_REPUTATION_TIMEOUT` (default `2s`): how long a query to a zone or a
check with AbuseIPDB may take. A duration.
## Alerting
- `SWW_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.
- `SWW_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.
- `SWW_ALERT_SLACK_WEBHOOK_URL` (default unset): the Slack incoming webhook that
receives each alert as a message, checked as the webhook URL is.
- `SWW_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.
- `SWW_ALERT_NTFY_TOKEN` (default unset): an ntfy access token. A control
- `SWW_WAF_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.
- `SWW_WAF_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.
- `SWW_WAF_ALERT_SLACK_WEBHOOK_URL` (default unset): the Slack incoming webhook
that receives each alert as a message, checked as the webhook URL is.
- `SWW_WAF_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.
- `SWW_WAF_ALERT_NTFY_TOKEN` (default unset): an ntfy access token. A control
character in it is refused.
- `SWW_ALERT_EVENTS` (default
- `SWW_WAF_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`](alerts.md)
but `summary`. Any other name is refused.
- `SWW_ALERT_COOLDOWN` (default `15m`): how long after an alert is sent its
- `SWW_WAF_ALERT_COOLDOWN` (default `15m`): how long after an alert is sent its
repeats are held back. A duration or `off`.
- `SWW_ALERT_MAX_PER_HOUR` (default `60`): the most alerts sent in an hour. A
whole number above zero, or `off`.
- `SWW_WAF_ALERT_MAX_PER_HOUR` (default `60`): the most alerts sent in an hour.
A whole number above zero, or `off`.
## Anomaly thresholds
@@ -280,25 +285,25 @@ 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:
- `SWW_ANOMALY_CLIENT_REQUESTS_PER_MINUTE`;
- `SWW_ANOMALY_CLIENT_REQUESTS_PER_HOUR`;
- `SWW_ANOMALY_CLIENT_BYTES_PER_MINUTE`;
- `SWW_ANOMALY_CLIENT_BYTES_PER_HOUR`.
- `SWW_WAF_ANOMALY_CLIENT_REQUESTS_PER_MINUTE`;
- `SWW_WAF_ANOMALY_CLIENT_REQUESTS_PER_HOUR`;
- `SWW_WAF_ANOMALY_CLIENT_BYTES_PER_MINUTE`;
- `SWW_WAF_ANOMALY_CLIENT_BYTES_PER_HOUR`.
The other scopes' names have another prefix before the same four endings, such
as `REQUESTS_PER_MINUTE`:
- `SWW_ANOMALY_NET_...`: per netblock around a client. Two settings give the
- `SWW_WAF_ANOMALY_NET_...`: per netblock around a client. Two settings give the
netblock's length:
- `SWW_ANOMALY_NET_V4_PREFIX` (default `24`, from 0 to 32) for an IPv4
- `SWW_WAF_ANOMALY_NET_V4_PREFIX` (default `24`, from 0 to 32) for an IPv4
client;
- `SWW_ANOMALY_NET_V6_PREFIX` (default `48`, from 0 to 128) for an IPv6
- `SWW_WAF_ANOMALY_NET_V6_PREFIX` (default `48`, from 0 to 128) for an IPv6
client.
- `SWW_ANOMALY_ASN_...`: per AS number.
- `SWW_ANOMALY_TOTAL_...`: the whole service.
- `SWW_WATCH_...`: each netblock in `SWW_WATCH_NETS`, as a whole.
`SWW_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
- `SWW_WAF_ANOMALY_ASN_...`: per AS number.
- `SWW_WAF_ANOMALY_TOTAL_...`: the whole service.
- `SWW_WAF_WATCH_...`: each netblock in `SWW_WAF_WATCH_NETS`, as a whole.
`SWW_WAF_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
@@ -319,7 +324,7 @@ Then mount its directory into the container read-only, and name the file:
docker run \
-v /srv/app/tokens:/etc/sww/tokens:ro \
-e SWW_COMMAND=discriminator \
-e SWW_METRICS_TOKEN_FILE=/etc/sww/tokens/metrics \
-e SWW_WAF_METRICS_TOKEN_FILE=/etc/sww/tokens/metrics \
...
```
@@ -343,51 +348,52 @@ A few limits are fixed rather than settings:
## `discriminator`'s answer and `rproxy`'s wait
`SWW_LOOKUP_TIMEOUT` is the longest a question waits on an outside source. Keep
it well under `rproxy`'s `SWRP_TIMEOUT_MS`, as the default is. No question waits
for `SWW_REPUTATION_TIMEOUT`, since the DNS blocklists and AbuseIPDB are asked
in the background (see "Answering in time" under "`discriminator`" in
[`SPEC.md`](../SPEC.md)).
`SWW_WAF_LOOKUP_TIMEOUT` is the longest a question waits on an outside source.
Keep it well under `rproxy`'s `SWW_RPROXY_TIMEOUT_MS`, as the default is. No
question waits for `SWW_WAF_REPUTATION_TIMEOUT`, since the DNS blocklists and
AbuseIPDB are asked in the background (see "Answering in time" under
"`discriminator`" in [`SPEC.md`](../SPEC.md)).
## `rproxy`
`sww rproxy` reads the settings below and no others. 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`](../SPEC.md) says what
they do.
start, and an invalid value stops the start. Any can be given as a file, as a
`SWW_WAF_` setting can. "`rproxy`" in [`SPEC.md`](../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): `discriminator`'s URL. An `http` or
`https` URL with a host and an optional port, and nothing more. `rproxy`
speaks HTTP/1.1 to it.
- `SWRP_TIMEOUT_MS` (default `2000`): how long `rproxy` waits for
- `SWW_RPROXY_WAF_BACKEND` (required, no default): `discriminator`'s URL. An
`http` or `https` URL with a host and an optional port, and nothing more.
`rproxy` speaks HTTP/1.1 to it.
- `SWW_RPROXY_TIMEOUT_MS` (default `2000`): how long `rproxy` waits for
`discriminator`'s answer, to a question and to a report. A time; never `off`.
- `SWRP_DEFAULT_DISPOSITION` (default `allow`): what is done with a request when
`discriminator` cannot be connected to, does not answer at all, or does not
answer within `SWRP_TIMEOUT_MS`. `allow` passes it to the app, and `deny`
answers `503`. It does not apply to an answer `discriminator` gives, such as
an error.
- `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. A client outside these netblocks cannot claim another address. Where
other containers reach `rproxy` directly, or visitors on a private network
reach traefik, they can name another address in the header. Narrowing the
setting to traefik's own network closes that gap.
- `SWW_RPROXY_DEFAULT_DISPOSITION` (default `allow`): what is done with a
request when `discriminator` cannot be connected to, does not answer at all,
or does not answer within `SWW_RPROXY_TIMEOUT_MS`. `allow` passes it to the
app, and `deny` answers `503`. It does not apply to an answer `discriminator`
gives, such as an error.
- `SWW_RPROXY_MAX_REQUEST_SIZE` (default `100M`): the largest request body. A
size or `off`.
- `SWW_RPROXY_MAX_RESPONSE_SIZE` (default `1G`): the largest response body. A
size or `off`.
- `SWW_RPROXY_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`.
- `SWW_RPROXY_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`.
- `SWW_RPROXY_LISTEN_ADDR` (default `:8080`): where `rproxy` listens, such as
`:9000`.
- `SWW_RPROXY_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.
- `SWW_RPROXY_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. A client
outside these netblocks cannot claim another address. Where other containers
reach `rproxy` directly, or visitors on a private network reach traefik, they
can name another address in the header. Narrowing the setting to traefik's own
network closes that gap.
## The image's command
@@ -399,14 +405,14 @@ check checks: `rproxy` or `discriminator` (see "Deployment" in
Nothing reads these names any more:
- `SWW_UPSTREAM_URL` is `SWRP_UPSTREAM_URL`.
- `SWW_TRUSTED_PROXIES` is `SWRP_TRUSTED_PROXIES`.
- `SWW_REQUEST_MAX_BYTES` is `SWRP_MAX_REQUEST_SIZE`.
- `SWW_RESPONSE_MAX_BYTES` is `SWRP_MAX_RESPONSE_SIZE`.
- `SWW_CLIENT_REQUEST_TIMEOUT` and `SWW_UPSTREAM_REQUEST_TIMEOUT` are
`SWRP_MAX_REQUEST_TIME_MS`, in milliseconds.
- `SWW_CLIENT_RESPONSE_TIMEOUT` and `SWW_UPSTREAM_RESPONSE_TIMEOUT` are
`SWRP_MAX_RESPONSE_TIME_MS`, in milliseconds.
- `SWW_CLIENT_IDLE_TIMEOUT` and `SWW_CLIENT_REQUEST_HEADER_MAX_BYTES` have no
setting. `rproxy` closes a kept-open connection idle for 120 seconds, and
takes a request line and headers of at most 32 KiB.
- `SWW_WAF_UPSTREAM_URL` is `SWW_RPROXY_UPSTREAM_URL`.
- `SWW_WAF_TRUSTED_PROXIES` is `SWW_RPROXY_TRUSTED_PROXIES`.
- `SWW_WAF_REQUEST_MAX_BYTES` is `SWW_RPROXY_MAX_REQUEST_SIZE`.
- `SWW_WAF_RESPONSE_MAX_BYTES` is `SWW_RPROXY_MAX_RESPONSE_SIZE`.
- `SWW_WAF_CLIENT_REQUEST_TIMEOUT` and `SWW_WAF_UPSTREAM_REQUEST_TIMEOUT` are
`SWW_RPROXY_MAX_REQUEST_TIME_MS`, in milliseconds.
- `SWW_WAF_CLIENT_RESPONSE_TIMEOUT` and `SWW_WAF_UPSTREAM_RESPONSE_TIMEOUT` are
`SWW_RPROXY_MAX_RESPONSE_TIME_MS`, in milliseconds.
- `SWW_WAF_CLIENT_IDLE_TIMEOUT` and `SWW_WAF_CLIENT_REQUEST_HEADER_MAX_BYTES`
have no setting. `rproxy` closes a kept-open connection idle for 120 seconds,
and takes a request line and headers of at most 32 KiB.