Skip to content
This repository was archived by the owner on Jun 24, 2025. It is now read-only.

feat(ci): add rootless dockerfiles #1923

Merged
merged 19 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0298c62
feat(ci): add rootless dockerfiles
perfectra1n May 13, 2025
6430d70
Merge branch 'develop' into feat/add-rootless-dockerfiles
perfectra1n May 14, 2025
cbbbae7
Merge branch 'develop' into feat/add-rootless-dockerfiles
perfectra1n May 21, 2025
a05e126
feat(docs): add documentation around using the rootless Docker image
perfectra1n May 21, 2025
d73a289
feat(docker): move from inline script to entrypoint
perfectra1n May 21, 2025
436fc4c
fix(docker): make the rootless entrypoint print more useful informati…
perfectra1n May 21, 2025
093cd5c
fix(docker): fix when we copy and chmod the entrypoint for rootless i…
perfectra1n May 22, 2025
6de074a
fix(docker): have the container fill in the user variable
perfectra1n May 22, 2025
aa8fd6d
feat(docker): add to the rootless docker docs
perfectra1n May 22, 2025
a32f355
Merge remote-tracking branch 'origin/develop' into feat/add-rootless-…
eliandoran May 25, 2025
aa10638
feat(nx/server): add build/run scripts for docker rootless
eliandoran May 25, 2025
84ab4dc
chore(docker): format Dockerfiles
eliandoran May 25, 2025
b635c74
fix(docker/rootless): copy sequence after switch to esbuild
eliandoran May 25, 2025
93c939b
fix(docker/rootless): main entry point extension
eliandoran May 25, 2025
a1dda3c
Merge branch 'develop' into feat/add-rootless-dockerfiles
eliandoran May 27, 2025
02fc521
fix(docker/rootless): entrypoint if executable bit is not set
eliandoran May 27, 2025
c46d5cc
fix(docker/rootless): CRLF issues on Windows
eliandoran May 27, 2025
061e238
fix(docker/rootless): missing bash under alpine
eliandoran May 27, 2025
521f4c2
docs(release): mention rootless Docker mode
eliandoran May 27, 2025
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
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.sh]
end_of_line = lf

[{server,translation}.json]
charset = utf-8
end_of_line = lf
Expand Down
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ demo/**/*.txt eol=lf
demo/**/*.js eol=lf
demo/**/*.css eol=lf

*.sh eol=lf

apps/client/src/libraries/** linguist-vendored
44 changes: 22 additions & 22 deletions apps/server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
FROM node:22.16.0-bullseye-slim AS builder
RUN corepack enable
RUN corepack enable

# Install native dependencies since we might be building cross-platform.
WORKDIR /usr/src/app/build
COPY ./docker/package.json ./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
# Install native dependencies since we might be building cross-platform.
WORKDIR /usr/src/app/build
COPY ./docker/package.json ./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.16.0-bullseye-slim
# Install only runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gosu && \
rm -rf \
/var/lib/apt/lists/* \
/var/cache/apt/*
# Install only runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gosu && \
rm -rf \
/var/lib/apt/lists/* \
/var/cache/apt/*

WORKDIR /usr/src/app
COPY ./dist /usr/src/app
RUN rm -rf /usr/src/app/node_modules/better-sqlite3
COPY --from=builder /usr/src/app/node_modules/better-sqlite3 /usr/src/app/node_modules/better-sqlite3
COPY ./start-docker.sh /usr/src/app
WORKDIR /usr/src/app
COPY ./dist /usr/src/app
RUN rm -rf /usr/src/app/node_modules/better-sqlite3
COPY --from=builder /usr/src/app/node_modules/better-sqlite3 /usr/src/app/node_modules/better-sqlite3
COPY ./start-docker.sh /usr/src/app

# Configure container
EXPOSE 8080
CMD [ "sh", "./start-docker.sh" ]
HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.cjs
# Configure container
EXPOSE 8080
CMD [ "sh", "./start-docker.sh" ]
HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.cjs
38 changes: 19 additions & 19 deletions apps/server/Dockerfile.alpine
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
FROM node:22.16.0-alpine AS builder
RUN corepack enable
RUN corepack enable

# Install native dependencies since we might be building cross-platform.
WORKDIR /usr/src/app
COPY ./docker/package.json ./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
# Install native dependencies since we might be building cross-platform.
WORKDIR /usr/src/app
COPY ./docker/package.json ./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.16.0-alpine
# Install runtime dependencies
RUN apk add --no-cache su-exec shadow
# Install runtime dependencies
RUN apk add --no-cache su-exec shadow

WORKDIR /usr/src/app
COPY ./dist /usr/src/app
RUN rm -rf /usr/src/app/node_modules/better-sqlite3
COPY --from=builder /usr/src/app/node_modules/better-sqlite3 /usr/src/app/node_modules/better-sqlite3
COPY ./start-docker.sh /usr/src/app
WORKDIR /usr/src/app
COPY ./dist /usr/src/app
RUN rm -rf /usr/src/app/node_modules/better-sqlite3
COPY --from=builder /usr/src/app/node_modules/better-sqlite3 /usr/src/app/node_modules/better-sqlite3
COPY ./start-docker.sh /usr/src/app

# Add application user
RUN adduser -s /bin/false node; exit 0
# Add application user
RUN adduser -s /bin/false node; exit 0

# Configure container
EXPOSE 8080
CMD [ "sh", "./start-docker.sh" ]
HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.cjs
# Configure container
EXPOSE 8080
CMD [ "sh", "./start-docker.sh" ]
HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.cjs
50 changes: 50 additions & 0 deletions apps/server/Dockerfile.alpine.rootless
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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 ./docker/package.json ./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 && \
apk add --no-cache bash && \
# 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
# Also copy the rootless entrypoint script
COPY rootless-entrypoint.sh /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", "--"]

# Use the entrypoint script
CMD [ "bash", "./rootless-entrypoint.sh" ]

HEALTHCHECK --start-period=10s CMD node /home/${USER}/app/docker_healthcheck.js
48 changes: 48 additions & 0 deletions apps/server/Dockerfile.rootless
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
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 ./docker/package.json ./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
# Also copy the rootless entrypoint script
COPY rootless-entrypoint.sh /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 the entrypoint script
CMD [ "bash", "./rootless-entrypoint.sh" ]

HEALTHCHECK --start-period=10s CMD node /home/${USER}/app/docker_healthcheck.js
12 changes: 12 additions & 0 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@
},
"alpine": {
"command": "docker build . -t triliumnext-alpine -f Dockerfile.alpine"
},
"rootless-debian": {
"command": "docker build . -t triliumnext-rootless-debian -f Dockerfile.rootless"
},
"rootless-alpine": {
"command": "docker build . -t triliumnext-rootless-alpine -f Dockerfile.alpine.rootless"
}
}
},
Expand All @@ -169,6 +175,12 @@
},
"alpine": {
"command": "docker run -p 8081:8080 triliumnext-alpine"
},
"rootless-debian": {
"command": "docker run -p 8081:8080 triliumnext-rootless-debian"
},
"rootless-alpine": {
"command": "docker run -p 8081:8080 triliumnext-rootless-alpine"
}
}
},
Expand Down
28 changes: 28 additions & 0 deletions apps/server/rootless-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash
# Rootless entrypoint script for Trilium Notes
# Works with both Debian and Alpine-based images

# Check if runtime UID/GID match the expected values
if [ "${TRILIUM_UID}" != "$(id -u)" ] || [ "${TRILIUM_GID}" != "$(id -g)" ]; then
echo "Detected UID:GID mismatch (current: $(id -u):$(id -g), expected: ${TRILIUM_UID}:${TRILIUM_GID})"
# Check GID mismatch
if [ "${TRILIUM_GID}" != "$(id -g)" ]; then
echo "ERROR: Cannot change GID at runtime in rootless mode."
echo " Current GID: $(id -g), Expected GID: ${TRILIUM_GID}"
echo " Please use docker run with --user $(id -u):$(id -g) instead."
exit 1
fi
# Check UID mismatch
if [ "${TRILIUM_UID}" != "$(id -u)" ]; then
echo "ERROR: Cannot change UID at runtime in rootless mode."
echo " Current UID: $(id -u), Expected UID: ${TRILIUM_UID}"
echo " Please use docker run with --user $(id -u):$(id -g) instead."
exit 1
fi
fi

# Make sure data directory has correct permissions
mkdir -p "${TRILIUM_DATA_DIR}"

# Start the app
exec node ./main.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading