Files
UNITRONIX e89a6889eb fix(docker): clarify ADMIN_PASSWORD mapping and ARM AIO :dev (#385)
Map ADMIN_PASSWORD into compose containers, log bootstrap set=yes/no,
and document amd64-only AIO :dev plus split/dev-arm workarounds for arm64.

Refs #385

Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
2026-09-05 23:00:49 +02:00

365 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🚀 BetterDesk Docker Quick Start
Get BetterDesk running in **30 seconds** with pre-built images from GitHub Container Registry (ghcr.io).
Versioned tags match [CHANGELOG.md](../../CHANGELOG.md) and git releases (e.g. `3.0.0`, git tag `v3.0.0`). The quick-start compose file defaults to the current release; override with `BETTERDESK_IMAGE_TAG`.
## Prerequisites
- Docker 20.10+
- docker-compose v2.0+ (or `docker compose` plugin)
- Open ports: 21115-21119, 21121, 5000 (official single-container layout)
## 🏃 Quick Start
### One-line installer (automated)
Fully automated: installs Docker if missing, downloads the **official all-in-one** compose + image (`ghcr.io/unitronix/betterdesk`), auto-detects relay IP, configures firewall, waits for health checks, prints credentials.
```bash
curl -fsSL https://raw.githubusercontent.com/UNITRONIX/BetterDesk/main/install.sh | sudo bash
```
**Common variants:**
```bash
# Legacy two-container layout (server + console images)
curl -fsSL .../install.sh | sudo bash -s -- --split
# LAN-only deployment
curl -fsSL .../install.sh | sudo bash -s -- --relay-mode local
# Pin image version + set admin password
curl -fsSL .../install.sh | sudo bash -s -- --version 3.3.112 --admin-password 'YourSecurePass'
# Uninstall (keep data volumes)
curl -fsSL .../install.sh | sudo bash -s -- --uninstall
# Uninstall and delete volumes
curl -fsSL .../install.sh | sudo bash -s -- --uninstall --purge
```
Files are stored under `/opt/betterdesk/docker/` (`docker-compose.yml`, `.env`).
### Quick Start (3 Commands) — official single container
```bash
# 1. Download docker-compose file
curl -fsSL https://raw.githubusercontent.com/UNITRONIX/BetterDesk/main/docker-compose.quick.single.yml -o docker-compose.yml
# 2. Pull pinned image and start (default tag matches VERSION in repo)
docker compose pull
docker compose up -d
# 3. Get admin password
docker compose exec betterdesk betterdesk-show-admin-credentials
```
**Done!** Open **http://localhost:5000** (plain HTTP — not `https://`) and log in with `admin` / (password from step 3). The default image does not terminate TLS on port 5000; using `https://…:5000` often yields Firefox `SSL_ERROR_RX_RECORD_TOO_LONG` — see [DOCKER_TROUBLESHOOTING.md](DOCKER_TROUBLESHOOTING.md#problem-browser-shows-ssl_error_rx_record_too_long-or-chrome-err_ssl_protocol_error).
If `cat /opt/rustdesk/.admin_credentials` returns **Permission denied**, use `betterdesk-show-admin-credentials` above (or `docker compose exec -u betterdesk betterdesk …`) — see [DOCKER_TROUBLESHOOTING.md](DOCKER_TROUBLESHOOTING.md#problem-permission-denied-reading-admin_credentials).
### Legacy split layout (two images)
```bash
curl -fsSL https://raw.githubusercontent.com/UNITRONIX/BetterDesk/main/docker-compose.quick.yml -o docker-compose.yml
docker compose pull && docker compose up -d
docker compose exec console betterdesk-show-admin-credentials
```
Split layout uses API port **21114**; the official single container uses **21121**.
### Pin or change image version
```bash
# Explicit release version (recommended for production — matches install.sh / compose default)
export BETTERDESK_IMAGE_TAG=3.0.0
docker compose pull && docker compose up -d
# Rolling tip of the last successful *stable* GHCR publish (release / main)
# Not the same as “newest CHANGELOG line” until that releases images are published
export BETTERDESK_IMAGE_TAG=latest
docker compose pull && docker compose up -d
```
Browse tags: GitHub repo → **Packages**`betterdesk` (official), or legacy `betterdesk-server` / `betterdesk-console`, or [releases](https://github.com/UNITRONIX/BetterDesk/releases).
---
## 📦 What Gets Installed (single container — default)
| Port | Description |
|------|-------------|
| 21116 TCP/UDP | Signal server (device registration) |
| 21117 | Relay server (connections) |
| 21121 | HTTP API (RustDesk client + REST) |
| 5000 | Web management panel |
Legacy split layout exposes API on **21114** instead of 21121.
## 🔧 Configuration
### Relay Address for Docker Hosts
If clients can register but remote sessions fail with `Failed to connect via relay server`, set the relay address that clients can actually reach. In Docker quick images, the server may see its internal container address, which is not reachable from RustDesk clients.
```bash
# Public server
RELAY_SERVERS=203.0.113.10:21117 docker compose up -d
# LAN-only server
RELAY_SERVERS=192.168.1.10:21117 docker compose up -d
```
Use the Docker host address, not the container IP. Make sure TCP port `21117` is open and forwarded to the host.
### Public Client Endpoints (survive container recreate)
Settings → **Public client endpoints** (ID server, relay, API URL) are stored on the **`console-data` volume** at `/app/data/public-endpoints.env`. They survive `docker compose pull`, `up -d`, and `--force-recreate`.
Alternatively, set them declaratively in compose (non-empty values override the panel file):
```yaml
environment:
- PUBLIC_SERVER_ID=gateway.example.net
- PUBLIC_RELAY_SERVER=gateway.example.net
- PUBLIC_API_URL=https://api.example.net:21121
```
Do **not** add empty `PUBLIC_*=` entries — leave the keys unset when using the panel. See [REVERSE_PROXY.md](../setup/REVERSE_PROXY.md#split-dns--multiple-hostnames).
### Custom Admin Password
```bash
# Set before first start, while the Docker volumes are still empty
ADMIN_PASSWORD=YourSecurePass123 docker compose up -d
```
`ADMIN_PASSWORD` only seeds the first admin account. If the container has
already created the admin user in `db_v2.sqlite3` (or PostgreSQL), changing the
environment variable on restart will not overwrite the stored password. Use
the panel password reset flow, or recreate the Docker volumes for a fresh
install.
Keep the compose `INIT_ADMIN_*` / `DEFAULT_ADMIN_*` / `ADMIN_PASSWORD=${ADMIN_PASSWORD:-}`
mappings uncommented — otherwise the host shell variable never reaches the
container (issue #385).
### Image architectures (`:dev` vs ARM)
| Image | `:dev` platforms | Notes |
|-------|------------------|-------|
| `ghcr.io/unitronix/betterdesk` (AIO) | **amd64 only** | Multi-arch AIO on `:dev` often hits the GitHub Actions time limit |
| `betterdesk-server` / `betterdesk-console` | amd64 + arm64 | Prefer [docker-compose.quick.yml](../../docker-compose.quick.yml) on ARM hosts |
| `betterdesk` `latest` / release tags | amd64 + arm64 | Stable channel |
On **linux/arm64**, use the split quick-start compose, build AIO locally from
`docker-compose.single.yml`, or pin a multi-arch tip tag (e.g. `dev-arm`) when
published. Do not expect a fresh `betterdesk:dev` pull to refresh ARM layers
while AIO `:dev` remains amd64-only.
### PostgreSQL Instead of SQLite
```yaml
# Add to docker-compose.yml
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: betterdesk
POSTGRES_USER: betterdesk
POSTGRES_PASSWORD: secretpassword
volumes:
- postgres-data:/var/lib/postgresql/data
server:
environment:
- DB_URL=postgres://betterdesk:secretpassword@postgres:5432/betterdesk
depends_on:
- postgres
volumes:
postgres-data:
```
### SSL/TLS
By default the web panel is **HTTP on port 5000**. Do not open `https://…:5000` unless you have enabled panel HTTPS or put a reverse proxy in front — otherwise browsers report `SSL_ERROR_RX_RECORD_TOO_LONG` / `ERR_SSL_PROTOCOL_ERROR` ([troubleshooting](DOCKER_TROUBLESHOOTING.md#problem-browser-shows-ssl_error_rx_record_too_long-or-chrome-err_ssl_protocol_error)).
See [HTTPS_SETUP.md](../setup/HTTPS_SETUP.md) for full instructions.
Quick self-signed cert:
```bash
mkdir -p certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout certs/key.pem -out certs/cert.pem \
-subj "/CN=betterdesk.local"
```
---
## 🔄 Updates
```bash
# Stay on the same pinned tag (default 3.0.0)
docker compose pull
docker compose up -d
# Move to a newer release after it is published on ghcr.io
export BETTERDESK_IMAGE_TAG=<new-version> # e.g. 3.0.0-beta or 3.0.0
docker compose pull && docker compose up -d
```
**Stable vs development channel:** Settings → Updates → Update channel does **not** switch GHCR images. Change the image tag instead:
| Channel | Typical `BETTERDESK_IMAGE_TAG` |
|---------|--------------------------------|
| Stable (`main`) | **Pin a release semver** (e.g. `3.5.65` — compose / `install.sh` default). Optional: `latest` = last successful stable image publish on GHCR (may lag a git release until CI publishes). |
| Development (`dev`) | `dev` |
Then: `docker compose pull && docker compose up -d`. In-app “Install update” stays disabled for official image deployments.
## 🗑️ Uninstall
```bash
docker compose down -v # -v removes volumes (data)
```
## 📊 Check Status
```bash
# All services running?
docker compose ps
# Logs (single container)
docker compose logs betterdesk
# Health check (single container)
curl http://localhost:21121/api/health
```
Legacy split: `docker compose logs server` / `console`, health on `:21114`.
---
## MACVLAN (dedicated LAN IP)
Use this when the stack must listen on a **macvlan** address (no host port mappings).
**Single container (recommended):**
```bash
docker network create -d macvlan \
--subnet=192.168.1.0/24 --gateway=192.168.1.1 \
-o parent=eth0 LAN
export MACVLAN_IPV4=192.168.1.51
export RELAY_SERVERS=${MACVLAN_IPV4}:21117
curl -fsSL https://raw.githubusercontent.com/UNITRONIX/BetterDesk/main/docker-compose.quick.single.macvlan.yml -o docker-compose.yml
docker compose pull && docker compose up -d
```
**Legacy split:** `docker-compose.quick.macvlan.yml`
Web console: `http://MACVLAN_IPV4:5000`
### Upgrading a custom macvlan compose (issue #186)
If you customized an older quick-start file before **3.0.0**, apply these changes after pulling new images:
| Setting | Required in 3.0.0+ |
|---------|-------------------|
| `depends_on` | `condition: service_started`**not** `service_healthy` |
| Server healthcheck | Keep enabled, or remove `service_healthy` from `depends_on` |
| Console `DB_PATH` | `/app/data/db_v2.sqlite3` |
| Server `AUTH_DB_PATH` | `/app/data/auth.db` only for legacy panel sync |
| Server volume | `console-data:/app/data:ro` |
| `network_mode: service:server` | Use `127.0.0.1` in `BETTERDESK_API_URL`, `WS_HBBS_HOST`, `WS_HBBR_HOST` (Docker DNS is unavailable) |
| Image tag | Pin `BETTERDESK_IMAGE_TAG` (e.g. `3.2.14`), not unversioned `latest` |
**Symptom:** server logs look healthy but the console never starts — check `docker compose ps -a` and `docker compose logs console`. The usual cause is `depends_on: service_healthy` while the server healthcheck is disabled.
Optional: copy `docker-compose.quick.macvlan.yml` from this repo as a maintained baseline.
---
## ❓ Troubleshooting
### "denied" or "pull access denied" when starting
This means the pre-built images are not yet published to GitHub Container Registry.
**Solution A — Build locally (recommended):**
```bash
# Use the full docker-compose.yml which builds images from source
git clone https://github.com/UNITRONIX/Rustdesk-FreeConsole.git
cd Rustdesk-FreeConsole
docker compose -f docker-compose.yml up -d --build
```
**Solution B — Wait for images to be published:**
The repository maintainer needs to trigger the Docker publish workflow:
1. Go to: GitHub repo → Actions → "Build & Publish Docker Images"
2. Click "Run workflow" → Branch: main → Click "Run workflow"
3. Wait ~10 minutes for images to build
4. Once images are published, retry `docker compose up -d`
**Solution C — Authenticate (if repo is private):**
```bash
# Create a GitHub Personal Access Token with 'read:packages' scope
docker login ghcr.io -u YOUR_GITHUB_USERNAME -p YOUR_GITHUB_TOKEN
docker compose up -d
```
### "Cannot connect to devices"
1. Check firewall allows ports 21116-21117
2. Verify server is healthy: `curl http://localhost:21114/api/health`
3. Check the advertised relay address: `docker compose logs server | grep 'relay='`
4. If logs show a Docker/container IP such as `10.x.x.x` or `172.x.x.x`, restart with `RELAY_SERVERS=YOUR_HOST_IP:21117 docker compose up -d`
### "Web console shows 0 devices"
1. Verify API key sync: `docker compose exec console cat /opt/rustdesk/.api_key`
2. Restart console: `docker compose restart console`
### "Connection refused on port 21116"
1. Wait 30 seconds for server to start
2. Check server health: `docker compose ps`
3. View server logs: `docker compose logs server`
### Need more help?
See [DOCKER_TROUBLESHOOTING.md](../docker/DOCKER_TROUBLESHOOTING.md) for advanced issues.
---
## 🏗️ Build from Source (Advanced)
If you need custom modifications:
```bash
git clone https://github.com/UNITRONIX/Rustdesk-FreeConsole.git
cd Rustdesk-FreeConsole
docker compose -f docker-compose.yml up -d --build
```
---
## 📝 RustDesk Client Configuration
Configure your RustDesk clients with:
| Setting | Value |
|---------|-------|
| ID Server | `YOUR_SERVER_IP:21116` |
| Relay Server | `YOUR_SERVER_IP:21117` |
| API Server | `http://YOUR_SERVER_IP:21121` |
| Key | (get from web console Settings page) |
Or scan the QR code from the web console Settings page.
For a public hostname that differs from the Docker service name (`betterdesk-server` / `127.0.0.1`), configure **Settings → Public client endpoints** (persisted on the `console-data` volume) or set `PUBLIC_*` in compose — see [Public Client Endpoints](#public-client-endpoints-survive-container-recreate).