Skip to content

feat(ci): add rootless dockerfiles #1923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions apps/server/Dockerfile.alpine.rootless
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
FROM node:22.15.0-alpine AS builder
RUN corepack enable

# Install native dependencies since we might be building cross-platform.
WORKDIR /usr/src/app
COPY ./dist/package.json ./dist/pnpm-lock.yaml ./docker/pnpm-workspace.yaml /usr/src/app/
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild

FROM node:22.15.0-alpine
# Create a non-root user with configurable UID/GID
ARG USER=trilium
ARG UID=1001
ARG GID=1001
ENV USER=${USER}
ENV UID=${UID}
ENV GID=${GID}

# Install runtime dependencies and create user with specific UID/GID
RUN apk add --no-cache dumb-init && \
# Alpine uses addgroup/adduser (from busybox) instead of groupadd/useradd
addgroup -g ${GID} ${USER} && \
adduser -u ${UID} -G ${USER} -s /bin/sh -D -h /home/${USER} ${USER}

WORKDIR /home/${USER}/app
COPY ./dist /home/${USER}/app
RUN rm -rf /home/${USER}/app/node_modules/better-sqlite3
COPY --from=builder /usr/src/app/node_modules/better-sqlite3 /home/${USER}/app/node_modules/better-sqlite3
RUN chown -R ${USER}:${USER} /home/${USER}

# Configure container
USER ${USER}
EXPOSE 8080

# By default, use UID/GID that was set during build
# These can be overridden at runtime
ENV TRILIUM_UID=${UID}
ENV TRILIUM_GID=${GID}
ENV TRILIUM_DATA_DIR=/home/${USER}/trilium-data

# Use dumb-init as entrypoint to handle signals properly
ENTRYPOINT ["/usr/bin/dumb-init", "--"]

# This script will handle UID/GID checks and start the app
CMD [ "sh", "-c", "\
if [ \"${TRILIUM_UID}\" != \"$(id -u)\" ] || [ \"${TRILIUM_GID}\" != \"$(id -g)\" ]; then \
echo \"Detected UID:GID mismatch\"; \
if [ \"${TRILIUM_GID}\" != \"$(id -g)\" ]; then \
echo \"ERROR: Cannot change GID at runtime in rootless mode.\"; \
echo \" Please use docker run with --user ${TRILIUM_UID}:${TRILIUM_GID} instead.\"; \
exit 1; \
fi; \
if [ \"${TRILIUM_UID}\" != \"$(id -u)\" ]; then \
echo \"ERROR: Cannot change UID at runtime in rootless mode.\"; \
echo \" Please use docker run with --user ${TRILIUM_UID}:${TRILIUM_GID} instead.\"; \
exit 1; \
fi; \
fi; \
# Make sure data directory has correct permissions \
mkdir -p \"${TRILIUM_DATA_DIR}\"; \
# Start the app \
exec node ./main \
" ]

HEALTHCHECK --start-period=10s CMD node /home/${USER}/app/docker_healthcheck.js
66 changes: 66 additions & 0 deletions apps/server/Dockerfile.rootless
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
FROM node:22.15.0-bullseye-slim AS builder
RUN corepack enable

# Install native dependencies since we might be building cross-platform.
WORKDIR /usr/src/app/build
COPY ./dist/package.json ./dist/pnpm-lock.yaml ./docker/pnpm-workspace.yaml /usr/src/app/
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild

FROM node:22.15.0-bullseye-slim
# Create a non-root user with configurable UID/GID
ARG USER=trilium
ARG UID=1001
ARG GID=1001
ENV USER=${USER}
ENV UID=${UID}
ENV GID=${GID}

# Install only runtime dependencies
RUN rm -rf \
/var/lib/apt/lists/* \
/var/cache/apt/* && \
# Create the user/group with the default UID/GID
groupadd -g ${GID} ${USER} && \
useradd -u ${UID} -g ${USER} -s /bin/sh -m ${USER}

WORKDIR /home/${USER}/app
COPY ./dist /home/${USER}/app
RUN rm -rf /home/${USER}/app/node_modules/better-sqlite3
COPY --from=builder /usr/src/app/node_modules/better-sqlite3 /home/${USER}/app/node_modules/better-sqlite3
RUN chown -R ${USER}:${USER} /home/${USER}

# Configure container
USER ${USER}
EXPOSE 8080

# By default, use UID/GID that was set during build
# These can be overridden at runtime
ENV TRILIUM_UID=${UID}
ENV TRILIUM_GID=${GID}
ENV TRILIUM_DATA_DIR=/home/${USER}/trilium-data

# This script will handle UID/GID remapping if needed and then start the app
CMD [ "sh", "-c", "\
if [ \"${TRILIUM_UID}\" != \"$(id -u)\" ] || [ \"${TRILIUM_GID}\" != \"$(id -g)\" ]; then \
echo \"Remapping user ${USER} to UID:GID ${TRILIUM_UID}:${TRILIUM_GID}\"; \
# Use 'id -u' and 'id -g' to get current UID and GID \
if [ \"${TRILIUM_GID}\" != \"$(id -g)\" ]; then \
# Need root to modify user/group, but we can't use sudo, so we need to exit \
echo \"ERROR: Cannot change GID at runtime in rootless mode.\"; \
echo \" Please use docker run with --user ${TRILIUM_UID}:${TRILIUM_GID} instead.\"; \
exit 1; \
fi; \
if [ \"${TRILIUM_UID}\" != \"$(id -u)\" ]; then \
echo \"ERROR: Cannot change UID at runtime in rootless mode.\"; \
echo \" Please use docker run with --user ${TRILIUM_UID}:${TRILIUM_GID} instead.\"; \
exit 1; \
fi; \
fi; \
# Make sure data directory has correct permissions \
mkdir -p \"${TRILIUM_DATA_DIR}\"; \
# Start the app \
exec node ./main \
" ]

HEALTHCHECK --start-period=10s CMD node /home/${USER}/app/docker_healthcheck.js
31 changes: 31 additions & 0 deletions docker-compose.rootless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: '3.8'

# Running `docker-compose -f docker-compose.rootless.yml up` will create/use the "trilium-data" directory in the user home
# Run `TRILIUM_DATA_DIR=/path/of/your/choice docker-compose -f docker-compose.rootless.yml up` to set a different directory
# To run in the background, use `docker-compose -f docker-compose.rootless.yml up -d`
# To use the Alpine-based image, run with `TRILIUM_VARIANT=alpine docker-compose -f docker-compose.rootless.yml up`
services:
trilium:
# Optionally, replace `latest` with a version tag like `v0.90.3`
# Using `latest` may cause unintended updates to the container
image: triliumnext/notes:rootless
restart: unless-stopped
environment:
- TRILIUM_DATA_DIR=/home/trilium/trilium-data
# Set the desired UID/GID for the Trilium process. Will be used during docker run
# These should match the owner of your data directory on the host
- TRILIUM_UID=${TRILIUM_UID:-1001}
- TRILIUM_GID=${TRILIUM_GID:-1001}
# Use the specified UID/GID for the container process
user: ${TRILIUM_UID:-1001}:${TRILIUM_GID:-1001}
ports:
# By default, Trilium will be available at http://localhost:8080
# It will also be accessible at http://<host-ip>:8080
# You might want to limit this with something like Docker Networks, reverse proxies, or firewall rules
- '8080:8080'
volumes:
# Unless TRILIUM_DATA_DIR is set, the data will be stored in the "trilium-data" directory in the home directory.
# This can also be changed by replacing the line below with `- /path/of/your/choice:/home/trilium/trilium-data
- ${TRILIUM_DATA_DIR:-~/trilium-data}:/home/trilium/trilium-data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
Loading