Install
Up and running
Since 1.5 the image contains the RustDesk server — ID server, relay and console in one container. Nothing to set up first.
Already running hbbs/hbbr?
Move them into the container
Running separate RustDesk servers next to CortenDesk is no longer the
recommended setup. The bundled server is
CortenDesk Server, our
fork of the open-source server with the signalling key exchange that
signed-in clients 1.4.1 and newer require. Against stock
hbbs, those clients fail with Failed to secure tcp.
Migrating keeps your key pair, device IDs and peer database, so no client needs reconfiguring. Four steps:
- Find the
hbbsdata directory, the one holdingid_ed25519,id_ed25519.pubanddb_v2.sqlite3. Back it up.id_ed25519cannot be regenerated without locking every client out. - Stop the old
hbbsandhbbrcontainers. They hold the ports CortenDesk is about to take. - Mount that directory at
/data/rustdeskin the CortenDesk container, publish the server ports, and removeCORTENDESK_ID_SERVER,CORTENDESK_RELAY_SERVERandCORTENDESK_PUBLIC_KEY.APP_URLnow supplies all three. - Start it and watch the log for
Private key comes from id_ed25519. That line means your key was adopted. If you seegenerated the server key pairinstead, the mount is wrong. Fix it before any client connects.
services:
cortendesk:
image: ghcr.io/marcpope/cortendesk
environment:
APP_URL: https://rd.example.com # the address CLIENTS reach
ports:
- "8080:8080"
- "21115:21115"
- "21116:21116"
- "21116:21116/udp"
- "21117:21117"
volumes:
- cortendesk-data:/data
- /home/you/rustdesk/data:/data/rustdesk # the old hbbs data
Devices come back online within a heartbeat. The full walkthrough, including rollback, is in Upgrading to 1.5.
CORTENDESK_EMBEDDED_SERVER=false and supply
CORTENDESK_ID_SERVER, CORTENDESK_RELAY_SERVER and
CORTENDESK_PUBLIC_KEY (the contents of id_ed25519.pub, pasted
with no surrounding whitespace; a trailing newline fails like a wrong key). Run
those servers on the
CortenDesk Server image,
not the stock one, or signed-in clients cannot connect.
Step 1
Compose, with MySQL
One stack: the console with its bundled ID server and relay, and a MySQL database. MariaDB works the same way.
services:
cortendesk:
image: ghcr.io/marcpope/cortendesk
ports:
- "8080:8080"
- "21115:21115"
- "21116:21116"
- "21116:21116/udp"
- "21117:21117"
environment:
APP_URL: https://console.example.com # the address CLIENTS reach
SESSION_SECURE_COOKIE: "true"
DB_CONNECTION: mysql
DB_HOST: db
DB_DATABASE: cortendesk
DB_USERNAME: cortendesk
DB_PASSWORD: use-a-real-password
volumes:
- cortendesk-data:/data
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: cortendesk
MYSQL_USER: cortendesk
MYSQL_PASSWORD: use-a-real-password
MYSQL_RANDOM_ROOT_PASSWORD: "1"
volumes:
- cortendesk-db:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s
timeout: 3s
retries: 20
restart: unless-stopped
volumes:
cortendesk-data:
cortendesk-db:
docker compose up -d
The entrypoint waits for the database, runs migrations, creates the first administrator and rebuilds every cache on boot. Upgrading is a new image tag and a restart.
Open http://localhost:8080 and sign in as admin / changeme.
Change that password immediately.
APP_URL has to be the address your clients reach, not
localhost. The ID server, the relay address handed to clients and the
public key are all derived from it, and a key pair is generated on first boot.
/data volume. It holds the generated APP_KEY and
the server key pair. Without the first, the encrypted values in your database — SMTP
password, SSO client secret, 2FA secrets — cannot be decrypted, even from a good
backup. Without the second, every client is locked out.
Step 2
Put TLS in front
The container serves plain HTTP on 8080 and expects a TLS-terminating proxy. With Caddy that is three lines:
console.example.com {
reverse_proxy localhost:8080
}
Set APP_URL to the public HTTPS address and
SESSION_SECURE_COOKIE=true. Traefik and nginx examples, plus the
trusted-proxy settings that keep client IPs accurate, are in the
reverse proxy guide.
Step 3
Point your clients at it
In a normal RustDesk client: Settings → Network. Set ID Server, Relay Server, Key, and set API Server to your console URL. The console's Settings screen shows all four ready to copy, including the generated key.
Devices appear within one heartbeat, about fifteen seconds.
--assign flag to place a machine in the right folder, with the right
owner and policy, on first run.
Prefer to install it without Docker?
It is a standard Laravel deployment — PHP 8.4, MySQL or MariaDB, nginx and php-fpm.