7) RuskDesk Clients bauen ( build_clients.sh )
Die RustDesk-Clients werden auf den Endgeräten installiert, die du fernsteuern oder zur Fernsteuerung freigeben möchtest (z. B. Laptop, PC, Server, ggf. auch Smartphones). Der Client stellt die Verbindung zu deinem selbst betriebenen RustDesk-Server her, zeigt eine Geräte-ID an und ermöglicht anschließend den Remote-Zugriff – entweder innerhalb deines Netzes oder über das Internet.
Damit Nutzer nicht jedes Mal manuell Server-Adresse und Key eintragen müssen, erzeugt das Build-Skript (build_clients.sh) vorkonfigurierte Download-Pakete:
- es lädt automatisch die aktuellste RustDesk-Client-Version (Windows/macOS) herunter,
- erstellt daraus fertige ZIP-Pakete für Windows (verschiedene Start-Optionen) und macOS,
- legt passende Konfigurationsdateien (TOML) ab (min/full),
- aktualisiert die Download-Webseite (index.html) sowie eine VERSION.txt, damit jederzeit sichtbar ist, welche Client-Version gerade bereitgestellt wird.
- Konfigurationen erzeugen
- clients/config/RustDesk2.min.toml
- clients/config/RustDesk2.full.toml
- clients/config/RustDesk2.toml (Alias auf full)
- Download-Webseite aktualisieren
- clients/index.html wird neu geschrieben (Servername, Links, Hinweise)
- clients/VERSION.txt wird neu geschrieben (RustDesk Release-Tag + Build-Zeit)
- Zips erstellen
- Windows: quick/unblock/standard
- macOS: ZIP mit DMG + install.command
- In jedem ZIP liegen zusätzlich README_DE.txt und README_EN.txt
Wichtige Anpassungsstellen im Skript
- Inhalt der Downloadseite: Block cat > “$INDEX_FILE” …
- Inhalte der Readmes: dort wo README_DE.txt / README_EN.txt erzeugt werden
- Automatische Version: kommt aus GitHub “latest release” → landet in VERSION.txt und in den Readmes
Build script erstellen :
nano /opt/containers/rustdesk/build_clients.sh
Inhalt:
#!/usr/bin/env bash
set -euo pipefail
BASE_DIR="/opt/containers/rustdesk"
ENV_FILE="${BASE_DIR}/.env"
need() { command -v "$1" >/dev/null 2>&1 || { echo "Missing dependency: $1" >&2; exit 1; }; }
need curl
need zip
need jq
# Load .env
if [[ -f "$ENV_FILE" ]]; then
set -a
# shellcheck disable=SC1090
source "$ENV_FILE"
set +a
fi
: "${RUSTDESK_HOST:?Missing in .env}"
: "${KEY_PUB:?Missing in .env}"
: "${RUSTDESK_RELAY:?Missing in .env}"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
# Paths
CONF_DIR="${BASE_DIR}/client-config"
CONF_MIN="${CONF_DIR}/RustDesk2.min.toml"
CONF_FULL="${CONF_DIR}/RustDesk2.full.toml"
CONF_DEFAULT="${CONF_DIR}/RustDesk2.toml" # used inside packages (FULL)
OUT_ROOT="${BASE_DIR}/clients"
OUT_WIN_DIR="${OUT_ROOT}/windows"
OUT_MAC_DIR="${OUT_ROOT}/macos"
OUT_CFG_DIR="${OUT_ROOT}/config"
INDEX_FILE="${OUT_ROOT}/index.html"
VERSION_FILE="${OUT_ROOT}/VERSION.txt"
MAC_DEFAULT_ARCH="${MAC_DEFAULT_ARCH:-aarch64}"
mkdir -p "$CONF_DIR" "$OUT_WIN_DIR" "$OUT_MAC_DIR" "$OUT_CFG_DIR"
# --- Generate configs ---
cat > "$CONF_MIN" <<EOF
rendezvous_server = '${RUSTDESK_HOST}:21116'
[options]
custom-rendezvous-server = '${RUSTDESK_HOST}'
key = '${KEY_PUB}'
EOF
cat > "$CONF_FULL" <<EOF
rendezvous_server = '${RUSTDESK_HOST}:21116'
[options]
custom-rendezvous-server = '${RUSTDESK_HOST}'
relay-server = '${RUSTDESK_RELAY}'
key = '${KEY_PUB}'
EOF
# Default used in packages = FULL (with relay)
cp -f "$CONF_FULL" "$CONF_DEFAULT"
# Publish configs
cp -f "$CONF_MIN" "${OUT_CFG_DIR}/RustDesk2.min.toml"
cp -f "$CONF_FULL" "${OUT_CFG_DIR}/RustDesk2.full.toml"
cp -f "$CONF_DEFAULT" "${OUT_CFG_DIR}/RustDesk2.toml"
# --- Fetch release metadata (for VERSION + index) ---
echo "==> Fetching latest RustDesk release metadata..."
REL_JSON="$(curl -fsSL https://api.github.com/repos/rustdesk/rustdesk/releases/latest)"
RUSTDESK_TAG="$(echo "$REL_JSON" | jq -r '.tag_name // "unknown"')"
RUSTDESK_PUBLISHED="$(echo "$REL_JSON" | jq -r '.published_at // ""')"
BUILD_DATE="$(date -u +"%Y-%m-%d %H:%M UTC")"
cat > "$VERSION_FILE" <<EOF
RustDesk version: ${RUSTDESK_TAG}
Published: ${RUSTDESK_PUBLISHED}
Built: ${BUILD_DATE}
Server: ${RUSTDESK_HOST}
EOF
# --- index.html (with version + server) ---
cat > "$INDEX_FILE" <<EOF
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>RustDesk – Downloads</title>
</head>
<body style="font-family: system-ui; max-width: 820px; margin: 40px auto; line-height: 1.55;">
<h1>RustDesk Downloads</h1>
<p style="opacity:.85">
Server: <b>${RUSTDESK_HOST}</b><br>
RustDesk Version: <b>${RUSTDESK_TAG}</b> (siehe auch <a href="/VERSION.txt">VERSION.txt</a>)<br>
In jedem ZIP liegt eine kurze Anleitung (<code>README_DE.txt</code> / <code>README_EN.txt</code>).
</p>
<h2>Windows</h2>
<ol>
<li><b>Option 1 (am einfachsten):</b> <a href="./windows/rustdesk-win-quick.zip">Quick-Start</a></li>
<li><b>Option 2 (Start mit Vorbereitung):</b> <a href="./windows/rustdesk-win-unblock.zip">Unblock</a></li>
<li><b>Option 3 (klassisch):</b> <a href="./windows/rustdesk-win.zip">Standard</a></li>
</ol>
<h2>macOS</h2>
<p><a href="./macos/rustdesk-mac.zip">macOS Download</a></p>
<h2>Konfiguration</h2>
<ul>
<li><a href="/config/RustDesk2.min.toml">Konfiguration (ohne Relay)</a></li>
<li><a href="/config/RustDesk2.full.toml">Konfiguration (mit Relay)</a></li>
</ul>
</body>
</html>
EOF
asset_url() {
local regex="$1"
echo "$REL_JSON" | jq -r --arg re "$regex" '
.assets[] | select(.name | test($re)) | .browser_download_url
' | head -n1
}
WIN_URL="$(asset_url "rustdesk-.*-x86_64\\.exe$")"
[[ -n "${WIN_URL:-}" && "$WIN_URL" != "null" ]] || { echo "Could not find Windows x86_64 exe" >&2; exit 1; }
MAC_ARM_URL="$(asset_url "rustdesk-.*-aarch64\\.dmg$")"
MAC_INTEL_URL="$(asset_url "rustdesk-.*-x86_64\\.dmg$")"
WIN_EXE="${TMP_DIR}/rustdesk.exe"
curl -fL "$WIN_URL" -o "$WIN_EXE"
# --------------------------
# Windows Option 3: STANDARD
# --------------------------
echo "==> Building Windows STANDARD package (rustdesk-win.zip)..."
WIN_STD="${TMP_DIR}/win_std"
mkdir -p "$WIN_STD"
cp -f "$WIN_EXE" "$WIN_STD/rustdesk.exe"
cp -f "$CONF_DEFAULT" "$WIN_STD/RustDesk2.toml"
cat > "$WIN_STD/start.cmd" <<'EOF'
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
set "CFGDIR=%APPDATA%\RustDesk\config"
mkdir "%CFGDIR%" >nul 2>&1
copy /Y "%SCRIPT_DIR%RustDesk2.toml" "%CFGDIR%\RustDesk2.toml" >nul
start "" "%SCRIPT_DIR%rustdesk.exe"
endlocal
EOF
cat > "$WIN_STD/README_DE.txt" <<EOF
RustDesk (Windows) – Standard
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) ZIP entpacken.
2) "start.cmd" ausführen.
Das Script kopiert die Konfiguration und startet RustDesk.
EOF
cat > "$WIN_STD/README_EN.txt" <<EOF
RustDesk (Windows) – Standard
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) Unzip the file.
2) Run "start.cmd".
The script installs the configuration and starts RustDesk.
EOF
rm -f "${OUT_WIN_DIR}/rustdesk-win.zip"
( cd "$WIN_STD" && zip -qr "${OUT_WIN_DIR}/rustdesk-win.zip" . )
# -----------------------------------------
# Windows Option 2: UNBLOCK + Fallback
# -----------------------------------------
echo "==> Building Windows UNBLOCK package (rustdesk-win-unblock.zip)..."
WIN_UNBLOCK="${TMP_DIR}/win_unblock"
mkdir -p "$WIN_UNBLOCK"
cp -f "$WIN_EXE" "$WIN_UNBLOCK/rustdesk.exe"
cp -f "$CONF_DEFAULT" "$WIN_UNBLOCK/RustDesk2.toml"
cat > "$WIN_UNBLOCK/start.cmd" <<'EOF'
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
set "CFGDIR=%APPDATA%\RustDesk\config"
rem Versucht, die Windows-Download-Markierung zu entfernen (falls vorhanden)
for %%F in ("%SCRIPT_DIR%rustdesk.exe" "%SCRIPT_DIR%RustDesk2.toml") do (
>nul 2>&1 del "%%~fF:Zone.Identifier"
)
mkdir "%CFGDIR%" >nul 2>&1
copy /Y "%SCRIPT_DIR%RustDesk2.toml" "%CFGDIR%\RustDesk2.toml" >nul
>nul 2>&1 del "%CFGDIR%\RustDesk2.toml:Zone.Identifier"
start "" "%SCRIPT_DIR%rustdesk.exe"
endlocal
EOF
cat > "$WIN_UNBLOCK/start-original.cmd" <<'EOF'
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
set "CFGDIR=%APPDATA%\RustDesk\config"
mkdir "%CFGDIR%" >nul 2>&1
copy /Y "%SCRIPT_DIR%RustDesk2.toml" "%CFGDIR%\RustDesk2.toml" >nul
start "" "%SCRIPT_DIR%rustdesk.exe"
endlocal
EOF
cat > "$WIN_UNBLOCK/README_DE.txt" <<EOF
RustDesk (Windows) – Start mit Vorbereitung
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) ZIP entpacken.
2) "start.cmd" ausführen.
Falls es Probleme gibt: "start-original.cmd" verwenden.
EOF
cat > "$WIN_UNBLOCK/README_EN.txt" <<EOF
RustDesk (Windows) – Start with preparation
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) Unzip the file.
2) Run "start.cmd".
If anything goes wrong, use "start-original.cmd".
EOF
rm -f "${OUT_WIN_DIR}/rustdesk-win-unblock.zip"
( cd "$WIN_UNBLOCK" && zip -qr "${OUT_WIN_DIR}/rustdesk-win-unblock.zip" . )
# -----------------------
# Windows Option 1: QUICK
# -----------------------
echo "==> Building Windows QUICK package (rustdesk-win-quick.zip)..."
WIN_QUICK="${TMP_DIR}/win_quick"
mkdir -p "$WIN_QUICK"
KEY_PUB_SAFE="$(printf '%s' "$KEY_PUB" | tr '+/' '-_')"
RENAMED_EXE="rustdesk-host=${RUSTDESK_HOST},key=${KEY_PUB_SAFE}=.exe"
cp -f "$WIN_EXE" "$WIN_QUICK/$RENAMED_EXE"
cat > "$WIN_QUICK/README_DE.txt" <<EOF
RustDesk (Windows) – Quick Start
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) ZIP entpacken.
2) Starte die Datei: ${RENAMED_EXE}
Wenn Quick nicht zuverlässig funktioniert:
Bitte die "Unblock" oder "Standard" Variante verwenden.
EOF
cat > "$WIN_QUICK/README_EN.txt" <<EOF
RustDesk (Windows) – Quick Start
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) Unzip the file.
2) Start: ${RENAMED_EXE}
If Quick is not reliable:
Use the "Unblock" or "Standard" package.
EOF
rm -f "${OUT_WIN_DIR}/rustdesk-win-quick.zip"
( cd "$WIN_QUICK" && zip -qr "${OUT_WIN_DIR}/rustdesk-win-quick.zip" . )
# ----------------
# macOS package
# ----------------
echo "==> Building macOS package (rustdesk-mac.zip)..."
MAC_PKG="${TMP_DIR}/mac_pkg"
mkdir -p "$MAC_PKG"
MAC_DMG_URL=""
if [[ "$MAC_DEFAULT_ARCH" == "x86_64" && -n "${MAC_INTEL_URL:-}" && "$MAC_INTEL_URL" != "null" ]]; then
MAC_DMG_URL="$MAC_INTEL_URL"
else
MAC_DMG_URL="$MAC_ARM_URL"
fi
[[ -n "${MAC_DMG_URL:-}" && "$MAC_DMG_URL" != "null" ]] || { echo "Could not find macOS dmg" >&2; exit 1; }
curl -fL "$MAC_DMG_URL" -o "$MAC_PKG/RustDesk.dmg"
cp -f "$CONF_DEFAULT" "$MAC_PKG/RustDesk2.toml"
cat > "$MAC_PKG/install.command" <<'EOF'
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
open "$SCRIPT_DIR/RustDesk.dmg"
echo "DMG ist geöffnet. Bitte RustDesk nach /Applications ziehen (falls noch nicht passiert)."
echo "Dann ENTER drücken, um die Konfiguration zu installieren..."
read -r
CFGDIR="$HOME/Library/Preferences/com.carriez.RustDesk"
mkdir -p "$CFGDIR"
cp -f "$SCRIPT_DIR/RustDesk2.toml" "$CFGDIR/RustDesk2.toml"
echo "Konfiguration installiert."
open -a "RustDesk" || true
EOF
chmod +x "$MAC_PKG/install.command"
cat > "$MAC_PKG/README_DE.txt" <<EOF
RustDesk (macOS)
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) ZIP entpacken.
2) "install.command" ausführen.
3) RustDesk (aus dem DMG) nach /Applications ziehen (falls nötig).
EOF
cat > "$MAC_PKG/README_EN.txt" <<EOF
RustDesk (macOS)
Server: ${RUSTDESK_HOST}
Version: ${RUSTDESK_TAG}
1) Unzip the file.
2) Run "install.command".
3) Drag RustDesk (from the DMG) to /Applications if needed.
EOF
rm -f "${OUT_MAC_DIR}/rustdesk-mac.zip"
( cd "$MAC_PKG" && zip -qr "${OUT_MAC_DIR}/rustdesk-mac.zip" . )
echo "==> Done."
echo "Index: ${INDEX_FILE}"
echo "Version: ${VERSION_FILE}"
echo "Windows quick: ${OUT_WIN_DIR}/rustdesk-win-quick.zip"
echo "Windows unblock: ${OUT_WIN_DIR}/rustdesk-win-unblock.zip"
echo "Windows standard:${OUT_WIN_DIR}/rustdesk-win.zip"
echo "macOS: ${OUT_MAC_DIR}/rustdesk-mac.zip"
Build ausführen:
chmod +x /opt/containers/rustdesk/build_clients.sh cd /opt/containers/rustdesk ./build_clients.sh
8) RustDesk starten
Hinweis: Damit alles funktioniert muss natürlich auf dem Host alles geregelt sein ! Siehe dazu 10.5
cd /opt/containers/rustdesk docker compose up -d docker compose ps
Container-Status + Health anzeigen
cd /opt/containers/rustdesk #optional wenn nicht im Order
docker compose ps
docker inspect -f '{{.State.Health.Status}}' rustdesk 2>/dev/null || true
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS rustdesk ghcr.io/rustdesk/rustdesk-server-s6:latest "/init" rustdesk 4 days ago Up 4 days (healthy) 21115-21119/tcp, 21116/udp rustdesk-clients joseluisq/static-web-server:2-alpine "/usr/local/bin/entr…" rustdesk-clients 4 days ago Up 4 days 80/tcp healthy

Hallo
Frank, ich habe Rustdesk mal neu nach deiner Anleitung installiert und es hat alles geklappt. Ich kann Verbindungen aufbauen. Aber nur wenn ich den Relayserver mit eintrage. Auch die Webseite mit dem Clients ist echt super. Ich muss mich mal noch weiter damit beschäftigen. Aber vielen Dank für deine gute Anleitung.