diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 3caf5c9..31f8926 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -31,9 +31,13 @@ hbbs itself (only the optional `oidc.toml` referenced from a flag). | Flag | Default | Purpose | |---|---|---| | `--http-port=` | `21114` | HTTP API port (`/api/*`) and admin dashboard (`/admin/*`). `0` disables both. | +| `--http-listen=` | wildcard | Bind address for `--http-port`. Set to `127.0.0.1` (or `::1`) when nginx/Caddy fronts this port for TLS so the reverse proxy can claim the public port without colliding. See "TLS deployment with nginx" below. | +| `--ws-listen=` | wildcard | Bind address for the browser-facing WebSocket rendezvous port (`port + 2`, default 21118). Same usage pattern as `--http-listen`. The plain TCP/UDP rendezvous ports (21115/21116) intentionally stay on the wildcard — desktop clients don't go through the reverse proxy. | | `--admin-ui-dir=` | `./admin_ui` | Hint at where the dashboard's static HTML lives. The HTML is *embedded* in the binary; this flag is informational. Setting it to empty (`--admin-ui-dir=`) disables the dashboard entirely. | | `--public-base-url=` | unset | The externally-reachable HTTP base of this server, e.g. `https://rustdesk.example.com:21114`. **Required when OIDC is enabled** — used to build `/oidc/callback` redirect URIs. | +The matching flag on **hbbr** is `--ws-listen=` (binds the relay's WS port, default 21119). hbbr's plain TCP relay port (21117) stays on the wildcard for desktop clients. See `./hbbr --help` for the full list. + ### Bootstrap admin | Flag | Purpose | @@ -249,11 +253,27 @@ name (Zitadel) or omit it to default to `"roles"` (generic). ## TOTP / 2FA -Per-user TOTP is enrolled from the dashboard: +TOTP enrollment is **self-service**: each user enables it for their own +account from the dashboard's "My profile" page. The flow is two-step +with QR confirmation, so no secret is stored until the user proves they +have a working authenticator: -1. Sign in as an admin → **Users** page. -2. Pick a user → action menu → **Enroll TOTP**. -3. Scan the QR code into an authenticator (1Password, Authy, Google Authenticator, etc.). The secret is shown once and stored in `user_totp_secrets`. +1. Sign in to the dashboard → **My profile** (sidebar) → **Enroll TOTP**. +2. Server generates a fresh secret and renders an inline SVG QR code + + the base32 secret for manual entry. Nothing is written to + `user_totp_secrets` at this point. +3. User scans the QR into an authenticator (1Password, Authy, Google + Authenticator, etc.) and submits the 6-digit code shown. +4. Server verifies the code against the pending secret. On match, the + secret lands in `user_totp_secrets`. Wrong code re-renders the same + QR with an error notice — no need to re-scan. +5. Removing TOTP requires the user's current password. + +Admins can disable a user's TOTP from the **Users** page action menu +(useful when a user lost their authenticator), but **cannot enroll it +on someone else's behalf** — the user has to do that themselves so the +secret never travels through admin hands. OIDC-linked accounts skip +local TOTP entirely; their MFA lives at the IdP. After enrollment, the next desktop-client login flow is: @@ -298,9 +318,11 @@ If you set `--ab-legacy-mode=on`, `/api/ab/personal` 404s and clients fall back | `/admin/login` | none (POST form) | Password+TOTP submit → sets `rd_admin_session` cookie | | `/admin/logout` | cookie | Clears cookie | | `/admin/me` | cookie | Sidebar's logged-in-as widget | +| `/admin/assets/tailwindcss.js` | none | Vendored Tailwind 3.4.16 Play CDN. Long-cache. | +| `/admin/assets/htmx.min.js` | none | Vendored htmx.org 1.9.10. Long-cache. | | `/admin/oidc/providers` | none | JSON list of enabled providers, used by login.html | | `/admin/login/oidc/:name` | none | Starts admin OIDC flow (302s to IdP) | -| `/admin/pages/users` | cookie + admin | Users page fragment | +| `/admin/pages/users` | cookie + admin | Users page fragment (incl. inline edit-profile / password-reset / TOTP-disable per row) | | `/admin/pages/devices` | cookie + admin | Devices (incl. delete) | | `/admin/pages/groups` | cookie + admin | Device groups | | `/admin/pages/strategies` | cookie + admin | Strategy management | @@ -309,6 +331,12 @@ If you set `--ab-legacy-mode=on`, `/api/ab/personal` 404s and clients fall back | `/admin/pages/audit` | cookie + admin | Audit log browser | | `/admin/pages/recordings` | cookie + admin | Recording file listing | | `/admin/pages/deploy` | cookie + admin | `--config` blob + renamed-installer generator | +| `/admin/pages/profile` | cookie | Self-service profile (display name, email, password, TOTP enroll/remove). Available to all signed-in users — no admin gate. | +| `/admin/pages/profile/update-info` | cookie (POST) | Display name + email update | +| `/admin/pages/profile/change-password` | cookie (POST) | Requires current password; refused for OIDC-linked accounts | +| `/admin/pages/profile/totp/{start,confirm,remove}` | cookie (POST) | Two-step QR enroll, plus password-gated removal | +| `/admin/connect/:peer_id` | cookie + admin | Web-client SPA shell — opens a browser-based remote-control session in a new tab | +| `/admin/connect/assets/bundle.{js,css}` | cookie + admin | Compiled web-client SPA bundle | The session cookie (`rd_admin_session`) is HttpOnly + SameSite=Strict. The middleware accepts the same cookie *or* `Authorization: Bearer …`, @@ -599,9 +627,10 @@ multi-instance HA; run a single hbbs against a single SQLite file. ## Security checklist before exposing to the internet -- TLS in front of `--http-port` (Caddy / nginx / Traefik). Required for OIDC redirect URIs in production. +- TLS in front of `--http-port` and the WebSocket ports (Caddy / nginx / Traefik). Required for OIDC redirect URIs and for the web client (browsers block mixed `ws://`). See "TLS deployment with nginx" for a worked config. +- Pin browser-facing ports to localhost when a reverse proxy is in front: `--http-listen=127.0.0.1` on hbbs, `--ws-listen=127.0.0.1` on both hbbs and hbbr. Keeps the plain-HTTP / plain-ws surface unreachable from the public internet — the proxy is the only path in. - `--public-base-url` set to the *externally* reachable URL, including the scheme. -- `--bootstrap-admin-password` rotated immediately after first login (Users page → reset password). +- `--bootstrap-admin-password` rotated immediately after first login (Users page → reset password, or via the admin's own "My profile" page). - `--key` / `id_ed25519` not committed to source control. Treat the private key as a deploy secret. - Audit retention (`--audit-retention-days`) set to a value that matches your data-retention policy. -- If running behind a reverse proxy: forward the original `Host:` header so OIDC redirect-URI validation matches. +- If running behind a reverse proxy: forward the original `Host:` header so OIDC redirect-URI validation matches, and forward `X-Forwarded-Proto: https` so the dashboard generates `wss://` URLs.