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.
Bringing your own server?
Three values, only if you run hbbs/hbbr yourself
Skip this entirely with the embedded server — the key pair is generated and
wired up on first boot. Set CORTENDESK_EMBEDDED_SERVER=false and
supply these to use servers you already run:
| Value | Looks like | Where it comes from |
|---|---|---|
| ID server | hbbs.example.com:21116 | Your hbbs host and port |
| Relay server | hbbs.example.com:21117 | Your hbbr host and port |
| Public key | base64… | Contents of id_ed25519.pub on the server |
Step 2 · quick trial
One container, SQLite
Enough to evaluate. No database to set up.
# Pull and run
docker run -d --name cortendesk \
-p 8080:8080 \
-v cortendesk-data:/data \
-e CORTENDESK_ID_SERVER=hbbs.example.com:21116 \
-e CORTENDESK_RELAY_SERVER=hbbs.example.com:21117 \
-e CORTENDESK_PUBLIC_KEY="<contents of id_ed25519.pub>" \
ghcr.io/marcpope/cortendesk
Open http://localhost:8080 and sign in as admin / changeme.
Change that password immediately.
/data volume. It holds the generated APP_KEY, and
without it the encrypted values in your database — SMTP password, SSO client secret,
2FA secrets — cannot be decrypted, even from a good backup.
Step 2 · production
Compose, with MySQL
services:
cortendesk:
image: ghcr.io/marcpope/cortendesk
ports:
- "8080:8080"
environment:
APP_URL: https://console.example.com
SESSION_SECURE_COOKIE: "true"
DB_CONNECTION: mysql
DB_HOST: db
DB_DATABASE: cortendesk
DB_USERNAME: cortendesk
DB_PASSWORD: use-a-real-password
CORTENDESK_ID_SERVER: hbbs.example.com:21116
CORTENDESK_RELAY_SERVER: hbbs.example.com:21117
CORTENDESK_PUBLIC_KEY: "<contents of id_ed25519.pub>"
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.
Step 3
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 4
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.
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.