-
Notifications
You must be signed in to change notification settings - Fork 2
Troubleshooting
English | 简体中文
Diagnose one layer at a time: configuration, process, network, TLS/proxy, registration, Relay allocation, and finally desktop data. Preserve the first specific error and its timestamp; later reconnect attempts often add noise.
Run read-only checks before changing images, keys, firewall rules, or clients:
docker compose --env-file .env -f compose.yaml config --quiet
docker compose --env-file .env -f compose.yaml ps
docker compose --env-file .env -f compose.yaml logs --since 15m hbbs hbbr
docker inspect rustdesk-starry-hbbs --format '{{json .State.Health}}'
ss -lntup | grep -E ':(21115|21116|21117|21118|21119)\b'If WebSocket is involved, validate Nginx and inspect authenticated Control
Agent GET /control/v1/status:
sudo nginx -tRecord the exact image tag/digest, config hash, client versions, both clients' public networks, whether each client has WebSocket enabled, and the same connection attempt's timestamps. Redact secrets before sharing output.
- Read the first HBBS error, not only the health-check result.
- Verify the bind source exists and is writable by the container.
- Check whether another HBBS already owns
21115,21116, or21118on the host network. - Confirm
id_ed25519andid_ed25519.pubare non-empty and a matching pair. - Render Compose with the same
.envactually used to start it.
The health check proves a key exists and local 21116/TCP accepts a
connection. It cannot prove public routing or client registration.
Starry rejects the complete candidate configuration when one field is unknown, duplicated, out of range, or inconsistent. It then keeps upstream-compatible behaviour instead of partially applying the file.
For an initial unmanaged deployment, restart HBBS and inspect the validation log. Managed deployments should use Control Agent validation and reload:
docker restart rustdesk-starry-hbbs
docker logs --tail 200 rustdesk-starry-hbbsFix the exact reported field. Do not delete unrelated sections at random. A
schema version: 1 file must not contain websocket_signal; use version: 2
for that section.
Work from the client towards HBBS:
- ID Server must resolve to the intended HBBS and expose
21116/TCPplus21116/UDPfor the native path. - The client public key must exactly match
id_ed25519.pub; remove whitespace introduced by copy/paste. - API Server is not the ID Server. A successful website/API response says nothing about native HBBS reachability.
- Check client time and server time when TLS or token expiry is involved.
- Test from a different network to distinguish a local firewall from a server problem.
If only TCP is open, failure of native controlled-endpoint registration is
expected with official 1.1.16: RegisterPk and heartbeats use UDP, and the TCP
listener returns NOT_SUPPORT for that registration message. This is separate
from an authenticated controller initiation over TCP/Secure TCP. Where UDP
cannot be opened, verify WSS /ws/id and /ws/relay instead of treating the
native registration failure as a JWT denial.
Do not regenerate server keys as a connectivity experiment. That changes the identity for every client.
Treat these as separate layers:
- API authentication and account data;
- native HBBS
21116/TCPsignalling, including Secure TCP when negotiated; - P2P or HBBR data transport.
Confirm the client ID Server and public key, then correlate HBBS handshake logs.
If the session needs Relay, separately confirm 21117/TCP and the selected
HBBR logs. Changing an API session_id or reverse-proxy route cannot repair a
failed native HBBS handshake.
Check in this order:
- the Starry config was accepted and
secure_tcp.modeisauto; - the client uses the correct HBBS public key;
-
21116/TCPreaches Starry HBBS rather than an old or duplicate process; - client and server versions/logs refer to the same attempt; and
- no L4 proxy is truncating or rewriting the connection.
Secure TCP is native HBBS signalling, not WSS and not API HTTPS. Do not disable certificate checks or change HBBR to diagnose this layer.
Check the precedence chain:
- the client Relay Server field is empty;
- HBBS observes the public IPs you tested;
- the required MMDB is loaded and contains the expected record;
- the specific rule precedes the catch-all;
-
symmetricmatches the intended direction; - the Relay spelling equals a
relay_serversitem; and - the preferred Relay is eligible for the requested transport.
Remember that Relay lists are strict priority. Repeated selection of the first healthy Relay is expected and is not failed load balancing.
An empty result means no Relay is eligible after transport filtering. It can result from:
- no native-online Relay for
native; - no certificate-valid healthy endpoint for
wss; - no Relay that is both native-online and WSS-healthy for
mixed; - a matching rule whose Relays are unavailable plus no usable later rule; or
- an empty effective Relay pool.
Compare authenticated GET /control/v1/relays, GET /control/v1/status, and
all three POST /control/v1/allocations:simulate transport modes. Use the
authenticated plan/apply or runtime-reload operation after changing Relay,
WebSocket, or general schema fields.
Inspect the configured URL from the server without printing credentials. Common
causes include an HTML login/licence page, expired signed URL, TLS interception,
file smaller than minimum_bytes, missing MaxMind marker, or a database that
does not support the requested record type.
Starry retains the last readable database when replacement validation fails.
Confirm the file timestamp and startup/reload message before assuming fresh
data is active. force_update: true is a temporary recovery tool, not a normal
permanent setting.
| Response | Typical interpretation |
|---|---|
404 |
Wrong hostname/path, non-exact Nginx location, or request reached a different virtual host. |
400 |
Upgrade headers or HTTP/1.1 missing, invalid Origin, or direct backend request is malformed. |
502 |
Nginx cannot reach 127.0.0.1:21118 for /ws/id or 127.0.0.1:21119 for /ws/relay. |
Verify exact paths, backend listeners, Nginx error logs, and proxy_http_version 1.1. Do not append a slash, query, or different path to a configured health
endpoint.
101 proves only HTTP Upgrade. Continue at the RustDesk protocol layer:
- confirm schema v2 or v3 and
websocket_signal.enabled: truewere accepted; - verify the client uses
/ws/idthrough the intended ID Server hostname; - inspect registration and routing logs after Upgrade;
- confirm a certificate-valid
/ws/relayendpoint is healthy; - ensure a common eligible Relay exists for mixed sessions; and
- correlate both clients and HBBR for the same attempt.
If Upgrade succeeds but registration fails, changing DNS or TLS repeatedly will not address the protocol error.
HBBS trusts forwarded IP headers only when the direct peer is in
trusted_proxies. Find the source address HBBS actually sees. Add the smallest
correct proxy CIDR; never trust all addresses.
If a client sends Origin, it must exactly equal an item in allowed_origins.
An empty list rejects all Origin-bearing requests while native clients without
that header remain accepted. Scheme, host, and port are part of the origin;
paths, credentials, queries, and fragments are not valid entries.
Native HBBR online state and WSS endpoint health are deliberately different.
For the Relay hostname in websocket-status, verify DNS, public port 443,
certificate chain, hostname/SNI, exact /ws/relay, Nginx-to-21119 reachability,
and success/failure thresholds. Ping and a normal HTTPS 200 are insufficient.
Mixed requires the same Relay name to be both native-online and WSS-healthy. Check that:
-
relay_serversandrelay_health.endpoints[].relayuse identicalhost:21117values; - the bundled unmodified HBBR reports that value online;
- its WSS endpoint is healthy in the current configuration generation; and
- the Geo rule lists that Relay.
Do not solve this by mapping native and WSS names for different physical nodes; they must describe one HBBR service reachable by both paths.
First determine P2P versus Relay from client and server logs. For Relay sessions, identify the Relay UUID/session and correlate both legs. Then measure client-to- Relay latency, packet loss, throughput, CPU, memory, and host/network shaping.
A lower geographic distance is not guaranteed lower latency. Use real measurements to adjust ordered rules. Restart or reload only the component whose state actually changed, then repeat the same controlled transfer.
Read configured_mode, effective_mode, verifier_state, key age, and metric
deltas from Control Agent status. --must-login can make effective mode
enforce even when the document says audit/off. A local claim/signature error
must not call introspection; an otherwise valid request does call a configured
introspection service and fails closed on timeout, TLS, 5xx, malformed, or
inactive responses.
Check exact typ=at+jwt, issuer/audience/token-use/scope, sub == user_id, clock sync,
explicit kid, Ed25519 public key rotation overlap, JWKS staleness, client
token placement, request kind, and transport. Never paste the raw token into a
ticket. Return enforce to audit through a local acknowledged reload if
legitimate clients regress; do not create a remote bypass.
A JWKS server with a shorter idle timeout can make stale pooled keep-alive
connections look like intermittent refresh failures. patch-v1.2.0 limits the
internal mTLS HTTP pool idle lifetime to 15 seconds. If failures continue,
correlate Starry refresh logs with the Kessoku idle timeout, certificate chain,
server name, and key_age_seconds; do not hide a persistent fault by only
increasing max_stale_seconds.
Separate TLS handshake, URI-SAN allowlist, service-JWT audience/azp/scope, and
local HBBS connectivity. A 404 for write endpoints is expected when
write_enabled: false. ETag/plan/idempotency conflicts are deliberate
concurrency protection, not retry-without-preconditions errors.
If an operation enters manual_intervention_required, stop retries. Preserve
the state/audit/recovery directories, compare exact managed config bytes and
HBBS runtime generation/digests, restore the reviewed last-known-good file, and
perform a local acknowledged reload. Follow the
Control Agent recovery runbook;
deleting state to clear the block destroys required evidence.
Stop rollout when the first reproducible protocol regression appears. Preserve the new and old image digests, config, and logs. If safe, disable only the new feature first; otherwise restore the previous immutable tag and configuration according to Upgrade and Rollback.
Do not overwrite the data directory with an empty backup or regenerate keys.
- Documentation home
- Getting started
- Docker image usage
- Docker deployment
- Native deployment
- Multi-node deployment
- Reverse proxy and TLS
- Client configuration
- Account/API integration
- Configuration reference
- Connection authentication
- Control Agent
- GEO rules: basics
- GEO rules: advanced
- Operations and verification
- Troubleshooting
- Upgrade and rollback
- Architecture and build
- 文档主页
- 快速开始
- Docker 镜像使用
- Docker 部署
- 原生部署
- 中心与 Relay 多节点部署
- 反向代理与 TLS
- 客户端配置
- 账户与 API 服务接入
- 配置参数详解
- 连接认证
- Control Agent
- Geo 规则:入门
- Geo 规则:进阶
- 运维与完整验证
- 常见问题排查
- 版本升级与回滚
- 架构与构建