bb4ed3502d
P5-01 — Documentation site under docs/book/ rendered with mdBook
(downloaded via Makefile, same static-binary pattern as Tailwind).
Structured chapters: getting started, concepts, operations,
security, reference. `make docs` / `make docs-watch`. Generated
output gitignored.
P5-02 — CONTRIBUTING.md rewritten from placeholder to a full
guide. CODE_OF_CONDUCT.md adapted from Contributor Covenant for a
single-maintainer project. .gitea/issue_template/{bug,feature}.md
and PULL_REQUEST_TEMPLATE.md.
P5-04 — Six README screenshots captured live from a fresh server
bootstrap (login, empty dashboard, add-host, alerts, settings,
audit log). README rewritten to centre the screenshot grid and
link out to the docs site.
P5-05 — SECURITY.md with disclosure policy (3-day ack, 30-day
default window), scope in/out, threat-model summary, operator
hardening checklist. Mirrored as a docs-site chapter.
P5-06 — End-to-end test harness. e2e/compose.e2e.yml brings up
server + sibling Linux agent (alpine + restic) + restic/rest-server.
Agent uses announce-and-approve so Playwright can drive the full
operator flow: bootstrap → login → accept pending → backup →
verify terminal status. Second spec scrapes /metrics to assert
the P6-04 endpoint surface. .gitea/workflows/e2e.yml runs on every
PR; local how-to in docs/e2e.md.
96 lines
3.1 KiB
Markdown
96 lines
3.1 KiB
Markdown
# Running behind a reverse proxy
|
|
|
|
The restic-manager server is HTTP-only by design. TLS termination,
|
|
public hostname, ACME, HSTS, and edge-level rate limiting all
|
|
belong to a reverse proxy you already operate outside this project.
|
|
|
|
## What the proxy must forward
|
|
|
|
The server reads four headers when (and only when) the immediate
|
|
peer matches `RM_TRUSTED_PROXY`:
|
|
|
|
| Header | Value | Why |
|
|
|------------------------|----------------------------------------------------|-----|
|
|
| `X-Forwarded-For` | The original client IP | Rate-limit keys, audit log entries, OIDC redirect-URI checks. |
|
|
| `X-Forwarded-Proto` | `https` | Used for absolute URLs (e.g. OIDC redirect URIs). |
|
|
| `Host` | The public hostname clients use | Cookies are scoped to this; `RM_BASE_URL` must match. |
|
|
| `Connection` / `Upgrade` | Pass through unchanged | `/ws/agent` and `/api/jobs/{id}/stream` are WebSockets; without `Upgrade: websocket` they fail. |
|
|
|
|
Set `RM_TRUSTED_PROXY` to the CIDR (or comma-separated list of
|
|
CIDRs) the proxy connects from. Anything outside that range has
|
|
its `X-Forwarded-*` headers ignored, so a stray request that
|
|
bypasses the proxy can't spoof the client IP.
|
|
|
|
## Caddy
|
|
|
|
```caddyfile
|
|
restic.example.com {
|
|
encode zstd gzip
|
|
reverse_proxy 127.0.0.1:8080 {
|
|
header_up X-Real-IP {remote_host}
|
|
}
|
|
}
|
|
```
|
|
|
|
Caddy adds `X-Forwarded-For` / `X-Forwarded-Proto` automatically
|
|
and passes WebSocket headers through by default, so this is the
|
|
whole config.
|
|
|
|
## nginx
|
|
|
|
```nginx
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name restic.example.com;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/restic.example.com/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/restic.example.com/privkey.pem;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:8080;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto https;
|
|
|
|
# WebSocket upgrade
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
|
|
# Long-lived agent WS — disable read timeout for this surface.
|
|
proxy_read_timeout 86400s;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Traefik
|
|
|
|
```yaml
|
|
http:
|
|
routers:
|
|
restic-manager:
|
|
rule: "Host(`restic.example.com`)"
|
|
entryPoints: [websecure]
|
|
tls:
|
|
certResolver: letsencrypt
|
|
service: restic-manager
|
|
|
|
services:
|
|
restic-manager:
|
|
loadBalancer:
|
|
servers:
|
|
- url: "http://restic-manager:8080"
|
|
passHostHeader: true
|
|
```
|
|
|
|
Traefik forwards WebSocket upgrades and the standard
|
|
`X-Forwarded-*` set out of the box.
|
|
|
|
## Verification
|
|
|
|
After bringing the proxy up, the audit log should show your real
|
|
client IP for an interactive login (not the proxy's local
|
|
address). If you see `127.0.0.1` or the proxy's container IP, your
|
|
`RM_TRUSTED_PROXY` is wrong or `X-Forwarded-For` isn't being
|
|
forwarded.
|