Skip to content

Troubleshooting

Marc Pope edited this page Oct 8, 2026 · 5 revisions

Troubleshooting

Grouped by symptom. Most reports come down to one of the first three.

No devices appear

Almost always the client's API Server setting, not CortenDesk.

  1. On the client: Settings → Network. API Server must be the console URL, including scheme and port — the same address you open in a browser.
  2. The client must be able to reach it. Test from the machine itself.
  3. Wait one heartbeat, about 15 seconds.

If devices still do not appear:

  • Is the approval gate on? With Settings → Server → require device approval enabled, new devices land in a pending tab and are invisible until approved. This looks exactly like nothing happening.
  • Was the device deleted? A device in the recycle bin has its heartbeats deliberately ignored, so it will never come back on its own. Restore it.
  • Key mismatch. A public key with a stray trailing newline or space fails exactly like a wrong key. Re-paste it with no surrounding whitespace.

Connections work signed out and fail signed in

Symptom: the client connects fine to any ID while signed out. Sign in to use the address book and every connection fails after about 18 seconds with

Failed to secure tcp: deadline has elapsed

The devices stay online in the console the whole time, and the address book loads normally. Only connecting from the signed-in client breaks.

Cause: the ID server. Clients from 1.4.1 onwards encrypt their connection to the ID server whenever they hold a console access token, and they begin by waiting for the server to send a signed key. The open-source RustDesk hbbs never sends one, so the client waits and gives up. Signed out there is no token, no encryption, and no problem — which is what makes it look like the address book is at fault when it is not.

Fix: run CortenDesk Server for hbbs and hbbr. It answers the exchange. Same binaries, ports, flags and data files, so switching is a change of image and a restart, and every device keeps its ID and key.

Workaround, if you cannot change the server right now: turn on Settings → Network → Use WebSocket on the machine you connect from. Clients skip the exchange on that transport. It needs ports 21118 and 21119 reachable, and it routes sessions through the relay rather than direct.

Signing out also "works", at the cost of the address book. It is worth knowing as a diagnostic — if signing out fixes it, this is what you are looking at.

Devices flicker between online and offline

Raise Settings → Server → online window (default 60 seconds). A device counts as offline once its last heartbeat is older than that, so lossy links can make devices appear to bounce.

Web client will not connect

Work through these in order.

  1. Do the WebSocket URLs match the page's scheme? CORTENDESK_WS_ID_URL and CORTENDESK_WS_RELAY_URL must be reachable from the browser, not from the container, and must be wss:// on an HTTPS console — a browser refuses ws:// from an HTTPS page as mixed content. Over plain HTTP, use ws://. HTTPS itself is not required; see Web client and HTTPS.
  2. Is the proxy reachable from the browser? See Reverse proxy and TLS.
  3. Does your proxy forward WebSocket upgrades on /ws/id and /ws/relay?
  4. Check the browser console for a mixed-content or upgrade error — it names the failure directly.
  5. Browser support. The stream requires WebCodecs; use Chrome or Edge.

Testing WebSocket endpoints with curl over HTTPS is misleading. curl negotiates HTTP/2, where the Upgrade header has no meaning, so a perfectly healthy endpoint reports 502 or times out. Use openssl s_client and look for 101 Switching Protocols.

Cannot sign in

  • 2FA device lost — php artisan cortendesk:2fa-reset <username>
  • Emailed sign-in codes required but mail is broken — php artisan cortendesk:email-verification off
  • Password sign-in hidden and the identity provider is down — set CORTENDESK_OIDC_DISABLED=true in the environment and restart. Note that a broken-but-still-configured provider does not restore the password form on its own.
  • Locked out by repeated failures — the sign-in limiter is per account and per address, and clears on its own within a minute.

See the command-line reference.

Sign-in redirects back to the login page over HTTPS

Make sure APP_URL uses https:// and your proxy sends X-Forwarded-Proto.

419 Page Expired when signing in over HTTP

SESSION_SECURE_COOKIE=true makes the browser drop the session cookie on plain HTTP. Remove it, or use the https:// address. Left unset, cookies are Secure on HTTPS requests and HTTP on the LAN still signs in.

Email is not sending

Use the test send in Settings → Email — it reports the provider's own error, which is usually conclusive. The two common causes:

  • the from address is not one your relay permits, or
  • credentials or encryption mode do not match what the relay expects.

Everyone appears to come from the same IP address

Your reverse proxy is not trusted, so the app records the proxy's address instead of the real client's.

The default already trusts loopback and every private range (127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16), which covers a proxy on the same host or a Docker bridge. So you normally hit this in one of two situations:

  • Your proxy reaches the app from a public address — Cloudflare, or an external load balancer. Add its ranges to TRUSTED_PROXIES.
  • You set TRUSTED_PROXIES yourself and left out the range your proxy actually arrives from.

Note that TRUSTED_PROXIES must be read at config-cache time, so set it as an environment variable before the app starts rather than expecting a later change to be picked up.

Left unfixed this is worse than a cosmetic issue: device last_online_ip is wrong, and the per-address sign-in limiter treats every user as one address and starts locking people out. See Reverse proxy and TLS.

Sessions stay "active" forever

Sessions from machines that rebooted, dropped off the network or had their service stopped are closed by a scheduled sweep. If they accumulate, the scheduler is not running.

Docker runs it automatically. A manual install needs the cron entry:

* * * * * cd /path/to/cortendesk && php artisan schedule:run >> /dev/null 2>&1

The same cron entry drives log pruning, so if logs are also growing without bound, this is the cause.

Scheduled tasks stopped on a manual install

Notifications stop, sessions stay open and Diagnostics shows no fresh scheduler heartbeat, even though the cron entry runs. On releases before 1.10.1 this happens when PHP has pcntl_signal in disable_functions, which many hosting panels set: each task ran once and then stayed locked for 24 hours. Upgrade to 1.10.1 or later, then clear the stuck locks once:

php artisan schedule:clear-cache

Logs grow forever

Retention is 0, which means keep everything, or the scheduler is not running. See above and Audit logs.

Every session appears three times

RustDesk 1.5.0 clients with a console before 1.11.0 stored each connection, file transfer and alarm three times, and the copies stayed on the dashboard as active sessions. Upgrade to 1.11.0, then remove the copies with cortendesk:dedupe-audits.

Console slow or unreachable with many devices

Requests queue when every PHP worker is busy, and nginx refuses connections when it runs out of open files. The Docker image sizes both for larger fleets since 1.11.0; see sizing in Docker and on a VM. Look for server reached pm.max_children setting or Too many open files in the log.

Console link: policy pull failed in the log

Console link: policy pull failed, keeping the last policy: ... Connection refused ...
Console link: reachable again

Right after the container starts this is harmless. hbbs asks the console for the server access policy every few seconds and started before the console was answering. When reachable again follows, the link works.

If it does not follow:

  • HTTP 401: the console and hbbs have different CORTENDESK_SERVER_SECRET values.
  • HTTP 404: the console has no CORTENDESK_SERVER_SECRET.
  • Connection refused or a timeout that persists: CORTENDESK_CONSOLE_URL on a separate hbbs does not reach the console.

Diagnostics → ID server link shows when hbbs last fetched the policy.

Permission errors on start, or "Please provide a valid cache path"

The /data volume is not writable. Recreate it rather than fixing ownership by hand.

Still stuck

Open an issue with your install method, version, and what you have already ruled out from this page.

Clone this wiki locally