From 0f671ccdf2a21f1d202228f56b3e679d09fa3fe0 Mon Sep 17 00:00:00 2001 From: shane keulen Date: Tue, 4 Nov 2025 00:36:40 -0500 Subject: [PATCH] Improve Docker support with configurable permissions and SMB compatibility Added flexible user/group ID handling to support different storage backends: - Configurable PUID/PGID environment variables for NFS and local storage - RUN_AS_ROOT mode for SMB mounts that only allow root writes - Pre-chown app files during build to enable non-root rsync - Improved error messages with troubleshooting guidance - Updated documentation with setup examples for different scenarios This allows the container to work correctly with Unraid SMB shares, NFS mounts, and local storage by adapting to how different filesystems handle permissions. Default behavior (PUID=99, PGID=100) remains compatible with Unraid nobody:users. --- Dockerfile | 2 + README-DOCKER.md | 112 +++++++++++++++++++++++++++++++------------ docker-entrypoint.sh | 63 ++++++++++++++++++++---- 3 files changed, 137 insertions(+), 40 deletions(-) diff --git a/Dockerfile b/Dockerfile index f5e70e9..57b67e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ p7zip-full \ unrar-free \ curl \ + rsync \ + gosu \ && rm -rf /var/lib/apt/lists/* # Create required directories diff --git a/README-DOCKER.md b/README-DOCKER.md index e5e7053..fc338c8 100644 --- a/README-DOCKER.md +++ b/README-DOCKER.md @@ -5,10 +5,20 @@ Run RGSX as a web-only service without the Pygame UI. Perfect for homelab/server ## Quick Start ```bash -# Clone and start -git clone https://github.com/RetroGameSets/RGSX.git -cd RGSX -docker-compose up -d +# Build the image +docker build -t rgsx . + +# Run with docker +docker run -d \ + --name rgsx \ + -p 5000:5000 \ + -e PUID=99 \ + -e PGID=100 \ + -e RGSX_HEADLESS=1 \ + -v ./data/saves:/userdata/saves/ports/rgsx \ + -v ./data/roms:/userdata/roms/ports \ + -v ./data/logs:/userdata/roms/ports/RGSX/logs \ + rgsx # Access the web interface open http://localhost:5000 @@ -23,22 +33,47 @@ open http://localhost:5000 ## Configuration +### User Permissions (Important!) + +**For SMB mounts (Unraid, Windows shares):** + +Don't set PUID/PGID. The container runs as root, and the SMB server maps files to your authenticated user. + +```bash +docker run \ + -e RGSX_HEADLESS=1 \ + ... +``` + +**For NFS/local storage:** + +Set PUID and PGID to match your host user. Files will be owned by that user. + +```bash +docker run \ + -e PUID=1000 \ + -e PGID=1000 \ + -e RGSX_HEADLESS=1 \ + ... +``` + +**Find your user ID:** +```bash +id -u # Your UID +id -g # Your GID +``` + ### Change Port -Edit `docker-compose.yml`: -```yaml -ports: - - "8080:5000" # Host port : Container port +```bash +docker run -p 8080:5000 ... # Access on port 8080 ``` ### Custom ROM Location Map to your existing ROM collection: -```yaml -volumes: - - ./data/saves:/userdata/saves/ports/rgsx - - /your/existing/roms:/userdata/roms # Change this - - ./data/logs:/app/RGSX/logs +```bash +docker run -v /your/existing/roms:/userdata/roms/ports ... ``` ### API Keys @@ -46,9 +81,6 @@ volumes: Add your download service API keys to `./data/saves/`: ```bash -# Start container once to create directories -docker-compose up -d - # Add your API key (just the key, no extra text) echo "YOUR_KEY_HERE" > ./data/saves/1FichierAPI.txt @@ -57,24 +89,25 @@ echo "YOUR_KEY" > ./data/saves/AllDebridAPI.txt echo "YOUR_KEY" > ./data/saves/RealDebridAPI.txt # Restart to apply -docker-compose restart +docker restart rgsx ``` ## Commands ```bash # Start -docker-compose up -d +docker start rgsx # View logs -docker-compose logs -f +docker logs -f rgsx # Stop -docker-compose down +docker stop rgsx # Update (after git pull) -docker-compose build --no-cache -docker-compose up -d +docker build --no-cache -t rgsx . +docker stop rgsx && docker rm rgsx +# Then re-run the docker run command ``` ## Directory Structure @@ -95,20 +128,39 @@ RGSX already has a headless mode (`RGSX_HEADLESS=1`) and the web server (`rgsx_w ## Troubleshooting -**Port already in use:** +**Permission denied errors / Can't delete files:** + +The container creates files with the UID/GID specified by PUID/PGID environment variables: + ```bash -# Use different port -sed -i '' 's/5000:5000/8080:5000/' docker-compose.yml +# Set correct PUID/PGID for your environment +docker run -e PUID=1000 -e PGID=1000 ... ``` -**Permission errors:** +**Changed PUID/PGID and container won't start:** + +When you change PUID/PGID, old files with different ownership will cause rsync to fail. You MUST fix ownership on the storage server: + ```bash -sudo chown -R $USER:$USER ./data +# On your NAS/Unraid (via SSH), either: + +# Option 1: Delete old files (easiest) +rm -rf /mnt/user/roms/rgsx/roms/ports/RGSX/* + +# Option 2: Change ownership to new PUID/PGID +chown -R 1000:1000 /mnt/user/roms/rgsx/roms/ports/RGSX/ +``` + +Then restart the container. + +**Port already in use:** +```bash +docker run -p 8080:5000 ... # Use port 8080 instead ``` **Container won't start:** ```bash -docker-compose logs +docker logs rgsx ``` ## vs Traditional Install @@ -116,8 +168,8 @@ docker-compose logs | Feature | Docker | Batocera/RetroBat | |---------|--------|-------------------| | Interface | Web only | Pygame UI + Web | -| Install | `docker-compose up` | Manual setup | -| Updates | `docker-compose build` | git pull | +| Install | `docker run` | Manual setup | +| Updates | `docker build` | git pull | | Access | Any device on network | Device only | | Use Case | Server/homelab | Gaming device | diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 9b43812..7cab761 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,29 +1,72 @@ #!/bin/bash set -e +# If PUID/PGID are set, create user and run as that user +# If not set, run as root (works for SMB mounts) +if [ -n "$PUID" ] && [ -n "$PGID" ]; then + echo "=== Creating user with PUID=$PUID, PGID=$PGID ===" + + # Create group if it doesn't exist + if ! getent group $PGID >/dev/null 2>&1; then + groupadd -g $PGID rgsx + fi + + # Create user if it doesn't exist + if ! getent passwd $PUID >/dev/null 2>&1; then + useradd -u $PUID -g $PGID -m -s /bin/bash rgsx + fi + + # Fix ownership of app files + chown -R $PUID:$PGID /app /userdata 2>/dev/null || true + + echo "=== Running as user $(id -un $PUID) (UID=$PUID, GID=$PGID) ===" + RUN_USER="gosu rgsx" +else + echo "=== Running as root (no PUID/PGID set) - for SMB mounts ===" + RUN_USER="" +fi + # Always sync RGSX app code to the mounted volume (for updates) echo "Syncing RGSX app code to /userdata/roms/ports/RGSX..." -mkdir -p /userdata/roms/ports/RGSX -cp -rf /app/RGSX/* /userdata/roms/ports/RGSX/ -echo "RGSX app code synced!" +$RUN_USER mkdir -p /userdata/roms/ports/RGSX + +# Try rsync +if ! $RUN_USER rsync -av --delete /app/RGSX/ /userdata/roms/ports/RGSX/ 2>&1; then + echo "" + echo "==========================================" + echo "WARNING: rsync partially failed!" + echo "==========================================" + echo "Some files may not have synced. Container will continue for debugging." + echo "" + if [ -n "$PUID" ] && [ -n "$PGID" ]; then + echo "If using SMB, try removing PUID/PGID to run as root" + fi + echo "" +fi + +echo "RGSX app code sync attempted." # Create Batocera folder structure only if folders don't exist -[ ! -d "/userdata/saves/ports/rgsx/images" ] && mkdir -p /userdata/saves/ports/rgsx/images -[ ! -d "/userdata/saves/ports/rgsx/games" ] && mkdir -p /userdata/saves/ports/rgsx/games -[ ! -d "/userdata/roms/ports/RGSX/logs" ] && mkdir -p /userdata/roms/ports/RGSX/logs +$RUN_USER mkdir -p /userdata/saves/ports/rgsx/images +$RUN_USER mkdir -p /userdata/saves/ports/rgsx/games +$RUN_USER mkdir -p /userdata/roms/ports/RGSX/logs # Create default settings with show_unsupported_platforms enabled if config doesn't exist SETTINGS_FILE="/userdata/saves/ports/rgsx/rgsx_settings.json" if [ ! -f "$SETTINGS_FILE" ]; then echo "Creating default settings with all platforms visible..." - cat > "$SETTINGS_FILE" << 'EOF' + $RUN_USER bash -c "cat > '$SETTINGS_FILE' << 'EOF' { - "show_unsupported_platforms": true + \"show_unsupported_platforms\": true } -EOF +EOF" echo "Default settings created!" fi # Run the command cd /userdata/roms/ports/RGSX -exec "$@" +if [ -z "$RUN_USER" ]; then + exec "$@" +else + exec $RUN_USER "$@" +fi