From e19efd9c4d106089ad047fd822b66ec7dce46300 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 21 May 2025 09:24:11 -0700 Subject: [PATCH] Chore: improve PUID/PGID support --- Dockerfile | 2 +- docker-entrypoint.sh | 41 ++++++++++++++++++++++++++++++++++---- src/utils/config/config.js | 16 ++++++++++++--- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index cac7623ea..d58737923 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ COPY --link --chmod=755 docker-entrypoint.sh /usr/local/bin/ COPY --link --from=builder --chown=1000:1000 /app/.next/standalone/ ./ COPY --link --from=builder --chown=1000:1000 /app/.next/static/ ./.next/static -RUN apk add --no-cache su-exec iputils-ping +RUN apk add --no-cache su-exec iputils-ping shadow ENV NODE_ENV=production ENV HOSTNAME=0.0.0.0 diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 9890fbee8..99379de1e 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -12,10 +12,43 @@ export PGID=${PGID:-0} export HOMEPAGE_BUILDTIME=$(date +%s) -# Set privileges for /app but only if pid 1 user is root and we are dropping privileges. -# If container is run as an unprivileged user, it means owner already handled ownership setup on their own. -# Running chown in that case (as non-root) will cause error -[ "$(id -u)" == "0" ] && [ "${PUID}" != "0" ] && chown -R ${PUID}:${PGID} /app/config /app/public +# Check ownership before chown +if [ -e /app/config ]; then + CURRENT_UID=$(stat -c %u /app/config) + CURRENT_GID=$(stat -c %g /app/config) + + if [ "$CURRENT_UID" -ne "$PUID" ] || [ "$CURRENT_GID" -ne "$PGID" ]; then + echo "Fixing ownership of /app/config" + if ! chown -R "$PUID:$PGID" /app/config 2>/dev/null; then + echo "Warning: Could not chown /app/config; continuing anyway" + fi + else + echo "/app/config already owned by correct UID/GID, skipping chown" + fi +else + echo "/app/config does not exist; skipping ownership check" +fi + +# Ensure /app/config/logs exists and is owned +if [ -n "$PUID" ] && [ -n "$PGID" ]; then + mkdir -p /app/config/logs 2>/dev/null || true + if [ -d /app/config/logs ]; then + LOG_UID=$(stat -c %u /app/config/logs) + LOG_GID=$(stat -c %g /app/config/logs) + if [ "$LOG_UID" -ne "$PUID" ] || [ "$LOG_GID" -ne "$PGID" ]; then + echo "Fixing ownership of /app/config/logs" + chown -R "$PUID:$PGID" /app/config/logs 2>/dev/null || echo "Warning: Could not chown /app/config/logs" + fi + fi +fi + +if [ -d /app/.next ]; then + CURRENT_UID=$(stat -c %u /app/.next) + if [ "$CURRENT_UID" -ne "$PUID" ]; then + echo "Fixing ownership of /app/.next" + chown -R "$PUID:$PGID" /app/.next || echo "Warning: Could not chown /app/.next" + fi +fi # Drop privileges (when asked to) if root, otherwise run as current user if [ "$(id -u)" == "0" ] && [ "${PUID}" != "0" ]; then diff --git a/src/utils/config/config.js b/src/utils/config/config.js index 3f6888420..60ac087aa 100644 --- a/src/utils/config/config.js +++ b/src/utils/config/config.js @@ -14,19 +14,29 @@ export const CONF_DIR = process.env.HOMEPAGE_CONFIG_DIR : join(process.cwd(), "config"); export default function checkAndCopyConfig(config) { + // Ensure config directory exists if (!existsSync(CONF_DIR)) { - mkdirSync(CONF_DIR, { recursive: true }); + try { + mkdirSync(CONF_DIR, { recursive: true }); + } catch (e) { + console.warn(`Could not create config directory ${CONF_DIR}: ${e.message}`); + return false; + } } const configYaml = join(CONF_DIR, config); + + // If the config file doesn't exist, try to copy the skeleton if (!existsSync(configYaml)) { const configSkeleton = join(process.cwd(), "src", "skeleton", config); try { copyFileSync(configSkeleton, configYaml); console.info("%s was copied to the config folder", config); } catch (err) { - console.error("error copying config", err); - throw err; + console.error("❌ Failed to initialize required config: %s", configYaml); + console.error("Reason: %s", err.message); + console.error("Hint: Make /app/config writable or manually place the config file."); + process.exit(1); } return true;