Docs: rproxy runs behind any TLS-terminating reverse proxy (closes #388)
check / check (push) Failing after 2m26s
check / check (push) Failing after 2m26s
README, SPEC and docs no longer present traefik as the required front proxy, and call it the TLS-terminating proxy. The README section of that name lists what the proxy must do: forward plain HTTP to port 8080, keep Host, set X-Forwarded-For and X-Forwarded-Proto, close an unused connection in under 120 seconds, and connect from an address in SWW_RPROXY_TRUSTED_PROXIES. traefik, Caddy and nginx appear as examples, with the Caddy and nginx settings their defaults lack. Model: opus-5-5
This commit was merged in pull request #391.
This commit is contained in:
1 parent
53d9bf6af6
commit
a05a82b1af
4 files changed
+100
-53
No files matched your search
@@ -3,7 +3,7 @@
|
||||
`smallwebwaf` is a web application firewall for self-hosted apps. It is one
|
||||
binary, `sww`, and two of its commands do the work:
|
||||
|
||||
- `sww rproxy` is a reverse proxy between traefik and one app.
|
||||
- `sww rproxy` is a reverse proxy between a TLS-terminating proxy and one app.
|
||||
- `sww waf` decides what happens to each request, for many sites.
|
||||
|
||||
This document says what it must do and why, each requirement once. Everything in
|
||||
@@ -45,7 +45,8 @@ never as a time.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- TLS, certificates and routing by host name. Those are traefik's job.
|
||||
- TLS, certificates and routing by host name. Those are the job of the
|
||||
TLS-terminating proxy, such as traefik, nginx or Caddy.
|
||||
- More than one app behind one `rproxy`. Each app has its own.
|
||||
- Browser challenges such as captchas or proof of work. If wanted, chain Anubis
|
||||
between `rproxy` and the app.
|
||||
@@ -1943,10 +1944,10 @@ leave out a cookie only when its name matches exactly, case included.
|
||||
### Ban lengths, response and scope
|
||||
|
||||
`SWW_WAF_BAN_RESPONSE` is `403` by default, which makes a ban easy to recognise
|
||||
when debugging; `429` and `close` are the alternatives. Behind traefik, `close`
|
||||
does not leave the client unanswered: traefik answers `502`, as it does whenever
|
||||
its backend drops a connection. `SWW_WAF_BAN_SCOPE_V4_PREFIX` widens an IPv4 ban
|
||||
to the surrounding netblock. The four ban lengths are under "Bans".
|
||||
when debugging; `429` and `close` are the alternatives. `close` does not leave
|
||||
the client unanswered: the TLS-terminating proxy answers `502`, as it does
|
||||
whenever its backend drops a connection. `SWW_WAF_BAN_SCOPE_V4_PREFIX` widens an
|
||||
IPv4 ban to the surrounding netblock. The four ban lengths are under "Bans".
|
||||
|
||||
### Reputation
|
||||
|
||||
@@ -2771,9 +2772,9 @@ its whole body. The visitor gets that answer at once, and the connection closes
|
||||
after it.
|
||||
|
||||
The largest request line and headers is 32 KiB. A kept-open connection is closed
|
||||
after 120 seconds idle. Neither has a setting. traefik, by default, closes an
|
||||
unused connection after 90 seconds. So traefik closes first, and never sends a
|
||||
request on a connection `rproxy` is closing.
|
||||
after 120 seconds idle. Neither has a setting. The TLS-terminating proxy should
|
||||
close an unused connection sooner, so that it never sends a request on a
|
||||
connection `rproxy` is closing. traefik closes one after 90 seconds by default.
|
||||
|
||||
What the visitor gets when a limit is passed:
|
||||
|
||||
@@ -2824,14 +2825,16 @@ chooses: `waf` runs `waf`, and with it unset the image runs `rproxy`.
|
||||
The usual setup is three containers on one private network:
|
||||
|
||||
- the app;
|
||||
- `rproxy`, which traefik routes to, with `SWW_RPROXY_UPSTREAM_URL` naming the
|
||||
app and `SWW_RPROXY_WAF_BACKEND` naming `waf`;
|
||||
- `rproxy`, which the TLS-terminating proxy forwards to, with
|
||||
`SWW_RPROXY_UPSTREAM_URL` naming the app and `SWW_RPROXY_WAF_BACKEND` naming
|
||||
`waf`;
|
||||
- `waf`, with `SWW_COMMAND=waf` and a volume for its state files.
|
||||
|
||||
Each further app adds its own container and its own `rproxy`, whose
|
||||
`SWW_RPROXY_WAF_BACKEND` names the same `waf` (see "Sites"). Anything on that
|
||||
network can reach an app around `rproxy`, and can ask `waf` questions or send it
|
||||
reports. So the network holds only what you trust.
|
||||
reports. So the network holds only what you trust. `README.md` lists what the
|
||||
TLS-terminating proxy must do.
|
||||
|
||||
### `rproxy` in the app's container
|
||||
|
||||
@@ -2903,10 +2906,10 @@ process that stops at start is started again every second, not in a tight loop.
|
||||
container's output, which `docker logs` shows.
|
||||
- When a service exits, runit runs its `run` script again, and the container
|
||||
does not stop. Beside an app, the other process keeps running.
|
||||
- While `rproxy` is down, traefik answers `502`. While the app is down, `rproxy`
|
||||
answers `502`, which is not a client offence. While `waf` is down,
|
||||
`SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION` decides (see "Without an answer
|
||||
from `waf`").
|
||||
- While `rproxy` is down, the TLS-terminating proxy answers `502`. While the app
|
||||
is down, `rproxy` answers `502`, which is not a client offence. While `waf` is
|
||||
down, `SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION` decides (see "Without an
|
||||
answer from `waf`").
|
||||
- Only faults found at start stop `waf`:
|
||||
- invalid configuration;
|
||||
- a lookup database that is missing or unreadable;
|
||||
@@ -2939,23 +2942,26 @@ checks:
|
||||
- With `SWW_COMMAND` unset, empty or `rproxy`, it passes while `rproxy` answers
|
||||
that request on `127.0.0.1`, at the port in `SWW_RPROXY_LISTEN_ADDR`, and the
|
||||
app accepts connections at `SWW_RPROXY_UPSTREAM_URL`. It does not ask `waf`,
|
||||
so that the site stays in traefik's routes while `waf` is down.
|
||||
so that the site stays in the TLS-terminating proxy's routes while `waf` is
|
||||
down.
|
||||
- With any other value, it fails with a message naming `SWW_COMMAND` and its
|
||||
value.
|
||||
|
||||
traefik sends a container no requests until it shows as healthy. So the check
|
||||
runs every second from the container's start until it first passes, for up to a
|
||||
minute, and every 30 seconds after that. An app with a health check of its own
|
||||
can replace the image's `HEALTHCHECK` with one that checks both.
|
||||
A TLS-terminating proxy that reads Docker's health status, as traefik does,
|
||||
sends a container no requests until it shows as healthy. So the check runs every
|
||||
second from the container's start until it first passes, for up to a minute, and
|
||||
every 30 seconds after that. An app with a health check of its own can replace
|
||||
the image's `HEALTHCHECK` with one that checks both.
|
||||
|
||||
### Ports
|
||||
|
||||
`rproxy` listens on no port but the one in `SWW_RPROXY_LISTEN_ADDR`, 8080 by
|
||||
default, which traefik routes to. It passes requests to the app at
|
||||
`SWW_RPROXY_UPSTREAM_URL`, `http://127.0.0.1:8081` by default. Another port may
|
||||
be set: the health check follows the setting, and traefik's port label
|
||||
(`traefik.http.services.<name>.loadbalancer.server.port`) must name it. An app
|
||||
beside `rproxy` must leave that port free.
|
||||
default, which the TLS-terminating proxy forwards to. It passes requests to the
|
||||
app at `SWW_RPROXY_UPSTREAM_URL`, `http://127.0.0.1:8081` by default. Another
|
||||
port may be set: the health check follows the setting, and the TLS-terminating
|
||||
proxy must name it, as traefik's port label
|
||||
(`traefik.http.services.<name>.loadbalancer.server.port`) does. An app beside
|
||||
`rproxy` must leave that port free.
|
||||
|
||||
`waf` listens on no port but the one in `SWW_WAF_LISTEN_ADDR`, 8080 by default.
|
||||
The questions, the reports and its own endpoints all come there.
|
||||
@@ -2996,9 +3002,9 @@ in `docs/settings.md` shows the commands.
|
||||
### Forwarded headers
|
||||
|
||||
The app's TCP peer is `rproxy`, and the `X-Forwarded-For` the app receives ends
|
||||
with traefik's address, which `rproxy` adds after the visitor's. So the app must
|
||||
trust `rproxy`'s address for forwarded headers, besides the private address
|
||||
ranges traefik is on.
|
||||
with the TLS-terminating proxy's address, which `rproxy` adds after the
|
||||
visitor's. So the app must trust `rproxy`'s address for forwarded headers,
|
||||
besides the private address ranges the TLS-terminating proxy is on.
|
||||
|
||||
- In a container of its own, `rproxy`'s address is on the private network. The
|
||||
usual default for a trusted-proxy setting, the private ranges, covers it.
|
||||
|
||||
Reference in new issue
Block a user