Docker: Build Optimization and Enhanced Non-Root/Volumeless Support (#5024) * docker: optimize build layers and enhance permission handling - Pre-created hardcoded dirs in Dockerfile to support volumeless non-root runs. - Enhanced slightly docker-entrypoint.sh with robust volume detection and safer chown logic. - Included legacy 'backups' directory... again. - Added dos2unix to install list. - Updated .dockerignore - Updated comments - Smaller fixes * fix(docker): removed unnecessary comment, and the... *sighs* backups dir, again * Exclude DS_Store everywhere * Exclude tests and all jsconfigs from docker images * Exclude local plugins from docker builds * fix(docker): backups are back... yay xD * feat(docker): add robust healthcheck script - Added `docker/healthcheck.cjs`: A standalone, dependency-free Node.js script for verifying server status. - Updated `Dockerfile`: Added HEALTHCHECK instruction and script copy step. - Features: Auto-detects port from env/config, handles IPv4/IPv6 fallback, auto-retries HTTPS on socket hangup, and sets custom User-Agent. * Fix .dockerignore permission * Revert "feat(docker): add robust healthcheck script" This reverts commit fa634fb08884cdef9245a12271cb9a13b487365f. --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

78651bdf560fae12da1d70e32e902a6e57f694b9

Pavdig <101715456+Pavdig@users.noreply.github.com>

Signed
3 files changed, +78 -45Showing whitespace changes
.dockerignore+55 -15
@@ -1,21 +1,61 @@
1# --- Git & CI ---
1.git2.git
2.github3.github
3.vscode4.gitignore
4node_modules5
5npm-debug.log6# --- Docker ---
6readme*7/Dockerfile
7Start.bat8/.dockerignore
8/dist9/docker/docker-compose.yml
9/backups
10cloudflared.exe
11access.log
12/data
13/cache
14.DS_Store
15/public/scripts/extensions/third-party
16/colab
17.gemini
18/docker/config10/docker/config
19/docker/extensions11/docker/extensions
20/docker/data12/docker/data
21/docker/plugins13/docker/plugins
14/public/scripts/extensions/third-party
15
16# --- Plugins (keep only package files) ---
17/plugins/*
18!/plugins/package.json
19!/plugins/package-lock.json
20
21# --- The Folders ---
22/backups
23/cache
24/colab
25/data
26/dist
27/node_modules
28/tests
29
30# --- Sensitive Info ---
31**/.env*
32**/*.pem
33**/certs
34
35# --- Documentation ---
36readme*
37*.md
38Update-Instructions.txt
39
40# --- OS & System Junk ---
41**/.DS_Store
42*.bat
43*.cmd
44*.exe
45start.sh
46
47# --- Dev Config ---
48.editorconfig
49.eslintrc.cjs
50.eslintrc*
51.vscode
52**/jsconfig.json
53.npmignore
54.gemini
55replit.nix
56.replit
57.nomedia
58
59# -- Logs & Temp ---
60*.log
61**/tmp
Dockerfile+10 -10
@@ -4,8 +4,8 @@ FROM node:lts-alpine3.23
4ARG APP_HOME=/home/node/app4ARG APP_HOME=/home/node/app
55
6# Install system dependencies6# Install system dependencies
7# Added su-exec and shadow to support optional PUID/PGID user mapping7# "Don't rely on the base image for tools; if you call it, you install it." ;)
8RUN apk add --no-cache gcompat tini git git-lfs su-exec shadow8RUN apk add --no-cache gcompat tini git git-lfs su-exec shadow dos2unix
99
10# Create app directory and set ownership10# Create app directory and set ownership
11WORKDIR ${APP_HOME}11WORKDIR ${APP_HOME}
@@ -21,28 +21,28 @@ RUN \
21 echo "*** Install npm packages ***" && \21 echo "*** Install npm packages ***" && \
22 npm ci --no-audit --no-fund --loglevel=error --no-progress --omit=dev && npm cache clean --force22 npm ci --no-audit --no-fund --loglevel=error --no-progress --omit=dev && npm cache clean --force
2323
24# Create config directory and link config.yaml24# Create config directory and link config.yaml. Added hardcoded dirs(constants.js?)
25# that must be present for Non-Root Mode and volumeless docker runs.
25RUN \26RUN \
26 rm -f "config.yaml" || true && \27 rm -f "config.yaml" || true && \
27 ln -s "./config/config.yaml" "config.yaml" || true && \28 mkdir -p config data plugins public/scripts/extensions/third-party backups && \
28 mkdir "config" || true29 chown -R node:node config data plugins public/scripts/extensions/third-party backups && \
29# Set ownership30 ln -s "./config/config.yaml" "config.yaml"
30RUN chown -R node:node config
3131
32# Pre-compile public libraries32# Pre-compile public libraries
33RUN \33RUN \
34 echo "*** Run Webpack ***" && \34 echo "*** Run Webpack ***" && \
35 node "./docker/build-lib.js"35 node "./docker/build-lib.js"
3636
37# Set the entrypoint script37# Set the entrypoint script and cleanup
38RUN \38RUN \
39 echo "*** Cleanup ***" && \39 echo "*** Cleanup ***" && \
40 mv "./docker/docker-entrypoint.sh" "./" && \40 mv "./docker/docker-entrypoint.sh" "./" && \
41 rm -rf "./docker" && \
42 echo "*** Make docker-entrypoint.sh executable ***" && \41 echo "*** Make docker-entrypoint.sh executable ***" && \
43 chmod +x "./docker-entrypoint.sh" && \42 chmod +x "./docker-entrypoint.sh" && \
44 echo "*** Convert line endings to Unix format ***" && \43 echo "*** Convert line endings to Unix format ***" && \
45 dos2unix "./docker-entrypoint.sh"44 dos2unix "./docker-entrypoint.sh" && \
45 rm -rf "./docker"
4646
47# Fix extension repos permissions47# Fix extension repos permissions
48RUN git config --global --add safe.directory "*"48RUN git config --global --add safe.directory "*"
docker/docker-entrypoint.sh+13 -20
@@ -8,7 +8,7 @@ start_sillytavern() {
8 # Config Check8 # Config Check
9 if [ ! -e "config/config.yaml" ]; then9 if [ ! -e "config/config.yaml" ]; then
10 echo "Resource not found, copying from defaults: config.yaml"10 echo "Resource not found, copying from defaults: config.yaml"
11 $PREFIX cp -r "default/config.yaml" "config/config.yaml"11 $PREFIX cp "default/config.yaml" "config/config.yaml"
12 fi12 fi
1313
14 # Execute postinstall to auto-populate config.yaml with missing values14 # Execute postinstall to auto-populate config.yaml with missing values
@@ -20,7 +20,7 @@ start_sillytavern() {
2020
21# Dirs that MUST be present at this point (e.g for volumeless docker runs).21# Dirs that MUST be present at this point (e.g for volumeless docker runs).
22# Please update list, if in the future a related perm issue appear.22# Please update list, if in the future a related perm issue appear.
23CORE_DIRS="config data plugins public/scripts/extensions/third-party"23CORE_DIRS="config data plugins public/scripts/extensions/third-party backups"
2424
25# Mounted Volumes (External)25# Mounted Volumes (External)
26# Parse mounts, handling files vs directories26# Parse mounts, handling files vs directories
@@ -35,11 +35,7 @@ for mount in $RAW_MOUNTS; do
3535
36 # Performance Safety: If the file is in the root of the app,36 # Performance Safety: If the file is in the root of the app,
37 # we do NOT add the parent (App Root), or we will recursively scan the whole app.37 # we do NOT add the parent (App Root), or we will recursively scan the whole app.
38 if [ "$PARENT_DIR" = "/home/node/app" ]; then38 [ "$PARENT_DIR" != "/home/node/app" ] && MOUNTED_DIRS="$MOUNTED_DIRS $PARENT_DIR" || MOUNTED_DIRS="$MOUNTED_DIRS $mount"
39 MOUNTED_DIRS="$MOUNTED_DIRS $mount"
40 else
41 MOUNTED_DIRS="$MOUNTED_DIRS $PARENT_DIR"
42 fi
43 else39 else
44 # It is a directory, add it directly40 # It is a directory, add it directly
45 MOUNTED_DIRS="$MOUNTED_DIRS $mount"41 MOUNTED_DIRS="$MOUNTED_DIRS $mount"
@@ -53,21 +49,19 @@ CHECK_DIRS=$(echo "$CORE_DIRS $MOUNTED_DIRS" | tr ' ' '\n' | sort -u)
53for dir in $CHECK_DIRS; do49for dir in $CHECK_DIRS; do
54 if [ ! -e "$dir" ]; then50 if [ ! -e "$dir" ]; then
55 echo "Creating missing directory: $dir"51 echo "Creating missing directory: $dir"
56 mkdir -p "$dir"52 mkdir -p "$dir" 2>/dev/null || echo "Warning: Could not create $dir" >&2
57 fi53 fi
58done54done
5955
60# Change permissions only if started as Root(UID 0) and needed.56# Mode Selection
61if [ "$(id -u)" = "0" ]; then57if [ "$(id -u)" = "0" ]; then
62 # Check if PUID/PGID variables are provided58 # Check if PUID/PGID variables are provided
63 if [ -n "$PUID" ] && [ -n "$PGID" ]; then59 if [ -n "$PUID" ] && [ -n "$PGID" ]; then
64 TARGET_UID=$PUID60 echo "Mode: PUID/PGID (UID:$PUID GID:$PGID)"
65 TARGET_GID=$PGID
66 echo "Non-root mode requested (UID:$TARGET_UID GID:$TARGET_GID)."
6761
68 # Update the internal 'node' user to match requested IDs62 # Update the internal 'node' user to match requested IDs
69 groupmod -o -g "$TARGET_GID" node63 groupmod -o -g "$PGID" node
70 usermod -o -u "$TARGET_UID" -g "$TARGET_GID" node64 usermod -o -u "$PUID" -g "$PGID" node
7165
72 for dir in $CHECK_DIRS; do66 for dir in $CHECK_DIRS; do
73 if [ -d "$dir" ]; then67 if [ -d "$dir" ]; then
@@ -75,11 +69,9 @@ if [ "$(id -u)" = "0" ]; then
75 DIR_UID=$(stat -c '%u' "$dir")69 DIR_UID=$(stat -c '%u' "$dir")
76 DIR_GID=$(stat -c '%g' "$dir")70 DIR_GID=$(stat -c '%g' "$dir")
7771
78 if [ "$DIR_UID" != "$TARGET_UID" ] || [ "$DIR_GID" != "$TARGET_GID" ]; then72 if [ "$DIR_UID" != "$PUID" ] || [ "$DIR_GID" != "$PGID" ]; then
79 echo "(Detected mismatch) Adjusting permissions for: $dir."73 echo "(Detected mismatch) Adjusting permissions for: $dir."
80 if ! chown -R node:node "$dir"; then74 chown -R node:node "$dir" || echo "Warning: Failed to update permissions for '$dir'." >&2
81 echo "Error: Failed to update permissions for '$dir'."
82 fi
83 fi75 fi
84 fi76 fi
85 done77 done
@@ -87,16 +79,17 @@ if [ "$(id -u)" = "0" ]; then
87 # Fix config file specifically79 # Fix config file specifically
88 chown node:node "config/config.yaml" 2>/dev/null80 chown node:node "config/config.yaml" 2>/dev/null
8981
82 # Set execution prefix to run as 'node' user
90 EXEC_PREFIX="su-exec node:node"83 EXEC_PREFIX="su-exec node:node"
91 else84 else
92 # Default: Run as Root (original behavior)85 # Default: Run as Root (original behavior)
93 echo "Running in default (root) mode."86 echo "Mode: Default (Root)"
94 EXEC_PREFIX=""87 EXEC_PREFIX=""
95 fi88 fi
9689
97else90else
98 # Non-Root Mode (Docker CLI --user flag)91 # Non-Root Mode (Docker CLI --user flag)
99 echo "Running as detected user (UID: $(id -u))."92 echo "Mode: Strict Non-Root (UID: $(id -u))"
100 # We CANNOT auto-fix permissions in this mode because we lack privileges.93 # We CANNOT auto-fix permissions in this mode because we lack privileges.
101 # Relying solely on the user configuring their host permissions correctly.94 # Relying solely on the user configuring their host permissions correctly.
102 EXEC_PREFIX=""95 EXEC_PREFIX=""