Files
mike 8ad3f43d21
build / build-linux-amd64 (push) Successful in 1m48s
ci(linux): add build workflow + Docker build instructions
2026-05-07 09:53:29 +02:00

9.6 KiB
Raw Permalink Blame History

RustDesk Server — Docker Compose Deployment

The repo ships a docker-compose.yml that builds the server from source (this fork's pro-features branch) and runs hbbs + hbbr as two containers. No prebuilt image is pulled — every docker compose build clones the configured Git URL and runs cargo build --release inside the build stage.

For the runtime flag reference (CLI options accepted by hbbs itself), see CONFIGURATION.md. This document only covers the Compose glue.


Quick start

cp .env.example .env
# edit .env — at minimum set RUSTDESK_DOMAIN, and change
# RUSTDESK_BOOTSTRAP_ADMIN_PASSWORD before the first boot
docker compose up -d --build

The bootstrap admin (default admin / changeme) is seeded into the users table on the first boot only — once the row exists, those flags are ignored. If you boot with the default password and forget to change it, rotate it via the admin UI; if you forget the password entirely, delete ./data/db_v2.sqlite3 (loses all server-side state) or edit the users row with sqlite3 directly.

First build pulls the Rust toolchain image and compiles the workspace; expect several minutes. Subsequent builds reuse the cargo cache layer unless the Git ref or build args change.

After it boots:

Endpoint Port Purpose
tcp://<domain>:21115 21115 NAT test
tcp+udp://<domain>:21116 21116 ID / rendezvous (desktop clients)
tcp://<domain>:21117 21117 Relay (hbbr)
ws://<domain>:21118 21118 Browser-facing rendezvous WebSocket
ws://<domain>:21119 21119 Browser-facing relay WebSocket
http://<domain>:21114/admin/ 21114 Admin dashboard (pro-features)
http://<domain>:21114/api/* 21114 Management API (pro-features)

Persistent state — including the auto-generated id_ed25519 keypair and the SQLite database — lives in ./data/ (bind-mounted to /root in both containers).


Files

File Role
docker-compose.yml Two services (hbbs, hbbr) sharing one image built from docker/Dockerfile.source.
docker/Dockerfile.source Multi-stage build: clones the repo, runs cargo build --release, copies binaries into a debian:bookworm-slim runtime.
.env.example Documented template; copy to .env.
data/ Created on first run. Contains keypair + SQLite DB. Back this up.

The legacy single-stage docker/Dockerfile (busybox + s6-overlay, expects prebuilt binaries) and docker-classic/Dockerfile are unrelated to this flow and unused by docker-compose.yml.


Environment variables

These are read by docker-compose.yml from .env. Compose ships them through to the container as command-line flags or environment: entries, not as raw process env (with the exception of RUST_LOG and ALWAYS_USE_RELAY, which hbbs reads from env directly).

Runtime

Variable Default Effect
RUSTDESK_DOMAIN required Public hostname clients connect to. Passed as hbbs -r ${RUSTDESK_DOMAIN}:21117.
RUSTDESK_BOOTSTRAP_ADMIN_USERNAME admin Seeded as the initial admin on first boot only (when the users table is empty). Ignored on subsequent restarts. Empty disables the bootstrap.
RUSTDESK_BOOTSTRAP_ADMIN_PASSWORD changeme Same — bcrypt-hashed at insert. Change this in .env before the first up, or rotate via the admin UI immediately after.
RUSTDESK_KEY - Pre-shared key. - = auto-generate on first boot (written to ./data/id_ed25519{,.pub}); _ = encrypted-only with auto-key; or paste a base64 public key to pin it. Applied to both hbbs and hbbr via -k.
RUSTDESK_HTTP_PORT 21114 Pro-features admin API + dashboard port. Set to 0 to disable HTTP entirely. The host port published is the same value.
RUSTDESK_ALWAYS_USE_RELAY N Force every session through the relay even on LAN. Read from env by hbbs (any non-empty/non-N value enables).
RUST_LOG info Log filter. e.g. debug, hbbs=debug,sqlx=warn.

Build source

Variable Default Effect
RUSTDESK_GIT_URL https://gitea.cstudio.ch/mike/rustdesk-server.git Repo cloned inside the builder stage.
RUSTDESK_GIT_BRANCH pro-features Branch / tag / commit to check out (--branch so it must be a ref name, not a SHA).
DATABASE_URL unset (uses the cloned repo's .env) Overrides the DATABASE_URL sqlx reads at compile time. Rarely needed — see below.

Build-arg changes only take effect when the image is rebuilt: docker compose build --no-cache hbbs (or up -d --build).


Why DATABASE_URL is a build-time concern

hbbs uses sqlx::query! macros, which verify SQL at compile time by running the queries against a real SQLite database. The repo includes a checked-in db_v2.sqlite3 with the schema pre-applied, and a tracked .env file pointing at it (DATABASE_URL=sqlite://./db_v2.sqlite3).

Cargo automatically reads .env from the project root, so cargo build inside the builder stage Just Works without any explicit configuration.

You only need to set DATABASE_URL in the Compose .env if you fork the schema or want to point the compile-time check at a different SQLite file. At runtime the binary opens its own DB under /root/ (your ./data/ bind mount) — that path is not configurable via this variable.


Adding extra hbbs flags

docker-compose.yml only wires the most common flags. To pass others (SMTP, OIDC, recording dir, audit retention, …), edit the command: block of the hbbs service. Example — enable SMTP and set the public base URL needed for OIDC callbacks:

    command: >
      hbbs
      -r ${RUSTDESK_DOMAIN:?...}:21117
      -k ${RUSTDESK_KEY:--}
      --http-port ${RUSTDESK_HTTP_PORT:-21114}
      --admin-ui-dir /opt/rustdesk/admin_ui
      --bootstrap-admin-username=${RUSTDESK_BOOTSTRAP_ADMIN_USERNAME:-}
      --bootstrap-admin-password=${RUSTDESK_BOOTSTRAP_ADMIN_PASSWORD:-}
      --public-base-url https://${RUSTDESK_DOMAIN}:${RUSTDESK_HTTP_PORT:-21114}
      --smtp-host ${SMTP_HOST}
      --smtp-user ${SMTP_USER}
      --smtp-pass ${SMTP_PASS}
      --smtp-from ${SMTP_FROM}

Then add the matching variables to .env. The full flag list lives in CONFIGURATION.md.

If you mount an oidc.toml, drop it into ./data/ and pass --oidc-config /root/oidc.toml.


Operational notes

Upgrading. Pull the latest commit on pro-features and rebuild:

docker compose build --pull --no-cache
docker compose up -d

The --pull refreshes the Rust toolchain base image; --no-cache forces a fresh git clone (otherwise Docker will reuse the cached clone layer). Alternatively, bump RUSTDESK_GIT_BRANCH to a tag and rebuild — the changed build arg invalidates the clone layer automatically.

Logs. docker compose logs -f hbbs (or hbbr). Both containers run the binary in the foreground.

Persistence. Everything that matters is in ./data/: id_ed25519{,.pub} (the server keypair — losing this invalidates every existing client) and db_v2.sqlite3 (users, address books, audit, etc.). Back up the whole directory.

TLS. The server itself speaks plain HTTP on 21114 and plain WebSocket on 21118 / 21119. Front it with nginx or Caddy for TLS — see the "TLS deployment" section in CONFIGURATION.md. When you do, set --http-listen=127.0.0.1 and --ws-listen=127.0.0.1 in the command: block so the reverse proxy can claim the public ports.

Building behind a proxy. Pass HTTP_PROXY / HTTPS_PROXY build args through Compose:

    build:
      <<: *rustdesk-build
      args:
        HTTP_PROXY: http://proxy.internal:3128
        HTTPS_PROXY: http://proxy.internal:3128

Resource hint. Cold compile takes ~35 GB of RAM for the linker step (LTO + codegen-units = 1). On a small VPS, build the image on a beefier machine, push to a registry, and pull from the VPS instead — set the image: field to a registry tag and drop the build: block.