ci(linux): add build workflow + Docker build instructions
build / build-linux-amd64 (push) Successful in 1m48s
build / build-linux-amd64 (push) Successful in 1m48s
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# Copy to .env and edit. docker-compose reads it automatically.
|
||||
|
||||
# --- Required ----------------------------------------------------------------
|
||||
|
||||
# Public domain clients connect to. hbbs advertises this as the relay address.
|
||||
RUSTDESK_DOMAIN=rd.gamecom.ch
|
||||
|
||||
# --- Bootstrap admin ---------------------------------------------------------
|
||||
# Seeded into the users table on the FIRST startup only (when users is empty).
|
||||
# Subsequent restarts ignore these — change the password via the admin UI.
|
||||
# Without these set on first boot, you'll have no way to log in.
|
||||
|
||||
RUSTDESK_BOOTSTRAP_ADMIN_USERNAME=admin
|
||||
RUSTDESK_BOOTSTRAP_ADMIN_PASSWORD=changeme
|
||||
|
||||
# --- Optional runtime --------------------------------------------------------
|
||||
|
||||
# Pre-shared key. "-" lets hbbs auto-generate on first run; "_" forces
|
||||
# encrypted-only mode without an explicit key.
|
||||
#RUSTDESK_KEY=-
|
||||
|
||||
# HTTP management API / admin UI port (pro-features). Set to 0 to disable.
|
||||
#RUSTDESK_HTTP_PORT=21114
|
||||
|
||||
# Force relay for all sessions even on LAN.
|
||||
#RUSTDESK_ALWAYS_USE_RELAY=Y
|
||||
|
||||
#RUST_LOG=info
|
||||
|
||||
# --- Optional build source ---------------------------------------------------
|
||||
# Override the upstream repo / branch the image is built from.
|
||||
|
||||
#RUSTDESK_GIT_URL=https://gitea.cstudio.ch/mike/rustdesk-server.git
|
||||
#RUSTDESK_GIT_BRANCH=pro-features
|
||||
|
||||
# --- Database connectivity ---------------------------------------------------
|
||||
DATABASE_URL=sqlite://./db_v2.sqlite3
|
||||
@@ -0,0 +1,136 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [pro-features]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version_suffix:
|
||||
description: "Version suffix (e.g. 'cst', 'beta1'). Empty = vanilla."
|
||||
type: string
|
||||
default: "cst"
|
||||
|
||||
env:
|
||||
# Cargo.lock is lockfile v4, which requires Rust >= 1.78. Upstream's
|
||||
# .github/workflows/build.yaml pins 1.90; mirror that here.
|
||||
RUST_VERSION: "1.90"
|
||||
VERSION_BASE: "1.1.15"
|
||||
VERSION_SUFFIX: ${{ inputs.version_suffix || 'cst' }}
|
||||
|
||||
jobs:
|
||||
build-amd64:
|
||||
name: build-linux-amd64
|
||||
# Same self-hosted runner as the rustdesk client build. provision.sh on the
|
||||
# host installs the Rust toolchain and devscripts/debhelper used here.
|
||||
runs-on: [self-hosted, Linux, X64, ubuntu-22.04]
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Verify host toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
required=(git bash rustc cargo rustup pkg-config debuild dh dpkg-deb)
|
||||
missing=()
|
||||
for t in "${required[@]}"; do
|
||||
if command -v "$t" >/dev/null 2>&1; then
|
||||
printf '%-20s %s\n' "$t" "$(command -v "$t")"
|
||||
else
|
||||
missing+=("$t")
|
||||
printf '%-20s MISSING\n' "$t"
|
||||
fi
|
||||
done
|
||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||
echo "Missing tools: ${missing[*]}. Install via: sudo apt install -y devscripts build-essential debhelper pkg-config"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Compute version strings
|
||||
shell: bash
|
||||
run: |
|
||||
base="${VERSION_BASE}"
|
||||
suffix="${VERSION_SUFFIX}"
|
||||
[[ "$base" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
|
||||
echo "VERSION_BASE '$base' must be major.minor.patch"; exit 1; }
|
||||
if [[ -n "$suffix" ]]; then display="${base}-${suffix}"; else display="${base}"; fi
|
||||
echo "Base : $base"
|
||||
echo "Suffix : $suffix"
|
||||
echo "Display : $display"
|
||||
echo "VERSION_DISPLAY=$display" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Patch Cargo.toml with display version
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -E "0,/^version[[:space:]]*=/{s/^version[[:space:]]*=[[:space:]]*\"${VERSION_BASE}\"/version = \"${VERSION_DISPLAY}\"/}" Cargo.toml
|
||||
grep '^version' Cargo.toml | head -1
|
||||
|
||||
- name: Patch debian/changelog with display version
|
||||
shell: bash
|
||||
run: |
|
||||
# The .deb filename is derived from the first changelog entry's
|
||||
# parenthesized version, NOT from Cargo.toml. Rewrite the leading
|
||||
# entry so the produced .debs carry $VERSION_DISPLAY.
|
||||
sed -i -E "0,/^rustdesk-server \(${VERSION_BASE}\)/{s/^rustdesk-server \(${VERSION_BASE}\)/rustdesk-server (${VERSION_DISPLAY})/}" debian/changelog
|
||||
head -1 debian/changelog
|
||||
|
||||
- name: Ensure Rust toolchain configured
|
||||
shell: bash
|
||||
run: |
|
||||
rustup toolchain install "$RUST_VERSION" --profile minimal --component rustfmt
|
||||
rustup default "$RUST_VERSION"
|
||||
rustup target add x86_64-unknown-linux-gnu
|
||||
rustc --version
|
||||
cargo --version
|
||||
|
||||
- name: Build hbbs / hbbr / rustdesk-utils
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
# Native build for the runner's amd64 host. --all-features matches
|
||||
# what upstream's GitHub workflow uses for its musl cross builds.
|
||||
cargo build --release --all-features
|
||||
mkdir -p debian-build/amd64/bin
|
||||
cp -v target/release/hbbs debian-build/amd64/bin/
|
||||
cp -v target/release/hbbr debian-build/amd64/bin/
|
||||
cp -v target/release/rustdesk-utils debian-build/amd64/bin/
|
||||
chmod -v a+x debian-build/amd64/bin/*
|
||||
|
||||
- name: Build .deb packages (amd64)
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
# Mirrors the deb-package job in upstream's .github/workflows/build.yaml:
|
||||
# stage debian/ and systemd/ next to the pre-built bin/ tree, then run
|
||||
# debuild -b so dh's auto_build step is a no-op (no source detected)
|
||||
# and dh_install just packages the binaries listed in the .install files.
|
||||
cp -vr debian systemd debian-build/amd64/
|
||||
sed "s/{{ ARCH }}/amd64/" debian/control.tpl > debian-build/amd64/debian/control
|
||||
(cd debian-build/amd64 && debuild -i -us -uc -b -aamd64)
|
||||
|
||||
mkdir -p ./SignOutput
|
||||
mv -v ./debian-build/rustdesk-server-hbbs_${VERSION_DISPLAY}_amd64.deb ./SignOutput/
|
||||
mv -v ./debian-build/rustdesk-server-hbbr_${VERSION_DISPLAY}_amd64.deb ./SignOutput/
|
||||
mv -v ./debian-build/rustdesk-server-utils_${VERSION_DISPLAY}_amd64.deb ./SignOutput/
|
||||
|
||||
- name: Report signing status of build artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
# .deb files are typically signed with debsign or via the apt repo
|
||||
# signing pipeline, not the .deb itself. Just list contents for now.
|
||||
for f in ./SignOutput/*.deb; do
|
||||
[[ -f "$f" ]] || continue
|
||||
size=$(stat -c%s "$f")
|
||||
printf '[UNSIGNED] %s (%d bytes)\n' "$(basename "$f")" "$size"
|
||||
done
|
||||
echo "::warning title=Unsigned .deb::Wire up debsigs / repo signing before distributing."
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: rustdesk-server-linux-amd64-${{ github.sha }}
|
||||
path: SignOutput/rustdesk-server-*.deb
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
@@ -0,0 +1,48 @@
|
||||
# Multi-stage build: clones rustdesk-server from a Git remote and builds the
|
||||
# hbbs / hbbr / rustdesk-utils binaries from source.
|
||||
#
|
||||
# Build args:
|
||||
# RUSTDESK_GIT_URL Git URL to clone (default: gitea.cstudio.ch fork)
|
||||
# RUSTDESK_GIT_BRANCH Branch / tag / ref to check out (default: pro-features)
|
||||
# RUST_VERSION Rust toolchain image tag (default: 1-bookworm)
|
||||
|
||||
ARG RUST_VERSION=1-bookworm
|
||||
|
||||
FROM rust:${RUST_VERSION} AS builder
|
||||
|
||||
ARG RUSTDESK_GIT_URL=https://gitea.cstudio.ch/mike/rustdesk-server.git
|
||||
ARG RUSTDESK_GIT_BRANCH=pro-features
|
||||
# sqlx::query! macros verify SQL at compile time against the checked-in
|
||||
# db_v2.sqlite3. Override only if you point cargo at a different DB.
|
||||
ARG DATABASE_URL=
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git ca-certificates pkg-config cmake \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
RUN git clone --recurse-submodules --shallow-submodules \
|
||||
--branch "${RUSTDESK_GIT_BRANCH}" --single-branch \
|
||||
"${RUSTDESK_GIT_URL}" .
|
||||
|
||||
RUN if [ -n "${DATABASE_URL}" ]; then export DATABASE_URL="${DATABASE_URL}"; fi \
|
||||
&& cargo build --release --bins
|
||||
|
||||
# Runtime stage
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates tini \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /src/target/release/hbbs /usr/local/bin/hbbs
|
||||
COPY --from=builder /src/target/release/hbbr /usr/local/bin/hbbr
|
||||
COPY --from=builder /src/target/release/rustdesk-utils /usr/local/bin/rustdesk-utils
|
||||
COPY --from=builder /src/admin_ui /opt/rustdesk/admin_ui
|
||||
|
||||
WORKDIR /root
|
||||
EXPOSE 21114 21115 21116 21116/udp 21117 21118 21119
|
||||
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
CMD ["hbbs"]
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
# 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](CONFIGURATION.md). This document only covers the Compose
|
||||
glue.
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```yaml
|
||||
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](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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```yaml
|
||||
build:
|
||||
<<: *rustdesk-build
|
||||
args:
|
||||
HTTP_PROXY: http://proxy.internal:3128
|
||||
HTTPS_PROXY: http://proxy.internal:3128
|
||||
```
|
||||
|
||||
**Resource hint.** Cold compile takes ~3–5 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.
|
||||
Reference in New Issue
Block a user