From ab887457bb74097b1a6b46a3dfaf3bcdb767340a Mon Sep 17 00:00:00 2001
From: Thales Pereira <31625914+thcp@users.noreply.github.com>
Date: Sun, 12 Jul 2026 21:21:24 +0100
Subject: [PATCH] feat(docker): honor PUID/PGID so Unraid gets nobody:users
ownership
The container hardcoded UID 1001, so files written to mounted appdata were
owned by 1001 rather than Unraid's nobody:users (99:100), causing permission
friction (discussion #255).
The entrypoint now reads PUID/PGID (default 1001, preserving prior behaviour),
chowns the writable paths (/app/jobs, /cache, settings.json) to them, and
drops to that UID:GID via gosu. Expose PUID=99 / PGID=100 as template
variables so Unraid installs get correct ownership out of the box.
---
build/docker-entrypoint.sh | 26 ++++++++++++++++++++------
templates/stemdeck.xml | 4 ++++
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/build/docker-entrypoint.sh b/build/docker-entrypoint.sh
index ef951426..99e6b924 100644
--- a/build/docker-entrypoint.sh
+++ b/build/docker-entrypoint.sh
@@ -1,8 +1,22 @@
#!/bin/sh
set -e
-# Re-chown /app/jobs in case the bind-mount was created by Docker as root
-# on first run (before the host directory existed). Safe no-op if already
-# owned by app:app.
-chown -R app:app /app/jobs 2>/dev/null || true
-# Drop to the non-root app user and exec the CMD.
-exec gosu app "$@"
+# Run as the requested UID/GID so files written to the mounted appdata paths are
+# owned consistently. This matches the Unraid/NAS convention (defaults there are
+# nobody:users = 99:100). When PUID/PGID are unset, fall back to the image's
+# original non-root app user (1001), preserving prior behaviour.
+PUID="${PUID:-1001}"
+PGID="${PGID:-1001}"
+
+# Chown the only paths the app writes to before dropping privileges:
+# /app/jobs registry.json, downloaded audio, and stems
+# /cache torch/Demucs model weights (TORCH_HOME, XDG_CACHE_HOME)
+# /app/settings.json best-effort settings persistence (created on demand)
+# App code and the venv under /app stay world-readable, so a different UID can
+# still import and run them. Re-chowning is also what fixes a bind mount that
+# Docker created as root on first run.
+chown -R "${PUID}:${PGID}" /app/jobs /cache 2>/dev/null || true
+touch /app/settings.json 2>/dev/null && chown "${PUID}:${PGID}" /app/settings.json 2>/dev/null || true
+
+# Drop to the target user and exec the CMD. gosu accepts a numeric UID:GID even
+# when no matching named user exists.
+exec gosu "${PUID}:${PGID}" "$@"
diff --git a/templates/stemdeck.xml b/templates/stemdeck.xml
index 00574c6a..21ca992b 100644
--- a/templates/stemdeck.xml
+++ b/templates/stemdeck.xml
@@ -51,6 +51,10 @@
3
+ 99
+
+ 100
+
all
all