You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Then restart the services and open `https://<hostname>:8443`. You will need to accept the certificate warning unless you import the certificate into your browser trust store.
355
355
356
+
### Pattern C — plain HTTP on a VPN interface
357
+
358
+
If Arbor is reachable only through a VPN tunnel (e.g. WireGuard), the tunnel itself provides confidentiality and a self-signed certificate adds no real security. Use `ARBOR_ALLOW_PLAINTEXT=1` to opt out of the TLS requirement:
359
+
360
+
```bash
361
+
ARBOR_HOST=0.0.0.0 # or the specific WireGuard interface IP
Arbor prints a startup warning. This mode is **only safe** when the bind address is reachable exclusively through a trusted private network or VPN — do not combine it with a public interface.
369
+
370
+
If you also want to keep the existing HTTPS reverse-proxy path (e.g. for access via a public domain), run two separate Arbor instances on different ports, or keep Apache terminating TLS on the public side while Arbor binds to the WireGuard IP directly.
371
+
372
+
**Apache HTTP proxy in front of the VPN path** (optional, e.g. to share port 80 with other services):
373
+
374
+
```apache
375
+
<VirtualHost *:80>
376
+
ServerName 10.0.0.1
377
+
ProxyPreserveHost On
378
+
RequestHeader set X-Forwarded-Proto "http"
379
+
380
+
ProxyPass /ws/ ws://127.0.0.1:8444/ws/
381
+
ProxyPassReverse /ws/ http://127.0.0.1:8444/ws/
382
+
383
+
ProxyPass /api/ http://127.0.0.1:8444/api/
384
+
ProxyPassReverse /api/ http://127.0.0.1:8444/api/
385
+
386
+
ProxyPass / http://127.0.0.1:8444/
387
+
ProxyPassReverse / http://127.0.0.1:8444/
388
+
</VirtualHost>
389
+
```
390
+
391
+
Do **not** add `ProxyPassReverseCookiePath` — it rewrites the cookie `Path` attribute, which causes the browser to hold multiple cookies with the same name and breaks CSRF validation. If you previously had this directive and see CSRF errors after removing it, clear all `arbor_*` cookies in the browser and re-login.
392
+
356
393
### After any LAN config change
357
394
358
395
- Sessions made before the change carry the old cookie attributes — log out + log in again to pick up `SameSite=Strict` and the CSRF cookie.
@@ -382,7 +419,7 @@ Then restart the services and open `https://<hostname>:8443`. You will need to a
382
419
|`ARBOR_IPC_KEY_FILE`|`/etc/arbor/ipc.key`| Shared HMAC key file, generated by setup by default |
383
420
|`ARBOR_IPC_ALLOWED_UIDS`| uid of user `arbor`| Comma-separated peer uid allowlist for `/run/arbor/daemon.sock`. Anything outside this set is rejected via `SO_PEERCRED`. |
384
421
|`ARBOR_TRUSTED_PROXIES`|`127.0.0.1`| Comma-separated IPs passed to uvicorn's `forwarded_allow_ips`. Controls which proxy addresses are trusted to set `X-Forwarded-For` / `X-Forwarded-Proto`. |
385
-
|`ARBOR_ALLOW_PLAINTEXT`| unset | Allow plain HTTP on **loopback only** when `ARBOR_TLS` is unset and cert/key are missing. Refused on public binds. |
422
+
|`ARBOR_ALLOW_PLAINTEXT`| unset | Allow plain HTTP on non-loopback interfaces (e.g. a WireGuard VPN address). Set to `1` alongside `ARBOR_HOST=0.0.0.0` (or a specific VPN IP) and `ARBOR_TLS=0`. Only safe when the network itself provides confidentiality (VPN tunnel). A startup warning is printed. |
|`ARBOR_STATIC_DIR`| auto-detected | Override the frontend static directory |
388
425
@@ -451,9 +488,9 @@ Arbor is still an early-release, local-first admin tool. The default install bin
451
488
### Web edge
452
489
453
490
-**CSRF**: every state-changing request (`POST`, `PUT`, `DELETE`, `PATCH`) requires a matching `X-CSRF-Token` header that echoes the `arbor_csrf` cookie. The cookie is set at login, rotated on logout/TOTP changes, and verified by middleware before the handler runs. The first WebSocket auth frame must include the same token. The login endpoint itself is the only exemption.
454
-
-**Cookies**: both `arbor_session` (HttpOnly) and `arbor_csrf` are `Secure`and `SameSite=Strict`. Cross-site navigations no longer carry the session, which closes most CSRF vectors at the browser level.
491
+
-**Cookies**: both `arbor_session` (HttpOnly) and `arbor_csrf` are `SameSite=Strict`. The `Secure`flag is set when the request is served over HTTPS (either Arbor's own TLS or via a reverse proxy that sets `X-Forwarded-Proto: https`); on plain HTTP (e.g. VPN access with `ARBOR_ALLOW_PLAINTEXT=1`) cookies are set without `Secure` so the browser accepts and returns them. Cross-site navigations no longer carry the session, which closes most CSRF vectors at the browser level.
455
492
-**HSTS**: emitted as `Strict-Transport-Security: max-age=63072000; includeSubDomains` when the request is served over HTTPS (including via a reverse proxy that sets `X-Forwarded-Proto: https`).
456
-
-**TLS bind enforcement**: a non-loopback bind (`ARBOR_HOST` other than `127.0.0.1`/`::1`/`localhost`) requires TLS to be active. Arbor refuses to start in plain HTTP on a public interface.
493
+
-**TLS bind enforcement**: a non-loopback bind (`ARBOR_HOST` other than `127.0.0.1`/`::1`/`localhost`) requires TLS to be active by default. Arbor refuses to start in plain HTTP on a public interface unless `ARBOR_ALLOW_PLAINTEXT=1` is set (opt-in escape hatch for VPN/private network deployments where the tunnel itself provides confidentiality).
457
494
-**WebSocket origin**: a missing `Origin` header is accepted only when bound to loopback. On any public bind, the connecting `Origin` must be in `ARBOR_CORS_ORIGINS`.
458
495
-**Security response headers**: a strict CSP (`script-src 'self'`, `object-src 'none'`, `frame-ancestors 'none'`), `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`. `/docs`, `/redoc`, and `/openapi.json` are disabled.
0 commit comments