fix(docker): run container as non-root (gosu) and drop build toolchain from runtime

This commit is contained in:
Jannis Braun
2026-07-13 00:58:07 +02:00
parent 9d2eeb0963
commit 3100965c30
2 changed files with 25 additions and 1 deletions
+7 -1
View File
@@ -40,7 +40,7 @@ RUN corepack enable && corepack prepare pnpm@10.34.3 --activate
# Install build dependencies for better-sqlite3 native module
RUN apt-get update && \
apt-get install -y --no-install-recommends python3 make g++ ffmpeg && \
apt-get install -y --no-install-recommends ffmpeg gosu && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
@@ -72,6 +72,11 @@ COPY --from=builder /app/packages/web/dist packages/web/dist
# Create data directories
RUN mkdir -p /app/data/uploads
# Non-root hardening: copy the privilege-dropping entrypoint. It chowns the
# data volume as root, then execs the CMD as the unprivileged `node` user.
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Set environment defaults
ENV NODE_ENV=production
ENV PORT=3000
@@ -94,4 +99,5 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=5 \
# Run the server using tsx from the server package directory
WORKDIR /app/packages/server
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node", "--import", "tsx/esm", "src/index.ts"]
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
# Runs as root: make the (bind-mounted, host-owned) data dir writable by the
# non-root `node` user, then drop privileges via gosu and exec the CMD. This
# lets the container run as uid 1000 while still owning ./data on hosts where
# the bind mount was created by a different uid.
#
# - Idempotent AND cheap: only chown entries not already node-owned, so after
# the first boot this is near-instant. A plain `chown -R` over a large
# uploads/ tree on slow Pi/SD storage would delay startup on EVERY restart.
# - Non-fatal: on a bind mount that rejects chown (some CIFS/NFS backings),
# warn and continue rather than crash-looping under `restart: unless-stopped`
# (the old root container booted fine on such mounts).
set -e
mkdir -p /app/data/uploads
chown node:node /app/data /app/data/uploads 2>/dev/null || true
find /app/data ! -user node -exec chown node:node {} + 2>/dev/null || \
echo "docker-entrypoint: warning: could not chown /app/data; continuing (ensure it is writable by uid 1000)"
exec gosu node "$@"