diff --git a/docs/management.md b/docs/management.md index 5a7c782..0a3030b 100644 --- a/docs/management.md +++ b/docs/management.md @@ -1,8 +1,8 @@ # Console management integration -The opt-in `/v1` HTTP API is independent of RustDesk's client protocol ports. Set `RD_MANAGEMENT_BIND` to a private socket address, `RD_MANAGEMENT_TOKEN` to an independent random Bearer credential of at least 32 characters, and `RD_MANAGEMENT_DIR` to a persistent directory for management state. Do not publish this listener to the client-facing network. +The opt-in `/v1` HTTP API is independent of RustDesk's client protocol ports and is served by hbbs only. Set `RD_MANAGEMENT_BIND` to a private socket address, `RD_MANAGEMENT_TOKEN` to an independent random Bearer credential of at least 32 characters, and `RD_MANAGEMENT_DIR` to a persistent directory for management state. Do not publish this listener to the client-facing network. -hbbs exposes `GET /v1/status`, `GET /v1/config`, `PUT /v1/config`, `GET /v1/logs`, `GET /v1/peers`, `GET/PUT /v1/bans`, `POST /v1/restart`, `GET /v1/events` (SSE), `GET /v1/relays`, `GET /v1/relays/:id/sessions`, `DELETE /v1/relays/:id/sessions/:uuid`, `GET/PUT /v1/relays/:id/config`, `GET /v1/relays/:id/logs`, `POST /v1/relays/:id/restart` and `GET /v1/control` (WebSocket upgrade). hbbr additionally exposes `GET /v1/sessions`, `DELETE /v1/sessions/:uuid` and `POST /v1/restart`; it has no peers endpoint. All endpoints require authorization. API version is 1. Session closure is asynchronous (`202`, `state: closing`). IP bans check both relay endpoints. Reported target IDs are not authenticated source identities. +hbbs exposes `GET /v1/status`, `GET /v1/config`, `PUT /v1/config`, `GET /v1/logs`, `GET /v1/peers`, `GET/PUT /v1/bans`, `POST /v1/restart`, `GET /v1/events` (SSE), `GET /v1/relays`, `GET /v1/relays/:id/sessions`, `DELETE /v1/relays/:id/sessions/:uuid`, `GET/PUT /v1/relays/:id/config`, `GET /v1/relays/:id/logs`, `POST /v1/relays/:id/restart` and `GET /v1/control` (WebSocket upgrade). hbbr exposes no HTTP listener; it is managed entirely through the hbbs control channel. All endpoints require authorization. API version is 1. Session closure is asynchronous (`202`, `state: closing`). IP bans check both relay endpoints. Reported target IDs are not authenticated source identities. Relay aggregation: when `RD_HBBS_API_URL` is set on hbbr, it opens an outbound WebSocket to the hbbs management API (`/v1/control`), registers with its relay identity and reports heartbeats, session lifecycle events and session snapshots. hbbs fans the active ban policy out to every registered relay (on update and on registration), aggregates relay sessions behind `GET /v1/relays/:id/sessions`, forwards disconnect requests through `DELETE /v1/relays/:id/sessions/:uuid`, proxies relay-scoped management requests (`GET/PUT /v1/relays/:id/config`, `GET /v1/relays/:id/logs`, `POST /v1/relays/:id/restart`) over the control channel using request ids and HTTP-equivalent responses (a relay that stays silent fails the proxy request after 10 seconds), and folds each relay address reported at registration into the live relay server list (static `relay-servers` plus registered relays; dynamic `relay-servers` updates replace the static baseline and keep the registered addresses). hbbr identity comes from `RD_RELAY_ID` (or `HOSTNAME`); `RD_RELAY_ADDRESS` optionally advertises the address clients use to reach the relay and is folded into the live relay server list only when set — the relay id (often a container hostname) is never broadcast as an address. A re-registering relay replaces its previous connection, and registrations silent for 45 seconds are dropped. `GET /v1/events` streams aggregated events (`peer_online`, `peer_offline`, `session_opened`, `session_closed`, `relay_registered`, `relay_disconnected`, `bans_replaced`) as server-sent events with a 15 second keep-alive. @@ -12,8 +12,8 @@ Files are service-specific: `hbbs-config.json`, `hbbr-config.json`, `hbbs-bans.j `GET /v1/logs?tail=N` returns up to 2000 recent in-memory log lines (default 200) captured from the standard log format; it requires no container log access. `GET /v1/relays/:id/logs` proxies the same read for a registered relay. -`POST /v1/restart` (directly on each service and proxied per relay) asks the supervisor to bring the service back: the process exits shortly after the response is flushed (`202`, `state: restarting`), and the persisted configuration including pending-restart entries is applied on the next startup. Relay restarts are fire-and-forget: the relay acknowledges, exits and drops off the control channel, and registers again once it is back. +`POST /v1/restart` (on hbbs and proxied per relay) asks the supervisor to bring the service back: the process exits shortly after the response is flushed (`202`, `state: restarting`), and the persisted configuration including pending-restart entries is applied on the next startup. Relay restarts are fire-and-forget: the relay acknowledges, exits and drops off the control channel, and registers again once it is back. Managed settings override startup inputs. Schema and validation are provided by `management-schema.json`. The API returns key placeholders, never the private key. It exposes only `id_ed25519.pub` as the public key. -The published `databk/rustdesk-server` image ships hbbs and hbbr with the management API compiled in; deploy each binary as its own container (for example through the Console repository's Compose `server` profile) and set `RD_MANAGEMENT_BIND` to enable the listener. The Console repository supplies the combined Compose deployment, permission enforcement, UI, integration workflow and detailed lifecycle documentation in `docs/server-management.md`. Existing binaries remain compatible with deployments that do not enable management. +The published `databk/rustdesk-server` image ships hbbs and hbbr with the management API compiled in; deploy each binary as its own container (for example through the Console repository's Compose `server` profile), set `RD_MANAGEMENT_BIND` on hbbs to enable its listener, and set `RD_HBBS_API_URL` on hbbr so it registers on the control channel. The Console repository supplies the combined Compose deployment, permission enforcement, UI, integration workflow and detailed lifecycle documentation in `docs/server-management.md`. Existing binaries remain compatible with deployments that do not enable management. diff --git a/src/management.rs b/src/management.rs index cf54906..2edcb7b 100644 --- a/src/management.rs +++ b/src/management.rs @@ -740,23 +740,6 @@ async fn peers(Extension(state): Extension) -> Response { Json(json!({"data":PEERS.read().unwrap().clone()})).into_response() } -async fn sessions(Extension(state): Extension) -> Response { - if state.service != "hbbr" { - return StatusCode::NOT_FOUND.into_response(); - } - Json(json!({"data":sessions_snapshot()})).into_response() -} - -async fn disconnect(Extension(state): Extension, Path(uuid): Path) -> Response { - if state.service != "hbbr" { - return StatusCode::NOT_FOUND.into_response(); - } - if disconnect_session(&uuid) { - return (StatusCode::ACCEPTED, Json(json!({"state":"closing"}))).into_response(); - } - StatusCode::NOT_FOUND.into_response() -} - async fn bans() -> Json { Json(BANS.read().unwrap().clone()) } @@ -1262,8 +1245,6 @@ fn router(state: ApiState) -> Router { .route("/v1/config", get(config).put(replace_config)) .route("/v1/logs", get(logs)) .route("/v1/peers", get(peers)) - .route("/v1/sessions", get(sessions)) - .route("/v1/sessions/:uuid", axum::routing::delete(disconnect)) .route("/v1/bans", get(bans).put(replace_bans)) .route("/v1/restart", axum::routing::post(restart)) .route("/v1/events", get(events)) diff --git a/src/relay_server/server.rs b/src/relay_server/server.rs index 78f8478..779caeb 100644 --- a/src/relay_server/server.rs +++ b/src/relay_server/server.rs @@ -55,10 +55,9 @@ pub async fn start_with_bind(bind_addr: Option, port: &str, key: &str) - // of being reported as pending restart. crate::management::set_dynamic_apply(Box::new(command::apply_dynamic)); // The managed state backs the control channel's proxied - // configuration requests even when no local listener is - // bound, so initialize it unconditionally. + // configuration requests; hbbr never exposes a local + // management listener and is aggregated through hbbs only. crate::management::init_managed_state("hbbr", port)?; - crate::management::start("hbbr", port)?; let control_url = std::env::var("RD_HBBS_API_URL").unwrap_or_default(); if !control_url.is_empty() { let token = std::env::var("RD_MANAGEMENT_TOKEN").unwrap_or_default();