diff --git a/Dockerfile b/Dockerfile index d42df26..eb0e8a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,8 +56,8 @@ RUN cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ # --------------------------------------------------------------------------- FROM debian:bookworm-slim AS runtime -# Shared libraries the daemon + plugin load at runtime, plus CA certs for -# HTTPS RSS feeds / tracker announces. +# Shared libraries the daemon + plugin load at runtime, CA certs for HTTPS RSS +# feeds / tracker announces, and gosu to drop privileges to PUID/PGID at start. RUN apt-get update && apt-get install -y --no-install-recommends \ liburing2 \ libssl3 \ @@ -65,8 +65,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ liblua5.4-0 \ libsqlite3-0 \ ca-certificates \ - && rm -rf /var/lib/apt/lists/* \ - && useradd --system --create-home --home-dir /home/naut --uid 1000 naut + gosu \ + && rm -rf /var/lib/apt/lists/* WORKDIR /app @@ -93,31 +93,37 @@ ENV NAUT_WEBUI_HOST=0.0.0.0 \ NAUT_WEBUI_DB=/data/webui.db \ NAUT_WEBUI_SAVE_PATH=/downloads \ NAUT_STATE_DIR=/data/state \ - NAUT_SOCKET=/run/naut/nautd.sock + NAUT_SOCKET=/run/naut/nautd.sock \ + PUID=99 \ + PGID=100 +# PUID / PGID # uid:gid the daemon runs as. Default 99:100 +# # = unraid's nobody:users, so it can write to +# # /mnt/user shares. Match your storage owner. # NAUT_AUTH_USER=admin # default # NAUT_AUTH_PASSWORD=... # generated + printed to the log if unset # NAUT_SESSION_TTL=604800 # login lifetime in seconds (default 7d) # NAUT_SCRIPT=/app/scripts/anime_sort.lua # set to load a script at startup -# Create the data/download/socket dirs (if the volume is fresh) then exec the -# daemon with the webui plugin and the configured script. Built with printf -# (single-quoted lines keep the $VARs literal) so the image stays a single -# Dockerfile on any builder. --script is only added when NAUT_SCRIPT is set. +# Entrypoint: start as root, create the data/socket dirs and hand the daemon's +# own state (not the downloads share) to PUID:PGID, then drop privileges with +# gosu and exec nautd. Built with printf (single-quoted lines keep the $VARs +# literal) so the image stays a single Dockerfile on any builder. RUN printf '%s\n' \ '#!/bin/sh' \ 'set -e' \ - 'mkdir -p "$NAUT_STATE_DIR" "$NAUT_WEBUI_SAVE_PATH" "$(dirname "$NAUT_WEBUI_DB")" "$(dirname "$NAUT_SOCKET")"' \ + ': "${PUID:=99}" "${PGID:=100}"' \ + 'mkdir -p "$NAUT_STATE_DIR" "$(dirname "$NAUT_WEBUI_DB")" "$(dirname "$NAUT_SOCKET")"' \ + 'mkdir -p "$NAUT_WEBUI_SAVE_PATH" 2>/dev/null || true' \ + '# Own the daemon state so it is writable as PUID:PGID. The downloads share' \ + '# is left alone — its permissions come from the host / NFS export.' \ + 'chown -R "$PUID:$PGID" "$NAUT_STATE_DIR" "$(dirname "$NAUT_WEBUI_DB")" "$(dirname "$NAUT_SOCKET")" 2>/dev/null || true' \ '[ -n "$NAUT_SCRIPT" ] && set -- --script "$NAUT_SCRIPT" "$@"' \ - 'exec /app/nautd --socket "$NAUT_SOCKET" --plugin /app/naut_webui.so --state-dir "$NAUT_STATE_DIR" "$@"' \ + 'exec gosu "$PUID:$PGID" /app/nautd --socket "$NAUT_SOCKET" --plugin /app/naut_webui.so --state-dir "$NAUT_STATE_DIR" "$@"' \ > /usr/local/bin/entrypoint.sh \ && chmod +x /usr/local/bin/entrypoint.sh -# Owned by the unprivileged runtime user; bind-mounted volumes must be writable -# by uid 1000. -RUN mkdir -p /data /downloads /run/naut \ - && chown -R naut:naut /app /data /downloads /run/naut - -USER naut +# Mountpoints (ownership is fixed at runtime by the entrypoint per PUID/PGID). +RUN mkdir -p /data /downloads /run/naut VOLUME ["/data", "/downloads"] EXPOSE 8080 6881 6881/udp