Use gosu for reliable UID:GID switching

Fix PUID/PGID collision issues by using gosu to run services with exact UID:GID. Changes include:

- Added redis-start.sh and updated app-start.sh to load /etc/environment, determine PUID/PGID, and invoke gosu "$PUID:$PGID" to start Redis and the Next.js app (with verification and fallbacks).
- Updated entrypoint.sh to persist PUID/PGID into /etc/environment, document the gosu approach, and adjust startup messaging.
- Updated supervisord.conf to run the new startup wrappers as root (so they can use gosu) instead of running processes directly as specific users.
- Dockerfile updated to install gosu and copy the redis-start.sh wrapper.
- Documentation updated (deployment/unified.md) describing the PUID collision bug, the root cause, and the gosu-based fix.

This resolves cases where PUID collides with existing system users (e.g., nobody) which previously caused processes to run with the wrong GID and produce EACCES errors.
This commit is contained in:
kikootwo
2026-02-02 20:19:09 -05:00
parent 0864fa7b43
commit 0d64b90fd0
6 changed files with 123 additions and 23 deletions
+49 -12
View File
@@ -1,22 +1,59 @@
#!/bin/bash
# App startup wrapper for unified container
# Starts Next.js server and initializes services
# Uses gosu to ensure correct PUID:PGID for file operations
set -e
# Load environment from /etc/environment (set by entrypoint)
if [ -f /etc/environment ]; then
set -a
source /etc/environment
set +a
fi
# Get PUID/PGID (default to node user's current IDs if not set)
PUID=${PUID:-$(id -u node)}
PGID=${PGID:-$(id -g node)}
echo "[App] Starting Next.js server..."
echo "[App] Process will run as UID:GID = $PUID:$PGID"
cd /app
# Start server in background
node server.js &
SERVER_PID=$!
# Use gosu to switch to correct UID:GID and start server
# This bypasses username resolution issues when PUID collides with existing users
if [ "$(id -u)" = "0" ]; then
# Running as root - use gosu to switch to PUID:PGID
echo "[App] Switching to UID:GID $PUID:$PGID via gosu..."
echo "[App] Waiting for server to be ready..."
sleep 5
# Start server in background with gosu
gosu "$PUID:$PGID" node server.js &
SERVER_PID=$!
# Initialize application services (creates default scheduled jobs)
echo "[App] Initializing application services..."
curl -f http://localhost:3030/api/init || echo "[App] ⚠️ Warning: Failed to initialize services"
echo "[App] Waiting for server to be ready..."
sleep 5
echo "[App] Server ready with PID $SERVER_PID"
# Initialize application services (creates default scheduled jobs)
echo "[App] Initializing application services..."
curl -sf http://localhost:3030/api/init || echo "[App] Warning: Failed to initialize services (may already be initialized)"
# Wait for server process
wait $SERVER_PID
echo "[App] Server ready with PID $SERVER_PID (running as $PUID:$PGID)"
# Verify the process is running with correct UID:GID
if [ -f "/proc/$SERVER_PID/status" ]; then
ACTUAL_UID=$(grep '^Uid:' /proc/$SERVER_PID/status | awk '{print $2}')
ACTUAL_GID=$(grep '^Gid:' /proc/$SERVER_PID/status | awk '{print $2}')
echo "[App] Verified process credentials: UID=$ACTUAL_UID GID=$ACTUAL_GID"
if [ "$ACTUAL_UID" != "$PUID" ] || [ "$ACTUAL_GID" != "$PGID" ]; then
echo "[App] WARNING: Process UID:GID ($ACTUAL_UID:$ACTUAL_GID) does not match expected ($PUID:$PGID)"
fi
fi
# Wait for server process
wait $SERVER_PID
else
# Not running as root - just run directly (fallback)
echo "[App] Warning: Not running as root, cannot use gosu. Running as current user."
exec node server.js
fi