mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 01:27:11 +00:00
7f7479fb88
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)
625 lines
15 KiB
Markdown
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
|