Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ sciter.dll
src/bridge_generated.rs
src/bridge_generated.io.rs
*deb
rustdesk
/rustdesk
*.cache
# appimage
appimage/AppDir
Expand Down Expand Up @@ -67,3 +67,5 @@ core
flutter/core
# playwright testing artifacts
.playwright-mcp/
# helm local overrides (contain private config)
deploy/helm/*/values-*.yaml
18 changes: 9 additions & 9 deletions docker/web-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ docker run -d -p 8080:80 \
ghcr.io/rophy/rustdesk/web-client
```

The web client defaults to same-origin WebSocket paths `/hbbs` and `/hbbr`, with `ws://` or `wss://` selected automatically based on the page protocol. No host configuration needed.
The web client defaults to same-origin WebSocket paths `/ws/id` and `/ws/relay`, with `ws://` or `wss://` selected automatically based on the page protocol. No host configuration needed.

For split-domain deployments (hbbs/hbbr on a different host):

Expand All @@ -26,8 +26,8 @@ docker run -d -p 8080:80 \

# Secure WebSocket via TLS-terminating proxy
docker run -d -p 8080:80 \
-e RUSTDESK_HOST=wss://hbbs.example.com/hbbs \
-e RUSTDESK_RELAY=wss://hbbr.example.com/hbbr \
-e RUSTDESK_HOST=wss://rustdesk.example.com/ws/id \
-e RUSTDESK_RELAY=wss://rustdesk.example.com/ws/relay \
-e RUSTDESK_KEY=your-public-key \
ghcr.io/rophy/rustdesk/web-client
```
Expand All @@ -39,8 +39,8 @@ Then open http://localhost:8080 in a browser.
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `RUSTDESK_KEY` | **Yes** | | Server public key |
| `RUSTDESK_HOST` | No | `/hbbs` | Rendezvous server (hbbs). Path (e.g. `/hbbs`) or full URI (e.g. `ws://host:21118`) |
| `RUSTDESK_RELAY` | No | `/hbbr` | Relay server (hbbr). Path (e.g. `/hbbr`) or full URI (e.g. `ws://host:21119`) |
| `RUSTDESK_HOST` | No | `/ws/id` | Rendezvous server (hbbs). Path (e.g. `/ws/id`) or full URI (e.g. `ws://host:21118`) |
| `RUSTDESK_RELAY` | No | `/ws/relay` | Relay server (hbbr). Path (e.g. `/ws/relay`) or full URI (e.g. `ws://host:21119`) |

When `RUSTDESK_HOST` or `RUSTDESK_RELAY` is a path (starts with `/`), the WebSocket scheme is derived from the page: `wss://` on HTTPS, `ws://` on HTTP. Full URIs are used as-is.

Expand All @@ -50,22 +50,22 @@ The proxy must route WebSocket connections to hbbs/hbbr:

| Path | Backend | Protocol |
|------|---------|----------|
| `/hbbs` | hbbs:21118 | WebSocket |
| `/hbbr` | hbbr:21119 | WebSocket |
| `/ws/id` | hbbs:21118 | WebSocket |
| `/ws/relay` | hbbr:21119 | WebSocket |
| `/` | web-client:80 | HTTP |

The proxy should terminate TLS and support WebSocket upgrade. Example with nginx:

```nginx
location /hbbs {
location /ws/id {
proxy_pass http://hbbs:21118;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}

location /hbbr {
location /ws/relay {
proxy_pass http://hbbr:21119;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
Expand Down
46 changes: 23 additions & 23 deletions flutter/web/js/src/url.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ describe("resolveUri", () => {
value: { protocol: "https:", host: "rustdesk.corp.com" },
writable: true,
});
expect(resolveUri("/hbbs")).toBe("wss://rustdesk.corp.com/hbbs");
expect(resolveUri("/hbbr")).toBe("wss://rustdesk.corp.com/hbbr");
expect(resolveUri("/ws/id")).toBe("wss://rustdesk.corp.com/ws/id");
expect(resolveUri("/ws/relay")).toBe("wss://rustdesk.corp.com/ws/relay");
});

it("resolves path to ws:// on HTTP page", () => {
(globalThis as any).location = { protocol: "http:", host: "localhost:8080" };
expect(resolveUri("/hbbs")).toBe("ws://localhost:8080/hbbs");
expect(resolveUri("/ws/id")).toBe("ws://localhost:8080/ws/id");
});

it("returns full URI as-is", () => {
expect(resolveUri("wss://example.com/hbbs")).toBe("wss://example.com/hbbs");
expect(resolveUri("wss://example.com/ws/id")).toBe("wss://example.com/ws/id");
expect(resolveUri("ws://127.0.0.1:21118")).toBe("ws://127.0.0.1:21118");
});

Expand All @@ -28,34 +28,34 @@ describe("resolveUri", () => {

describe("getDefaultUri", () => {
beforeEach(() => {
setConfig("/hbbs", "/hbbr", "");
setConfig("/ws/id", "/ws/relay", "");
(globalThis as any).location = { protocol: "https:", host: "rustdesk.corp.com" };
});

it("defaults resolve to same-origin wss paths", () => {
expect(getDefaultUri()).toBe("wss://rustdesk.corp.com/hbbs");
expect(getDefaultUri(true)).toBe("wss://rustdesk.corp.com/hbbr");
expect(getDefaultUri()).toBe("wss://rustdesk.corp.com/ws/id");
expect(getDefaultUri(true)).toBe("wss://rustdesk.corp.com/ws/relay");
});

it("returns full wss:// host URL without modification", () => {
setConfig("wss://rustdesk.example.com/hbbs", "wss://rustdesk.example.com/hbbr", "");
expect(getDefaultUri()).toBe("wss://rustdesk.example.com/hbbs");
setConfig("wss://rustdesk.example.com/ws/id", "wss://rustdesk.example.com/ws/relay", "");
expect(getDefaultUri()).toBe("wss://rustdesk.example.com/ws/id");
});

it("returns full wss:// relay URL without modification", () => {
setConfig("wss://rustdesk.example.com/hbbs", "wss://rustdesk.example.com/hbbr", "");
expect(getDefaultUri(true)).toBe("wss://rustdesk.example.com/hbbr");
setConfig("wss://rustdesk.example.com/ws/id", "wss://rustdesk.example.com/ws/relay", "");
expect(getDefaultUri(true)).toBe("wss://rustdesk.example.com/ws/relay");
});

it("returns full ws:// URL without modification", () => {
setConfig("ws://127.0.0.1:12022/hbbs", "ws://127.0.0.1:12022/hbbr", "");
expect(getDefaultUri()).toBe("ws://127.0.0.1:12022/hbbs");
expect(getDefaultUri(true)).toBe("ws://127.0.0.1:12022/hbbr");
setConfig("ws://127.0.0.1:12022/ws/id", "ws://127.0.0.1:12022/ws/relay", "");
expect(getDefaultUri()).toBe("ws://127.0.0.1:12022/ws/id");
expect(getDefaultUri(true)).toBe("ws://127.0.0.1:12022/ws/relay");
});

it("falls back to HOST when RELAY_HOST is empty", () => {
setConfig("/hbbs", "", "");
expect(getDefaultUri(true)).toBe("wss://rustdesk.corp.com/hbbs");
setConfig("/ws/id", "", "");
expect(getDefaultUri(true)).toBe("wss://rustdesk.corp.com/ws/id");
});

it("returns relay when relay is set", () => {
Expand All @@ -82,14 +82,14 @@ describe("loadConfig", () => {
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({
host: "wss://test.example.com/hbbs",
relay: "wss://test.example.com/hbbr",
host: "wss://test.example.com/ws/id",
relay: "wss://test.example.com/ws/relay",
key: "testkey123",
}),
});
await loadConfig();
expect(getHost()).toBe("wss://test.example.com/hbbs");
expect(getRelayHost()).toBe("wss://test.example.com/hbbr");
expect(getHost()).toBe("wss://test.example.com/ws/id");
expect(getRelayHost()).toBe("wss://test.example.com/ws/relay");
expect(getConfigKey()).toBe("testkey123");
});

Expand Down Expand Up @@ -122,10 +122,10 @@ describe("loadConfig", () => {
(globalThis as any).location = { protocol: "https:", host: "myapp.com" };
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ host: "/hbbs", relay: "/hbbr", key: "k1" }),
json: () => Promise.resolve({ host: "/ws/id", relay: "/ws/relay", key: "k1" }),
});
await loadConfig();
expect(getDefaultUri()).toBe("wss://myapp.com/hbbs");
expect(getDefaultUri(true)).toBe("wss://myapp.com/hbbr");
expect(getDefaultUri()).toBe("wss://myapp.com/ws/id");
expect(getDefaultUri(true)).toBe("wss://myapp.com/ws/relay");
});
});
4 changes: 2 additions & 2 deletions flutter/web/js/src/url.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
let HOST = "/hbbs";
let RELAY_HOST = "/hbbr";
let HOST = "/ws/id";
let RELAY_HOST = "/ws/relay";
let CONFIG_KEY = "";

export function setConfig(host: string, relay: string, key: string) {
Expand Down
Loading