feat: add Melo's stylish UI support for Docker containers (#7475)
* feat: add Melo's stylish UI support for containers * chore: add fallback echo * feat: integrate suggestions * chore: edit Debian Dockerfile as well * chore: bump to absolute paths * chore: rename variable --------- Co-authored-by: DaanSelen <dselen@systemec.nl>
DaanSelen committed
Dec 16, 2025 at 15:19 UTC
a0a6b4a9e564b229771c54bb171e8b928581dbde
3 files changed
+124
-34
docker/Dockerfile
+6
-4
@@ -78,14 +78,16 @@ ENV NODE_ENV="production" \
78
ENV ALLOW_PLUGINS="false" \
79
ALLOW_NEW_ACCOUNTS="false" \
80
ALLOWED_ORIGIN="false" \
81
+ HOSTNAME="localhost" \
82
+ INSTALL_STYLISHUI="false" \
83
IFRAME="false" \
82
- REGEN_SESSIONKEY="false" \
83
- WEBRTC="false" \
84
LOCAL_SESSION_RECORDING="true" \
85
MINIFY="true" \
86
- HOSTNAME="localhost" \
86
REVERSE_PROXY="" \
87
REVERSE_PROXY_TLS_PORT="443" \
88
+ REGEN_SESSIONKEY="false" \
89
+ STYLISHUI_FORCE_LATEST="false" \
90
+ WEBRTC="false" \
91
TRUSTED_PROXY="" \
92
ARGS=""
93
@@ -208,4 +210,4 @@ VOLUME /opt/meshcentral/meshcentral-backups
210
COPY ./docker/entrypoint.sh /opt/meshcentral/entrypoint.sh
211
COPY ./docker/config.json.template /opt/meshcentral/config.json.template
212
211
-ENTRYPOINT ["bash", "/opt/meshcentral/entrypoint.sh"]
\ No newline at end of file
213
+ENTRYPOINT ["/bin/bash", "/opt/meshcentral/entrypoint.sh"]
docker/Dockerfile-debian
+6
-4
@@ -104,14 +104,16 @@ ENV NODE_ENV="production" \
104
ENV ALLOW_PLUGINS="false" \
105
ALLOW_NEW_ACCOUNTS="false" \
106
ALLOWED_ORIGIN="false" \
107
+ HOSTNAME="localhost" \
108
+ INSTALL_STYLISHUI="false" \
109
IFRAME="false" \
108
- REGEN_SESSIONKEY="false" \
109
- WEBRTC="false" \
110
LOCAL_SESSION_RECORDING="true" \
111
MINIFY="true" \
112
- HOSTNAME="localhost" \
112
REVERSE_PROXY="" \
113
REVERSE_PROXY_TLS_PORT="443" \
114
+ REGEN_SESSIONKEY="false" \
115
+ STYLISHUI_FORCE_LATEST="false" \
116
+ WEBRTC="false" \
117
TRUSTED_PROXY="" \
118
ARGS=""
119
@@ -235,4 +237,4 @@ VOLUME /opt/meshcentral/meshcentral-backups
237
COPY ./docker/entrypoint.sh /opt/meshcentral/entrypoint.sh
238
COPY ./docker/config.json.template /opt/meshcentral/config.json.template
239
238
-ENTRYPOINT ["bash", "/opt/meshcentral/entrypoint.sh"]
\ No newline at end of file
240
+ENTRYPOINT ["/bin/bash", "/opt/meshcentral/entrypoint.sh"]
docker/entrypoint.sh
+112
-26
@@ -1,6 +1,10 @@
1
#!/bin/bash
2
3
-graceful_shutdown() {
3
+# Origin: https://github.com/Melo-Professional/MeshCentral-Stylish-UI
4
+stylishui_base_url="https://github.com/Melo-Professional/MeshCentral-Stylish-UI/archive/refs"
5
+stylishui_compat="https://raw.githubusercontent.com/Melo-Professional/MeshCentral-Stylish-UI/refs/heads/main/metadata/compat.json"
6
+
7
+function graceful_shutdown() {
8
echo "Received SIGTERM from the container host. Cleaning up..."
9
kill -SIGINT $meshcentral_pid
10
@@ -9,33 +13,18 @@ graceful_shutdown() {
13
}
14
trap graceful_shutdown SIGTERM
15
12
-### Start MeshCentral Docker Container.
13
-
14
-# Make the start more cleared when restarted.
15
-echo "-------------------------------------------------------------"
16
-date
17
-if [ -n "$CONFIG_FILE" ]; then
18
- echo "Config file: $CONFIG_FILE"
19
-else
20
- exit 1
21
-fi
22
-
23
-# Failsafe to create a new config if the expected config is not there.
24
-if [ -f "${CONFIG_FILE}" ]; then
25
- echo "Pre-existing config found, not recreating..."
26
-else
27
- if [ ! -d $(dirname "$CONFIG_FILE") ]; then
28
- echo "Creating meshcentral-data directory..."
29
- mkdir -p /opt/meshcentral/meshcentral-data
16
+function test_url() {
17
+ wget --spider $1 &> /dev/null
18
+ if [[ $? -eq 0 ]]; then
19
+ echo "is ok."
20
+ return 0
21
+ else
22
+ echo "is NOT ok."
23
+ return 1
24
fi
25
+}
26
32
- echo "Placing template into the relevant directory: $(dirname $CONFIG_FILE)"
33
- cp /opt/meshcentral/config.json.template "${CONFIG_FILE}"
34
-fi
35
-
36
-if [[ ${DYNAMIC_CONFIG,,} =~ ^(true|yes)$ ]]; then
37
- echo "Using Dynamic Configuration values..."
38
-
27
+function dynamic_config() {
28
# BEGIN DATABASE CONFIGURATION FIELDS
29
USE_MONGODB=${USE_MONGODB,,}
30
if [[ $USE_MONGODB =~ ^(true|yes)$ ]]; then
@@ -269,12 +258,109 @@ if [[ ${DYNAMIC_CONFIG,,} =~ ^(true|yes)$ ]]; then
258
fi
259
260
cat "$CONFIG_FILE"
261
+}
262
+
263
+function install_stylishui() {
264
+ # Start by testing if we can determine compatibility
265
+ printf "Testing compatibility schema URL..."
266
+ if ! test_url $stylishui_compat; then
267
+ echo "Compat URL failed."
268
+ return 1
269
+ fi
270
+
271
+ if [[ ${STYLISHUI_FORCE_LATEST,,} =~ ^(true|yes)$ ]]; then
272
+ echo "Overriding to main branch..."
273
+ full_url="${stylishui_base_url}/heads/main.tar.gz"
274
+ else
275
+ # Retrieve the values we need to determine compatibility
276
+ compat_data=$(curl -fsSL $stylishui_compat)
277
+ meshcentral_version=$(jq -r '.version' /opt/meshcentral/meshcentral/package.json)
278
+ # Target the StylishUI version we need for our present Meshcentral version
279
+ compat_version=$(echo "$compat_data" | jq -r --arg mcv "$meshcentral_version" \
280
+ '.compatibility[] | select(.meshcentral==$mcv) | .stylishui')
281
+ echo "Data: MeshCentral: $meshcentral_version, matched StylishUI: $compat_version"
282
+
283
+ # From the data gathered above, compile the whole URL.
284
+ full_url="${stylishui_base_url}/tags/${compat_version}.tar.gz"
285
+ fi
286
+
287
+ # Test if we can reach the data/content URL on github
288
+ printf "Testing content URL..."
289
+ if ! test_url $full_url; then
290
+ echo "StylishUI URL failed."
291
+ return 1
292
+ fi
293
+
294
+ # Lets download and install the UI
295
+ wget -O /tmp/stylishui.tar.gz $full_url > /dev/null
296
+ tar -xzf /tmp/stylishui.tar.gz -C /tmp
297
+ web_folder=$(find /tmp -name meshcentral-web)
298
+
299
+ # Check if we have some integrity
300
+ if [[ -z $web_folder ]]; then
301
+ echo "Installation failed, cleaning..."
302
+ rm /tmp/stylishui*
303
+ return 1
304
+ fi
305
+
306
+ # Looks good!
307
+ echo Found extracted contents at: $web_folder
308
+ mv ${web_folder}/* /opt/meshcentral/meshcentral-web
309
+ rm /tmp/stylishui*
310
+
311
+ return 0
312
+}
313
+
314
+### Start MeshCentral Docker Container.
315
+
316
+### BEGIN MAIN CHAIN
317
+
318
+# Make the start more cleared when restarted.
319
+echo "-------------------------------------------------------------"
320
+date
321
+if [ -n "$CONFIG_FILE" ]; then
322
+ echo "Config file: $CONFIG_FILE"
323
+else
324
+ exit 1
325
+fi
326
+
327
+# Failsafe to create a new config if the expected config is not there.
328
+if [ -f "${CONFIG_FILE}" ]; then
329
+ echo "Pre-existing config found, not recreating..."
330
+else
331
+ if [ ! -d $(dirname "$CONFIG_FILE") ]; then
332
+ echo "Creating meshcentral-data directory..."
333
+ mkdir -p /opt/meshcentral/meshcentral-data
334
+ fi
335
+
336
+ echo "Placing template into the relevant directory: $(dirname $CONFIG_FILE)"
337
+ cp /opt/meshcentral/config.json.template "${CONFIG_FILE}"
338
+fi
339
+
340
+if [[ ${DYNAMIC_CONFIG,,} =~ ^(true|yes)$ ]]; then
341
+ echo "-------------------------------------------------------------"
342
+ echo "Using Dynamic Configuration values..."
343
+ dynamic_config
344
+ echo "-------------------------------------------------------------"
345
else
346
echo "Leaving config as-is. Dynamic Configuration is off."
347
fi
348
349
+if [[ ${INSTALL_STYLISHUI,,} =~ ^(true|yes)$ ]]; then
350
+ echo "-------------------------------------------------------------"
351
+ echo "Reached StylishUI install trigger, installing..."
352
+ if ! install_stylishui; then
353
+ echo "Something fatal happened in the StylishUI install. Skipping..."
354
+ else
355
+ echo "StylishUI has been installed!"
356
+ fi
357
+ echo "-------------------------------------------------------------"
358
+fi
359
+
360
# Actually start MeshCentral.
361
node /opt/meshcentral/meshcentral/meshcentral --configfile "${CONFIG_FILE}" "${ARGS}" >> /proc/1/fd/1 &
362
meshcentral_pid=$!
363
364
wait "$meshcentral_pid"
365
+
366
+### END MAIN CHAIN