Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
160 lines (136 loc) · 5.82 KB
/
Copy pathDockerfile
File metadata and controls
160 lines (136 loc) · 5.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# check=skip=SecretsUsedInArgOrEnv
# BetterDesk — Single Container Image
# =====================================
# Combines Go server (signal + relay + API) and Node.js web console
# into a single container using supervisord as process manager.
#
# Build: docker build -t betterdesk:local .
# Run: docker compose up -d
#
# Ports:
# 21121 - HTTP API (Go server: RustDesk client API + REST)
# 21115 - NAT type test
# 21116 - Signal TCP/UDP
# 21117 - Relay TCP
# 21118 - WebSocket Signal
# 21119 - WebSocket Relay
# 5000 - Web Console (Node.js admin panel)
# ============= Stage 1: Build Go server =============
FROM golang:1.26.10-alpine AS go-builder
ARG TARGETARCH
# Retry apk in case of transient DNS failures (common on AlmaLinux/CentOS Docker)
RUN apk add --no-cache git || { sleep 2 && apk add --no-cache git; }
WORKDIR /src
COPY betterdesk-server/go.mod betterdesk-server/go.sum ./
RUN go mod download
COPY betterdesk-server/ .
ARG BETTERDESK_PRODUCT_VERSION=dev
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build \
-ldflags="-s -w -X main.Version=${BETTERDESK_PRODUCT_VERSION}" \
-tags "netgo osusergo" \
-o /betterdesk-server .
# ============= Stage 2: Build Node.js console =============
# TEMPORARY: Node 24.19.0 triggers a native better-sqlite3 cleanup-hook
# assertion during Statement GC. Keep the production console on the latest
# Node 22 LTS patch until the Node 24 backport is released and validated.
FROM node:22.23.2-alpine3.24 AS node-builder
WORKDIR /app
# Build dependencies for native modules (better-sqlite3, bcrypt)
# Note: sqlite-dev is NOT needed — better-sqlite3 bundles its own SQLite
RUN apk add --no-cache python3 make g++ || { sleep 2 && apk add --no-cache python3 make g++; }
COPY web-nodejs/package.json web-nodejs/package-lock.json* ./
RUN npm ci --omit=dev
# ============= Stage 3: Production runtime =============
# Note: supervisord requires root to manage child processes with user= directive.
# Both betterdesk-server and betterdesk-console run as non-root 'betterdesk' user
# via supervisord configuration (user=betterdesk).
FROM node:22.23.2-alpine3.24
LABEL maintainer="UNITRONIX"
LABEL description="BetterDesk — All-in-One (Go Server + Node.js Console)"
LABEL version="3.5.224"
# Install runtime packages (retry for transient DNS failures)
RUN apk add --no-cache \
ca-certificates \
curl \
sqlite \
tini \
supervisor \
su-exec \
shadow \
&& mkdir -p /var/log/supervisor \
|| { sleep 2 && apk add --no-cache \
ca-certificates \
curl \
sqlite \
tini \
supervisor \
su-exec \
shadow \
&& mkdir -p /var/log/supervisor; }
# The production image never runs npm; remove its bundled CLI and transitive
# package tree (including tar) from the runtime attack surface.
RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
# Create betterdesk user and directories
RUN addgroup -g 10001 -S betterdesk && \
adduser -u 10001 -S -G betterdesk betterdesk && \
mkdir -p /opt/rustdesk /app/data /var/log/betterdesk && \
chown -R betterdesk:betterdesk /opt/rustdesk /app/data /var/log/betterdesk
# ---- Go server binary ----
COPY --from=go-builder /betterdesk-server /usr/local/bin/betterdesk-server
RUN chmod +x /usr/local/bin/betterdesk-server
# ---- Node.js console ----
WORKDIR /app
# IMPORTANT: Copy app code FIRST, then overlay compiled node_modules.
# This prevents local node_modules (if any) from overwriting the
# properly compiled Alpine/musl native modules from the builder.
COPY web-nodejs/ .
COPY --from=node-builder /app/node_modules ./node_modules/
ARG BETTERDESK_COMMIT_SHA=unknown
ARG BETTERDESK_IMAGE_VERSION=unknown
ENV BETTERDESK_IMAGE_SHA=${BETTERDESK_COMMIT_SHA}
ENV BETTERDESK_IMAGE_VERSION=${BETTERDESK_IMAGE_VERSION}
ENV BETTERDESK_UPDATE_MODE=image
RUN printf '%s\n' "${BETTERDESK_COMMIT_SHA}" > /app/.image-commit
# ---- Supervisord config ----
COPY docker/supervisord.conf /etc/supervisor/conf.d/betterdesk.conf
# ---- Entrypoint ----
COPY docker/ensure-app-user.sh /ensure-app-user.sh
COPY docker/entrypoint.sh /entrypoint.sh
COPY docker/bootstrap-admin-credentials.sh /docker/bootstrap-admin-credentials.sh
COPY docker/guard-sqlite-auth-split.sh /docker/guard-sqlite-auth-split.sh
COPY docker/wait-panel-auth-db.sh /app/docker/wait-panel-auth-db.sh
COPY docker/show-admin-credentials.sh /usr/local/bin/betterdesk-show-admin-credentials
RUN chmod +x /ensure-app-user.sh /entrypoint.sh /docker/bootstrap-admin-credentials.sh /docker/guard-sqlite-auth-split.sh /app/docker/wait-panel-auth-db.sh /usr/local/bin/betterdesk-show-admin-credentials
# Environment variables (defaults)
ENV NODE_ENV=production
ENV PORT=5000
ENV SIGNAL_PORT=21116
ENV SIGNAL_RATE_LIMIT_PER_IP=20
ENV HOST=0.0.0.0
ENV API_HOST=0.0.0.0
ENV DATA_DIR=/app/data
ENV RUSTDESK_PATH=/opt/rustdesk
ENV DB_PATH=/opt/rustdesk/db_v2.sqlite3
ENV PUB_KEY_PATH=/opt/rustdesk/id_ed25519.pub
ENV API_KEY_PATH=/opt/rustdesk/.api_key
ENV SERVER_BACKEND=betterdesk
# API consolidated onto the Go server (21121); console proxies to it and does
# not run its own client API listener.
ENV API_ENABLED=false
ENV HBBS_API_URL=http://127.0.0.1:21121/api
ENV BETTERDESK_API_URL=http://127.0.0.1:21121/api
ENV DOCKER=true
ENV ENCRYPTED_ONLY=1
ENV RELAY_SERVERS=
# Billing clock / NTP — required by supervisord %(ENV_*)s (#299 / #223)
ENV NTP_SERVERS=pool.ntp.org,time.google.com,time.cloudflare.com
ENV BILLING_MAX_CLOCK_SKEW_MS=2000
ENV BILLING_REQUIRE_SYNCED_CLOCK=1
ENV BILLING_TRUST_OS_NTP=Y
# Expose all ports
EXPOSE 5000 21115 21116/tcp 21116/udp 21117 21118 21119 21121
# Health check: both Go server API and Node.js console must be healthy
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -sf http://localhost:21121/api/health && curl -sf http://localhost:5000/health || exit 1
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/entrypoint.sh"]