diff --git a/Dockerfile b/Dockerfile index 8b65b0e210..bf1501aad8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,17 @@ FROM node:lts-trixie-slim AS base +ARG USER_UID=1000 +ARG USER_GID=1000 RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates curl git \ + && apt-get install -y --no-install-recommends ca-certificates curl git gosu \ && rm -rf /var/lib/apt/lists/* + RUN corepack enable +# Modify the existing node user/group to have the specified UID/GID to match host user +RUN usermod -u $USER_UID --non-unique node \ + && groupmod -g $USER_GID --non-unique node \ + && usermod -g $USER_GID -d /paperclip node + FROM base AS deps WORKDIR /app COPY package.json pnpm-workspace.yaml pnpm-lock.yaml .npmrc ./ @@ -35,12 +43,17 @@ RUN pnpm --filter @paperclipai/server build RUN test -f server/dist/index.js || (echo "ERROR: server build output missing" && exit 1) FROM base AS production +ARG USER_UID=1000 +ARG USER_GID=1000 WORKDIR /app COPY --chown=node:node --from=build /app /app RUN npm install --global --omit=dev @anthropic-ai/claude-code@latest @openai/codex@latest opencode-ai \ && mkdir -p /paperclip \ && chown node:node /paperclip +COPY docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + ENV NODE_ENV=production \ HOME=/paperclip \ HOST=0.0.0.0 \ @@ -48,6 +61,8 @@ ENV NODE_ENV=production \ SERVE_UI=true \ PAPERCLIP_HOME=/paperclip \ PAPERCLIP_INSTANCE_ID=default \ + USER_UID=${USER_UID} \ + USER_GID=${USER_GID} \ PAPERCLIP_CONFIG=/paperclip/instances/default/config.json \ PAPERCLIP_DEPLOYMENT_MODE=authenticated \ PAPERCLIP_DEPLOYMENT_EXPOSURE=private @@ -55,5 +70,5 @@ ENV NODE_ENV=production \ VOLUME ["/paperclip"] EXPOSE 3100 -USER node +ENTRYPOINT ["docker-entrypoint.sh"] CMD ["node", "--import", "./server/node_modules/tsx/dist/loader.mjs", "server/dist/index.js"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000000..eb9078d4fd --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,29 @@ +#!/bin/sh +set -e + +# Capture runtime UID/GID from environment variables, defaulting to 1000 +PUID=${USER_UID:-1000} +PGID=${USER_GID:-1000} + +# Adjust the node user's UID/GID if they differ from the runtime request +# and fix volume ownership only when a remap is needed +changed=0 + +if [ "$(id -u node)" -ne "$PUID" ]; then + echo "Updating node UID to $PUID" + usermod -o -u "$PUID" node + changed=1 +fi + +if [ "$(id -g node)" -ne "$PGID" ]; then + echo "Updating node GID to $PGID" + groupmod -o -g "$PGID" node + usermod -g "$PGID" node + changed=1 +fi + +if [ "$changed" = "1" ]; then + chown -R node:node /paperclip +fi + +exec gosu node "$@"