Seventh review: false statements fixed, README shortened to link the spec
check / check (push) Waiting to run

- Engine error handling dropped as not built; unknown country and AS
  number each on its own; observe mode makes no ban of its own.
- README no longer restates the request steps, the refusal answers or
  the design; its step list uses the spec's numbers.
- Repeats, misreadable sentences, late verbs and long sentences reworded
  as the review asks.

Model: fable-5-1
This commit is contained in:
2026-10-26 00:37:38 +00:00
parent a62909dbf4
commit 8282404453
3 changed files with 114 additions and 184 deletions
+55 -128
View File
@@ -8,8 +8,7 @@ scanners and other abusers before they reach the app.
A web application firewall reads each request on its way to a web app and
refuses the ones that look like abuse. `smallwebwaf` is also a reverse proxy: it
accepts requests on the app's behalf, passes them to the app, and passes the
app's answers back. A request it does not refuse reaches the app as it came,
apart from a few headers (see "Design" below).
app's answers back.
It needs no setting. Every setting has a default chosen for a service on the
open internet. [`SPEC.md`](SPEC.md) says how `smallwebwaf` behaves and why. The
@@ -30,8 +29,8 @@ reference documents under [`docs/`](docs/) are listed under "Documents" below.
of your own, or an entry in `SWWAF_TRAP_PATHS`, bans those the same way.
- Attacks carried in a request's URL or headers, such as SQL injection and path
traversal. The OWASP Core Rule Set is a published set of rules that recognise
common web attacks. Coraza, a Go engine, runs those rules (step 11 under "What
happens to a request" below). A request the rules take for an attack is
common web attacks. Coraza, a Go engine, runs those rules (see "Attack
detection" in [`SPEC.md`](SPEC.md)). A request the rules take for an attack is
refused.
- Abuse from networks and countries you do not want. You can:
- refuse whole netblocks and countries;
@@ -142,89 +141,32 @@ while working on it, see "Entrypoints" below.
## What happens to a request
Two terms recur below. A clear sign of attack is a request that matches a rule
whose action is `ban`, or asks for a trap path (steps 9 and 10). An offence is a
request that counts against its client in its history. It is one of:
`smallwebwaf` handles each request in fifteen steps, in this order. Once a step
refuses a request, the steps after it are skipped, apart from step 15, and
nothing of the request reaches the app. "What happens to a request" in
[`SPEC.md`](SPEC.md) gives each step in full, under the same numbers.
- a clear sign of attack;
- a broken limit;
- a refusal by a rule, by the Core Rule Set or for a missing or wrong token.
1. The health check, `GET /_smallwebwaf/healthz`, is answered at once.
2. The client is identified.
3. The static lists, `SWWAF_ALLOW_NETS` and `SWWAF_DENY_NETS`.
4. The bans.
5. The lookup of the client's AS number and country.
6. The country lists.
7. The reputation sources.
8. The client's limit percentage.
9. The rate limits.
10. The trap paths.
11. The rule files.
12. The Core Rule Set.
13. `smallwebwaf`'s own endpoints, under `/_smallwebwaf/`.
14. The request is passed to the app.
15. After the answer: the byte limits, the error burst and the client's history.
`smallwebwaf` handles each request in this order. Once a step refuses a request,
the steps after it are skipped, apart from step 13. Nothing of a refused request
reaches the app. "What happens to a request" in [`SPEC.md`](SPEC.md) gives each
step in full.
1. `GET /_smallwebwaf/healthz` is answered `200` with `ok` at once, before any
check and without asking the app.
2. The client is worked out. A netblock is a range of addresses, written as an
address and a prefix length: `203.0.113.0/24`. `SWWAF_TRUSTED_PROXIES` lists
the netblocks traefik comes from, by default the private address ranges. For
a TCP peer inside them, `X-Forwarded-For` is read from the right, and the
first address outside those netblocks is the client. A peer outside them is
the client itself. An IPv6 client is its group: the whole netblock around its
address, a /64 by default; `SWWAF_IPV6_GROUP_PREFIX` sets its length.
3. A client in `SWWAF_ALLOW_NETS` skips steps 4 to 11, the byte limits and the
error burst, but still needs a token at step 12. A client in
`SWWAF_DENY_NETS` is refused.
4. A client under a ban is refused. If the ban was made for a clear sign of
attack, this request makes it permanent.
5. The client's AS number and country are looked up, unless
`SWWAF_LOOKUP_SOURCE` is `off`. An AS number names the network an address
belongs to, such as `AS64496`.
6. The country lists are checked. A client from a country in
`SWWAF_DENIED_COUNTRIES` is refused. When
`SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES` is set, a client from any other country
is refused, and so is a client without a country. Such a refusal is not an
offence.
7. The reputation sources are checked: the blocklists, the CrowdSec decision
list, the DNS blocklists and AbuseIPDB. A client on the CrowdSec decision
list is banned until the decision ends. Any other source refuses the client,
lowers its limits or only notes it, as `SWWAF_BLOCKLIST_ACTION` and
`SWWAF_REPUTATION_ACTION` say. No request waits for a query.
8. Rate limiting counts the request, unless the client or the path is exempt. A
request that takes the client over a limit is refused and bans the client.
9. A request for a path in `SWWAF_TRAP_PATHS` is refused and bans the client, as
a clear sign of attack.
10. The rule files are checked. A `log` rule notes the match. A `block` rule
refuses the request. A `ban` rule refuses it and bans the client, as a clear
sign of attack.
11. The Core Rule Set inspects the request's method, URL and headers, and, once
`SWWAF_WAF_BODY_LIMIT` is set, form, JSON and XML bodies. A request it takes
for an attack is refused while `SWWAF_WAF_MODE` is `block`, the default, and
let through while it is `detect`. It bans no one by itself.
12. A request under `/_smallwebwaf/` is answered here by `smallwebwaf`, after
its token is checked. Any other request is passed to the app. The app's
answer is streamed back within the size and time limits.
13. Once the answer has ended, a request passed to the app has its bytes counted
for the byte limits. If a rule, a trap path, the Core Rule Set or a token
check refused the request, the refusal is counted for the error burst. The
client's history and the anomaly counters are updated. More than
`SWWAF_ERROR_BURST_THRESHOLD` refusals of one client in a minute ban it.
In `observe` mode (`SWWAF_MODE=observe`), `smallwebwaf` makes no ban of its own.
It refuses a request only for a size or time limit, or for a missing or wrong
token. A request it would otherwise have refused is passed to the app, and its
log line says what `enforce` mode would have done. Observe mode is for trying a
configuration before enforcing it.
What a refused visitor sees:
- `SWWAF_BAN_RESPONSE`, by default `403` with the plain text `Forbidden`. It can
be `429` instead, or `close`, which closes the connection, so that traefik
answers `502`. It answers:
- a ban or a broken rate limit;
- a `ban` rule or a trap path;
- `SWWAF_DENY_NETS` and the country lists;
- a reputation source whose action is `deny`.
- `403` for a `block` rule and the Core Rule Set.
- For a size or time limit:
- `431` for headers over their limit;
- `413` for a body over its limit;
- `408` for a client too slow to send its body;
- `502` or `504` when the app passes a limit or cannot be reached.
- `401` from an endpoint of `smallwebwaf`'s own, for a request without its
token.
A refused visitor is answered with `SWWAF_BAN_RESPONSE`, `403` by default (see
"Ban lengths, response and scope" in [`SPEC.md`](SPEC.md)). A `block` rule or a
Core Rule Set match answers `403`. A missing or wrong token gets `401`. A
request over a size or time limit gets the status for that limit, such as `413`
for a body too large (see "Size and time limits" in [`SPEC.md`](SPEC.md)).
## Settings you are likely to touch
@@ -233,8 +175,11 @@ Each setting is an environment variable of the app's container, such as
[`docs/settings.md`](docs/settings.md) lists every setting, its default and the
values it takes. The ones most deployments touch:
- `SWWAF_MODE=observe`: log what would have been refused, refuse almost nothing,
ban no one. For trying a configuration.
- `SWWAF_MODE=observe`: `smallwebwaf` makes no ban of its own, and refuses a
request only for a size or time limit or a missing or wrong token. A request
it would have refused is passed to the app, and its log line says what
`enforce` mode would have done. For trying a configuration before enforcing
it.
- `SWWAF_ALLOW_NETS`: 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`: netblocks exempt from rate limiting and the
@@ -376,50 +321,32 @@ nixpkgs fixed at one release. An app's `Dockerfile` installs a package with
[`docs/image.md`](docs/image.md) lists what the image holds and how each part is
pinned.
- The container's first process is `runsvinit`, which starts runit, a service
supervisor. runit runs the `run` script of each directory under
`/etc/service`, and runs it again a second after its program exits.
`smallwebwaf` runs as the `smallwebwaf` user (uid 65532) and the app as a user
of its own. So the app cannot touch the state files or the process of
`smallwebwaf`.
- `smallwebwaf` listens on port 8080, on every address. traefik sends the app's
requests there. `smallwebwaf` passes them to the app on `127.0.0.1:8081`. The
app listens on `127.0.0.1` only, so nothing reaches it except through
`smallwebwaf`. The health check, the metrics and the ban management are on the
same port, under `/_smallwebwaf/`. A request for that prefix never reaches the
app.
- The app sees what it would see from traefik directly: the same `Host`, the
same `X-Forwarded-Proto`, and `X-Forwarded-For` with traefik's address added
at the end. The app's TCP peer is `smallwebwaf` on `127.0.0.1`. So the app
must trust `127.0.0.1` and `::1` for forwarded headers, besides the private
address ranges. An app that keeps its usual trusted proxies sees every visitor
as `127.0.0.1`. Each request also carries its id in `X-Request-ID`. Any
`X-Client-ASN` or `X-Client-Country` header a client sent is removed.
- Both processes start with the container's environment variables. That is why
every setting of `smallwebwaf` starts with `SWWAF_`. A token given as an
environment variable is readable by the app. A token given as a file that only
the `smallwebwaf` user can read is not (see "Settings given as files" in
- runit, a service supervisor, runs `smallwebwaf` and the app side by side, each
as its own user, and starts either again when it exits. The app cannot touch
the state files or the process of `smallwebwaf`.
- `smallwebwaf` listens on port 8080 and passes requests to the app on
`127.0.0.1:8081`. The app listens on `127.0.0.1` only, so nothing reaches it
except through `smallwebwaf`. `smallwebwaf`'s own endpoints are under
`/_smallwebwaf/`, on the same port.
- The app sees the headers traefik sent, with traefik's address added to
`X-Forwarded-For`, from a TCP peer on `127.0.0.1`. So the app must trust
`127.0.0.1` and `::1` for forwarded headers, besides the private address
ranges.
- Both processes start with the container's environment variables, so every
setting of `smallwebwaf` starts with `SWWAF_`, and the app can read a token
given as one. A token given as a file that only the `smallwebwaf` user can
read is out of its reach (see "Settings given as files" in
[`docs/settings.md`](docs/settings.md)).
- The state files live in `/var/lib/smallwebwaf`. Without a volume there, they
survive a restart of the container and are lost when a deploy replaces it. The
`run` script gives that directory and every file in it to the `smallwebwaf`
user at each start, so a host directory mounted there needs no change of
owner.
- The image's health check passes while `smallwebwaf` answers
`GET /_smallwebwaf/healthz` and the app accepts connections. traefik sends a
container no requests until it is healthy.
- When `smallwebwaf` or the app exits, runit starts it again a second later. The
other process keeps running. While either is down, the client gets `502`. A
`smallwebwaf` that stops at start, as on an invalid setting, is started again
every second until the cause is fixed, and logs its message each time.
- `docker stop` has runit send `SIGTERM` to both processes at once.
`smallwebwaf` gives the requests in progress five seconds to finish and writes
its state files. To let them finish, the app must keep answering for five
- The state files live in `/var/lib/smallwebwaf`. A volume mounted there keeps
them across a deploy.
- `docker stop` stops both processes at once. `smallwebwaf` gives the requests
in progress five seconds to finish, so the app must keep answering for five
seconds after `SIGTERM`.
"Deployment" in [`SPEC.md`](SPEC.md) has the rest: moving `smallwebwaf` to
another port, the health check's timing, and the forwarded headers.
"Architecture" in [`SPEC.md`](SPEC.md) lists the packages and what each does.
"Deployment" in [`SPEC.md`](SPEC.md) has the rest: the health check, what
happens when a process stops, moving `smallwebwaf` to another port, and the
forwarded headers. "Architecture" in [`SPEC.md`](SPEC.md) lists the packages and
what each does.
## TODO
+58 -54
View File
@@ -164,8 +164,8 @@ its rules.
thresholds are evaluated.
In `SWWAF_MODE=observe`, every refusal above is logged as what would have
happened, nothing is refused, and no ban is made. The size and time limits and
the token check still apply.
happened, nothing is refused, and `smallwebwaf` makes no ban of its own. The
size and time limits and the token check still apply.
## Counting method
@@ -183,8 +183,8 @@ the token check still apply.
GeoJS answers, the reputation verdicts and scores, the DNS queries under way
and the anomaly counters have fixed bounds, listed under "Fixed limits" in
`docs/settings.md`. Past its bound, the GeoJS answer or anomaly counter used
longest ago goes first, and the verdict or score fetched longest ago. Past
that bound, a zone is asked at the client's next request.
longest ago goes first, and the verdict or score fetched longest ago. Past the
bound on DNS queries under way, a zone is asked at the client's next request.
## Bans
@@ -215,9 +215,12 @@ to a ban, each by its own rule:
permanent this way.
- Once that ban has run out, the netblock is served like any other. Its next
clear sign of attack bans it permanently at once.
- A broken limit: a request over a rate limit, a response that takes the
client's byte total past a byte limit, or more than
`SWWAF_ERROR_BURST_THRESHOLD` refusals within a minute.
- A broken limit, one of:
- a request over a rate limit;
- a response that takes the client's byte total past a byte limit;
- more than `SWWAF_ERROR_BURST_THRESHOLD` refusals within a minute.
The bans for a broken limit:
- The first such ban lasts `SWWAF_LIMIT_BAN_DURATION` (default `1h`), with
the cause `limit`. So does one that comes more than
`SWWAF_LIMIT_BAN_REPEAT_WINDOW` (default `24h`) after the last such ban
@@ -233,7 +236,7 @@ to a ban, each by its own rule:
A Core Rule Set match refuses only the request it matched, with `403` and
without a ban, because the Core Rule Set has false positives. A `block` rule
does the same. Those refusals count toward the error burst, so a client that
keeps setting them off is banned under the second rule.
keeps setting them off is banned for a broken limit.
A client on the CrowdSec decision list is banned until the decision ends, with
the cause `crowdsec`. Only a client that sends a request is banned, so a long
@@ -328,8 +331,8 @@ Conventions:
- `SWWAF_ADMIN_TOKEN` switches on the ban endpoints and
`/_smallwebwaf/clients/<ip>`. The metrics are off until `SWWAF_METRICS_TOKEN`
is set, since without a token they would be open to anyone on the internet.
The two are separate, so a scraper that holds the metrics token cannot manage
bans.
The two are separate, so the metrics collector, which holds the metrics token,
cannot manage bans.
- A token is a long random value, since the endpoints can be reached from the
internet. One shorter than 32 characters stops the start. The app starts with
the same environment variables as `smallwebwaf`, so it can read a token set as
@@ -453,8 +456,8 @@ service that keeps its visitors' addresses on its own host.
Addresses are asked about together, up to 200 in one request
(`https://get.geojs.io/v1/ip/geo.json?ip=a,b,c`), one request at a time, which
keeps the number of requests to GeoJS low. Each answer's `country_code`, `asn`
and `organization_name` are read. An answer without a `country_code`, or with
the `asn` `64512`, counts as unknown.
and `organization_name` are read. An answer without a `country_code` leaves
the country unknown, and the `asn` `64512` leaves the AS number unknown.
- Each answer is kept for seven days, in memory and in `lookups.json`. Answers
are kept apart from the table of clients, so that an answer outlasts a client
dropped from that table. The answer reaches the client's history and ban notes
@@ -528,12 +531,12 @@ service's abuse comes from.
fetched and kept like a blocklist (see "Reputation"). Where it and
`SWWAF_ASN_LIMIT_PERCENT` both give a percentage, the lower applies.
- A client's limit percentage is the lowest of those that apply to it: its AS
number's, its country's, or a reputation hit's `limit:<percent>`. A client the
lookup cannot place gets `SWWAF_UNKNOWN_LIMIT_PERCENT` in place of an AS
number's or a country's. The percentage is 100 if none applies. Clients given
a lower percentage are banned after fewer requests, first for a while and
then, for repeated abuse, permanently. The log line of each counted request,
and the notes of each ban, say which setting lowered the limit.
number's, its country's, or a reputation hit's `limit:<percent>`. A client
without a country gets `SWWAF_UNKNOWN_LIMIT_PERCENT` in place of a country's.
The percentage is 100 if none applies. Clients given a lower percentage are
banned after fewer requests, first for a while and then, for repeated abuse,
permanently. The log line of each counted request, and the notes of each ban,
say which setting lowered the limit.
- No budget is shared by a whole country or AS number. One abuser could use it
up and lock out everyone else there: a denial of service nobody chose, and the
one this tool exists to prevent. Refusing a whole country is left to the
@@ -544,15 +547,14 @@ service's abuse comes from.
By default the Core Rule Set reads the method, the URL with its query string,
and the headers of every request. That is where automated attacks show:
injection in query strings, path traversal, attacks carried in headers,
scanners' user agents. It reads no request body. On a code forge, the example
deployment, bodies carry what people write and publish, such as issue text and
scanners' user agents. It reads no request body. In front of a code forge such
as gitea, bodies carry what people write and publish, such as issue text and
files saved in the web editor. The Core Rule Set takes the shell commands and
code in them for attacks. The default gives up refusing an attack carried in a
body. The rule files, the limits and the bans still apply to the client that
sends it.
- The Core Rule Set skips a path under `SWWAF_WAF_EXEMPT_PATHS`. An engine error
on a request forwards the request, and is logged and counted.
- The Core Rule Set skips a path under `SWWAF_WAF_EXEMPT_PATHS`.
- `SWWAF_WAF_PARANOIA_LEVEL` and `SWWAF_WAF_ANOMALY_THRESHOLD` are the Core Rule
Set's own two tuning values, at its own defaults. Each level up runs more
rules, which find more attacks and take more ordinary requests for attacks.
@@ -633,12 +635,12 @@ every app, and no setting undoes them:
- `ref`, `sha`, `branch` and `workflow`;
- `artifactName` and `redirect_to`.
gitea puts file paths, branch and workflow names, and the page to return to
after signing in into them. It reads these values as names in a repository
gitea puts into them file paths, branch and workflow names, and the page to
return to after signing in. It reads these values as names in a repository
or in its own records, or as a page of its own site, never as a command. Any
name on those lists can be an ordinary file or branch, such as `.gitignore`
or `docker-build`. In these parameters, anything only these three rules
catch reaches the app, commands such as `|cat /etc/passwd` included. Path
or `docker-build`. In these parameters, what only these three rules would
catch reaches the app, such as the command `|cat /etc/passwd`. Path
traversal, SQL and script injection, and PHP, Java and Node.js code are
still refused there. Every other parameter keeps all three rules. An app
that uses one of these parameters as a file on the server, or passes it to a
@@ -647,8 +649,8 @@ every app, and no setting undoes them:
5. Two cookies are left out, and `Referer` keeps fewer rules:
- The Core Rule Set reads the request without the `gitea_flash` and
`redirect_to` cookies. gitea puts a message naming what was just done into
`gitea_flash`. It puts the page to return to after signing in into
`redirect_to`. The Core Rule Set takes file names in them, such as
`gitea_flash`. It puts into `redirect_to` the page to return to after
signing in. The Core Rule Set takes file names in them, such as
`package.json`, for attacks. A browser sends such a cookie with every
request until gitea replaces it. gitea cannot replace it while those
requests are refused, so one refusal would keep the browser out of the
@@ -772,7 +774,8 @@ too close together.
client gets a quarter of every request and byte limit rather than a refusal.
- Verdicts and scores are kept for `SWWAF_REPUTATION_CACHE_TTL`, in memory and
in `reputation.json`. A source that is down or over quota gives no verdict.
The service continues, with one `source_failure` alert per cooldown.
The service continues. Each failure raises a `source_failure` alert (see
"Alerting").
### Alerting
@@ -861,11 +864,11 @@ and the default file.
wrong for every app, with its path rules anchored at the site root. In front
of gitea, `/.env` is a probe, while
`/<owner>/<repo>/src/branch/main/.env.example` is a file in a repository that
any visitor may open. `ban` rules of your own follow the same rule. Anything
app-specific, such as a rule banning WordPress probes in front of gitea,
belongs in a file the app's Dockerfile adds or the deployer mounts. A
directory mounted over `SWWAF_RULES_DIR` replaces the default file; single
files mounted into it add to it.
any visitor may open. Anchor the paths of your own `ban` rules at the site
root too. Anything app-specific, such as a rule banning WordPress probes in
front of gitea, belongs in a file the app's Dockerfile adds or the deployer
mounts. A directory mounted over `SWWAF_RULES_DIR` replaces the default file;
single files mounted into it add to it.
- Rules meant to be edited while `smallwebwaf` runs belong in a mounted
directory, not a mounted file. Many editors save a file by replacing it, and a
container keeps seeing the old one when the file alone is mounted. The lookup
@@ -874,11 +877,11 @@ and the default file.
## Persistent state
All state lives in memory, and the files in `SWWAF_STATE_DIR` hold a copy of all
of it, so an orderly stop loses nothing (the remote log is the exception; see
"Request log"). The files are meant for people as well: an admin can read or
edit them at any time, and the running `smallwebwaf` takes the edit in.
`docs/state-files.md` lists the files, what each holds, and their sizes.
All state lives in memory, and the files in `SWWAF_STATE_DIR` hold a copy of it,
so an orderly stop loses nothing. The files are meant for people as well: an
admin can read or edit them at any time, and the running `smallwebwaf` takes the
edit in. `docs/state-files.md` lists the files, what each holds, and their
sizes.
- Each file holds one kind of state, as JSON with:
- a top-level `version` number;
@@ -1019,14 +1022,14 @@ what the image holds and how each part is pinned.
digest.
- nixpkgs comes from a release file on `releases.nixos.org`, named with its
hash, not from a GitHub archive, whose bytes can change. Root uses Nix
directly; no Nix daemon runs, and since `nix-bin` creates no build users,
`build-users-group =` in `/etc/nix/nix.conf` lets root build without them.
Root's Nix profile is last on the `PATH`, so that no package hides the image's
own commands; busybox's `sv`, for one, looks for services elsewhere. An app
built on the image gets the same packages each time. Security fixes from
Ubuntu and nixpkgs come with a newer `smallwebwaf` image, which an app takes
by changing the digest in its `FROM` line. The image moves to each new nixpkgs
release, every six months.
directly; no Nix daemon runs. `nix-bin` creates no build users, so
`/etc/nix/nix.conf` sets `build-users-group =`, which lets root build without
them. Root's Nix profile is last on the `PATH`, so that no package hides the
image's own commands; busybox's `sv`, for one, looks for services elsewhere.
An app built on the image gets the same packages each time. Security fixes
from Ubuntu and nixpkgs come with a newer `smallwebwaf` image, which an app
takes by changing the digest in its `FROM` line. The image moves to each new
nixpkgs release, every six months.
- runit supervises the two processes, with `runsvinit` as the entrypoint, as the
owner's code style guide asks for service containers. No package carries
`runsvinit`, so the image builds it from its archived source, unchanged since
@@ -1075,10 +1078,10 @@ It sets no `ENTRYPOINT` or `USER` of its own. The container must start
- an unwritable `SWWAF_STATE_DIR`;
- a `SWWAF_RULES_DIR` that does not exist or cannot be read;
- a `SWWAF_LISTEN_ADDR` it cannot listen on.
- A `smallwebwaf` that stops at start is therefore started again every second,
logging its message each time, until the cause is fixed; the health check
fails meanwhile. Once running, a failing GeoJS, reputation source or alert
destination, or a broken edit, never takes the protected service down.
- A `smallwebwaf` that stops at start logs its message at each try until the
cause is fixed; the health check fails meanwhile. Once running, a failing
GeoJS, reputation source or alert destination, or a broken edit, never takes
the protected service down.
- `docker stop` sends `SIGTERM` to `runsvinit`, which has runit stop both
services at once, each with `SIGTERM`, and exits once they have stopped.
`smallwebwaf` stops taking requests, gives those in progress five seconds to
@@ -1147,9 +1150,10 @@ all: `10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32,::1/128`.
### upaas
An app deployed by upaas takes this shape with no change to upaas. upaas builds
the app's Dockerfile and runs the one container as it runs any app. The traefik
labels route to port 8080, and any `SWWAF_` settings go with the app's
An app deployed by upaas, which rebuilds and restarts an app's Docker container
when its repository changes, takes this shape with no change to upaas. upaas
builds the app's Dockerfile and runs the one container as it runs any app. The
traefik labels route to port 8080, and any `SWWAF_` settings go with the app's
environment variables. The volume for `/var/lib/smallwebwaf` and the directory
of any token file go beside the app's own volumes. gitea is built on the image
like any other app; `docs/gitea.md` records what the defaults do in front of it,
+1 -2
View File
@@ -196,8 +196,7 @@ that take `off`, the `_FILE` form, and what each group does and why.
- `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`.
in a minute (see "Attack detection" in `SPEC.md`). A count or `off`.
## Ban lengths, response and scope