Files
UNITRONIX 7f7479fb88 feat(docker): support PUID/PGID for container app user
Remap betterdesk at entrypoint start so Synology/NAS bind mounts can
match host ownership without Compose user: overrides.

Refs #376

Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
2026-08-19 10:28:39 +02:00

625 lines
15 KiB
Markdown

# 🐳 Docker Installation Guide - BetterDesk Console
Complete guide for running BetterDesk Console with RustDesk in Docker containers.
> **Images**: Pre-built images are published to [GitHub Container Registry](https://github.com/UNITRONIX/BetterDesk/pkgs/container/betterdesk-server) (`ghcr.io/unitronix/…`) with version tags aligned to [CHANGELOG.md](../../CHANGELOG.md). Use [DOCKER_QUICKSTART.md](DOCKER_QUICKSTART.md) and `docker-compose.quick.yml` to pull by tag. For custom changes, build locally with `docker compose build` or `docker compose up --build` (not on Docker Hub).
## Table of Contents
- [Quick Start (Recommended)](#quick-start-recommended)
- [Docker Compose Setup](#docker-compose-setup)
- [Manual Docker Setup](#manual-docker-setup)
- [Troubleshooting](#troubleshooting)
- [Migration from Native Install](#migration-from-native-install)
---
## Quick Start (Recommended)
### Option 1: Automatic Setup (Easiest)
```bash
# Clone repository
git clone https://github.com/UNITRONIX/Rustdesk-FreeConsole.git
cd Rustdesk-FreeConsole
# Run quick setup
chmod +x docker-quickstart.sh
./docker-quickstart.sh
```
This script will:
- ✅ Create docker-compose environment
- ✅ Set up data directories
- ✅ Ask about existing RustDesk data import
- ✅ Start all services
- ✅ Show access URLs
### Option 2: Custom Installation
```bash
# Use the Docker installer with custom options
chmod +x install-docker.sh
sudo ./install-docker.sh
```
This installer provides:
- ✅ Path selection for existing RustDesk data
- ✅ Container vs volume installation modes
- ✅ Database migration
- ✅ Binary deployment
- ✅ Service configuration
### 1. Create Project Directory
```bash
mkdir -p /opt/betterdesk-docker
cd /opt/betterdesk-docker
```
### 2. Create docker-compose.yml
```yaml
version: '3.8'
services:
# RustDesk HBBS (Signal Server) with BetterDesk API
hbbs:
image: rustdesk/rustdesk-server:latest
container_name: betterdesk-hbbs
command: hbbs -k _ --api-port 21114
ports:
- "21115:21115"
- "21116:21116"
- "21116:21116/udp"
- "21114:21114" # API port for BetterDesk
volumes:
- ./data:/root
environment:
- ALWAYS_USE_RELAY=N
networks:
- betterdesk-net
restart: unless-stopped
# RustDesk HBBR (Relay Server)
hbbr:
image: rustdesk/rustdesk-server:latest
container_name: betterdesk-hbbr
command: hbbr -k _
ports:
- "21117:21117"
volumes:
- ./data:/root
networks:
- betterdesk-net
restart: unless-stopped
depends_on:
- hbbs
# BetterDesk Web Console
console:
build:
context: ./console
dockerfile: Dockerfile
container_name: betterdesk-console
ports:
- "5000:5000"
volumes:
- ./data:/opt/rustdesk:ro # Read-only access to RustDesk data
- ./console-data:/app/data # Console-specific data
environment:
- DB_PATH=/opt/rustdesk/db_v2.sqlite3
- API_KEY_PATH=/opt/rustdesk/.api_key
- PUB_KEY_PATH=/opt/rustdesk/id_ed25519.pub
- FLASK_SECRET_KEY=${FLASK_SECRET_KEY:?Set FLASK_SECRET_KEY in .env or export it}
networks:
- betterdesk-net
restart: unless-stopped
depends_on:
- hbbs
networks:
betterdesk-net:
driver: bridge
```
### 3. Create Console Dockerfile
```bash
mkdir -p console
cat > console/Dockerfile << 'EOF'
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
RUN apt-get update && apt-get install -y \
sqlite3 \
&& rm -rf /var/lib/apt/lists/*
# Copy application files
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Create data directory
RUN mkdir -p /app/data
EXPOSE 5000
# Run with gunicorn for production
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "app:app"]
EOF
```
### 4. Create Console Requirements
```bash
cat > console/requirements.txt << 'EOF'
flask>=2.0.0
flask-wtf>=1.0.0
flask-limiter>=3.0.0
bcrypt>=4.0.0
markupsafe>=2.1.0
gunicorn>=21.0.0
requests>=2.28.0
EOF
```
### 5. Copy Console Files
```bash
# Clone repository first if you haven't
git clone https://github.com/UNITRONIX/Rustdesk-FreeConsole.git /tmp/betterdesk
# Copy web files
cp -r /tmp/betterdesk/web/* console/
```
### 6. Start Services
```bash
# Generate a random secret key
export FLASK_SECRET_KEY=$(openssl rand -hex 32)
# Start all services
docker-compose up -d
# Check status
docker-compose ps
docker-compose logs -f
```
### 7. Access Console
- **Web Console**: http://your-server-ip:5000
- **Default Login**: admin / (check logs for password)
---
## Docker Compose Setup (Full)
### Complete docker-compose.yml with All Options
```yaml
version: '3.8'
services:
hbbs:
image: rustdesk/rustdesk-server:latest
container_name: betterdesk-hbbs
hostname: betterdesk-hbbs
command: hbbs -k _ --api-port 21114
ports:
- "21115:21115" # TCP hole punching
- "21116:21116/tcp" # TCP relay
- "21116:21116/udp" # UDP hole punching
- "21114:21114" # HTTP API
volumes:
- betterdesk-data:/root
environment:
- ALWAYS_USE_RELAY=N
- ENCRYPTED_ONLY=1
- DB_URL=./db_v2.sqlite3
networks:
betterdesk-net:
aliases:
- hbbs
restart: unless-stopped
healthcheck:
test: ["CMD", "nc", "-z", "localhost", "21116"]
interval: 30s
timeout: 10s
retries: 3
hbbr:
image: rustdesk/rustdesk-server:latest
container_name: betterdesk-hbbr
hostname: betterdesk-hbbr
command: hbbr -k _
ports:
- "21117:21117" # Relay port
volumes:
- betterdesk-data:/root
networks:
betterdesk-net:
aliases:
- hbbr
restart: unless-stopped
depends_on:
hbbs:
condition: service_healthy
console:
build:
context: ./console
dockerfile: Dockerfile
container_name: betterdesk-console
hostname: betterdesk-console
ports:
- "5000:5000"
volumes:
- betterdesk-data:/opt/rustdesk:ro
- console-data:/app/data
environment:
- DB_PATH=/opt/rustdesk/db_v2.sqlite3
- API_KEY_PATH=/opt/rustdesk/.api_key
- PUB_KEY_PATH=/opt/rustdesk/id_ed25519.pub
- HBBS_API_URL=http://hbbs:21114/api
- FLASK_SECRET_KEY=${FLASK_SECRET_KEY}
- FLASK_ENV=production
networks:
- betterdesk-net
restart: unless-stopped
depends_on:
- hbbs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 10s
retries: 3
volumes:
betterdesk-data:
driver: local
console-data:
driver: local
networks:
betterdesk-net:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
```
---
## Using Pre-built BetterDesk Binaries in Docker
If you want to use the enhanced HBBS with ban enforcement:
### 1. Custom Dockerfile for HBBS
```dockerfile
FROM debian:bullseye-slim
WORKDIR /opt/rustdesk
# Install dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
libsqlite3-0 \
&& rm -rf /var/lib/apt/lists/*
# Copy precompiled binaries
COPY hbbs-v8-api /opt/rustdesk/hbbs
COPY hbbr-v8-api /opt/rustdesk/hbbr
RUN chmod +x /opt/rustdesk/hbbs /opt/rustdesk/hbbr
# Create data directory
RUN mkdir -p /root
WORKDIR /root
EXPOSE 21115 21116 21116/udp 21117 21114
ENTRYPOINT ["/opt/rustdesk/hbbs"]
CMD ["-k", "_", "--api-port", "21114"]
```
### 2. Build and Run
```bash
# Copy binaries from repository
cp hbbs-patch/bin-with-api/hbbs-v8-api ./hbbs-v8-api
cp hbbs-patch/bin-with-api/hbbr-v8-api ./hbbr-v8-api
# Build custom image
docker build -t betterdesk-hbbs:v8 -f Dockerfile.hbbs .
# Update docker-compose.yml to use custom image
# Replace: image: rustdesk/rustdesk-server:latest
# With: image: betterdesk-hbbs:v8
```
---
## Manual Docker Setup
### Individual Container Commands
```bash
# Create network
docker network create betterdesk-net
# Create data volume
docker volume create betterdesk-data
# Run HBBS
docker run -d \
--name betterdesk-hbbs \
--network betterdesk-net \
-p 21115:21115 \
-p 21116:21116 \
-p 21116:21116/udp \
-p 21114:21114 \
-v betterdesk-data:/root \
rustdesk/rustdesk-server:latest \
hbbs -k _ --api-port 21114
# Run HBBR
docker run -d \
--name betterdesk-hbbr \
--network betterdesk-net \
-p 21117:21117 \
-v betterdesk-data:/root \
rustdesk/rustdesk-server:latest \
hbbr -k _
# Run Console (after building)
docker run -d \
--name betterdesk-console \
--network betterdesk-net \
-p 5000:5000 \
-v betterdesk-data:/opt/rustdesk:ro \
-e DB_PATH=/opt/rustdesk/db_v2.sqlite3 \
-e FLASK_SECRET_KEY=$(openssl rand -hex 32) \
betterdesk-console:latest
```
---
## Troubleshooting
### Issue: Installation Script Not Detecting Docker
**Symptom:**
```
✗ Could not detect current version
✗ Installation directory not found
```
**Solution:** The installation script is for native installations. For Docker, use docker-compose as shown above.
### Issue: Devices Show as Offline
**Cause:** Database missing `last_online` column.
**Solution:**
```bash
# Access HBBS container
docker exec -it betterdesk-hbbs /bin/sh
# Add missing column
sqlite3 /root/db_v2.sqlite3 "ALTER TABLE peer ADD COLUMN last_online TEXT;"
sqlite3 /root/db_v2.sqlite3 "ALTER TABLE peer ADD COLUMN is_deleted INTEGER DEFAULT 0;"
# Restart container
docker restart betterdesk-hbbs betterdesk-console
```
### Issue: Cannot Connect to API
**Solution:**
```bash
# Check if API is responding
docker exec betterdesk-hbbs curl -s http://localhost:21114/api/health
# Check logs
docker logs betterdesk-hbbs --tail 50
# Verify port mapping
docker port betterdesk-hbbs
```
### Issue: Console Cannot Access Database
**Solution:**
```bash
# Check volume mounts
docker inspect betterdesk-console | grep Mounts -A 20
# Verify database exists
docker exec betterdesk-hbbs ls -la /root/*.sqlite3
# Check permissions
docker exec betterdesk-console ls -la /opt/rustdesk/
```
### Viewing Logs
```bash
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f hbbs
docker-compose logs -f console
# Last 100 lines
docker logs betterdesk-hbbs --tail 100
```
---
## Migration from Native Install
### 1. Backup Existing Data
```bash
sudo cp -r /opt/rustdesk /opt/rustdesk-backup
sudo cp -r /opt/BetterDeskConsole /opt/BetterDeskConsole-backup
```
### 2. Stop Native Services
```bash
sudo systemctl stop hbbs hbbr betterdesk
sudo systemctl disable hbbs hbbr betterdesk
```
### 3. Copy Data to Docker Volume
```bash
# Create directory for Docker data
mkdir -p /opt/betterdesk-docker/data
# Copy RustDesk data
sudo cp /opt/rustdesk/db_v2.sqlite3 /opt/betterdesk-docker/data/
sudo cp /opt/rustdesk/id_ed25519* /opt/betterdesk-docker/data/
sudo cp /opt/rustdesk/.api_key /opt/betterdesk-docker/data/
# Set permissions to the container app user (default PUID/PGID 10001)
sudo chown -R 10001:10001 /opt/betterdesk-docker/data
# Or, if you set PUID/PGID in compose/.env:
# sudo chown -R "${PUID}:${PGID}" /opt/betterdesk-docker/data
```
### 4. Update docker-compose.yml
Use bind mount instead of named volume (paths are `/opt/rustdesk` and `/app/data`, not `/root`):
```yaml
volumes:
- /opt/betterdesk-docker/data:/opt/rustdesk
environment:
- PUID=10001
- PGID=10001
```
### 5. Start Docker Services
```bash
cd /opt/betterdesk-docker
docker-compose up -d
```
---
## Security Considerations
### Production Recommendations
1. **Use HTTPS** - Put a reverse proxy (nginx/traefik) in front
2. **Limit Network Access** - Use firewall rules
3. **Change Default Password** - Immediately after first login
4. **Regular Backups** - Backup the data volume
5. **Update Regularly** - Pull latest images
### Nginx Reverse Proxy Example
```nginx
server {
listen 443 ssl http2;
server_name betterdesk.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/betterdesk.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/betterdesk.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
### Reverse Proxy with WSS (RustDesk Clients)
When BetterDesk runs in Docker and a reverse proxy (Nginx, Nginx Proxy Manager,
Caddy, Traefik) terminates HTTPS on the host, the **console** and **RustDesk WSS**
endpoints use different upstream ports.
| Public path | Host upstream | Container service | Purpose |
|-------------|---------------|-------------------|---------|
| `/` (panel) | `http://HOST:5000` | `console` | Web admin UI |
| `/ws/id` | `http://HOST:21118` | `server` (Go) | RustDesk signal / rendezvous WSS |
| `/ws/relay` | `http://HOST:21119` | `server` (Go) | RustDesk relay WSS |
Docker Compose publishes `21118` and `21119` on the host by default
(see `docker-compose.yml`). The proxy on the host should target **`127.0.0.1`**
or the host LAN IP — not the container name — when the proxy runs outside the
Docker bridge network.
**Do not** route `/ws/id` or `/ws/relay` to port `5000`. The console exposes
different WebSocket paths (`/ws/rendezvous`, chat, remote viewer, etc.).
Example nginx locations (add to the same `server` block as the panel):
```nginx
location = /ws/id {
proxy_pass http://127.0.0.1:21118;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 120s;
}
location = /ws/relay {
proxy_pass http://127.0.0.1:21119;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 120s;
}
```
**Nginx Proxy Manager:** create one Proxy Host for your domain with the main
forward to `:5000` (Websockets ON), then add Custom Locations for `/ws/id`
`:21118` and `/ws/relay``:21119` (Websockets ON on each). Use `http://`
backends unless Enterprise TLS is enabled on the Go server.
**Verify from the Docker host:**
```bash
curl -i -N \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
http://127.0.0.1:21118/ws/id
```
Expected: `HTTP/1.1 101 Switching Protocols`.
Full troubleshooting (TLS SNI errors, keepalive timeouts): see
[HTTPS Setup — RustDesk WSS](../setup/HTTPS_SETUP.md#rustdesk-client-wss-through-nginx).
---
**Updated:** January 2026
**Version:** v1.5.0