mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
Merge pull request #1923 from TriliumNext/feat/add-rootless-dockerfiles
feat(ci): add rootless dockerfiles
This commit is contained in:
commit
c82c01fb41
@ -8,6 +8,9 @@ indent_style = space
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
[{server,translation}.json]
|
[{server,translation}.json]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
|
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -14,4 +14,6 @@ demo/**/*.txt eol=lf
|
|||||||
demo/**/*.js eol=lf
|
demo/**/*.js eol=lf
|
||||||
demo/**/*.css eol=lf
|
demo/**/*.css eol=lf
|
||||||
|
|
||||||
|
*.sh eol=lf
|
||||||
|
|
||||||
apps/client/src/libraries/** linguist-vendored
|
apps/client/src/libraries/** linguist-vendored
|
@ -1,28 +1,28 @@
|
|||||||
FROM node:22.16.0-bullseye-slim AS builder
|
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.
|
# Install native dependencies since we might be building cross-platform.
|
||||||
WORKDIR /usr/src/app/build
|
WORKDIR /usr/src/app/build
|
||||||
COPY ./docker/package.json ./docker/pnpm-workspace.yaml /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
|
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||||
|
|
||||||
FROM node:22.16.0-bullseye-slim
|
FROM node:22.16.0-bullseye-slim
|
||||||
# Install only runtime dependencies
|
# Install only runtime dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
gosu && \
|
gosu && \
|
||||||
rm -rf \
|
rm -rf \
|
||||||
/var/lib/apt/lists/* \
|
/var/lib/apt/lists/* \
|
||||||
/var/cache/apt/*
|
/var/cache/apt/*
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
COPY ./dist /usr/src/app
|
COPY ./dist /usr/src/app
|
||||||
RUN rm -rf /usr/src/app/node_modules/better-sqlite3
|
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 --from=builder /usr/src/app/node_modules/better-sqlite3 /usr/src/app/node_modules/better-sqlite3
|
||||||
COPY ./start-docker.sh /usr/src/app
|
COPY ./start-docker.sh /usr/src/app
|
||||||
|
|
||||||
# Configure container
|
# Configure container
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
CMD [ "sh", "./start-docker.sh" ]
|
CMD [ "sh", "./start-docker.sh" ]
|
||||||
HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.cjs
|
HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.cjs
|
@ -1,26 +1,26 @@
|
|||||||
FROM node:22.16.0-alpine AS builder
|
FROM node:22.16.0-alpine AS builder
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
# Install native dependencies since we might be building cross-platform.
|
# Install native dependencies since we might be building cross-platform.
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
COPY ./docker/package.json ./docker/pnpm-workspace.yaml /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
|
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||||
|
|
||||||
FROM node:22.16.0-alpine
|
FROM node:22.16.0-alpine
|
||||||
# Install runtime dependencies
|
# Install runtime dependencies
|
||||||
RUN apk add --no-cache su-exec shadow
|
RUN apk add --no-cache su-exec shadow
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
COPY ./dist /usr/src/app
|
COPY ./dist /usr/src/app
|
||||||
RUN rm -rf /usr/src/app/node_modules/better-sqlite3
|
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 --from=builder /usr/src/app/node_modules/better-sqlite3 /usr/src/app/node_modules/better-sqlite3
|
||||||
COPY ./start-docker.sh /usr/src/app
|
COPY ./start-docker.sh /usr/src/app
|
||||||
|
|
||||||
# Add application user
|
# Add application user
|
||||||
RUN adduser -s /bin/false node; exit 0
|
RUN adduser -s /bin/false node; exit 0
|
||||||
|
|
||||||
# Configure container
|
# Configure container
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
CMD [ "sh", "./start-docker.sh" ]
|
CMD [ "sh", "./start-docker.sh" ]
|
||||||
HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.cjs
|
HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.cjs
|
50
apps/server/Dockerfile.alpine.rootless
Normal file
50
apps/server/Dockerfile.alpine.rootless
Normal file
@ -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
apps/server/Dockerfile.rootless
Normal file
48
apps/server/Dockerfile.rootless
Normal file
@ -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
|
@ -154,6 +154,12 @@
|
|||||||
},
|
},
|
||||||
"alpine": {
|
"alpine": {
|
||||||
"command": "docker build . -t triliumnext-alpine -f Dockerfile.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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -169,6 +175,12 @@
|
|||||||
},
|
},
|
||||||
"alpine": {
|
"alpine": {
|
||||||
"command": "docker run -p 8081:8080 triliumnext-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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
28
apps/server/rootless-entrypoint.sh
Executable file
28
apps/server/rootless-entrypoint.sh
Executable file
@ -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
|
@ -76,4 +76,115 @@ docker inspect [container_name]</code></pre>
|
|||||||
<h3>Note on timezones</h3>
|
<h3>Note on timezones</h3>
|
||||||
<p>If you are having timezone issues and you are not using docker-compose,
|
<p>If you are having timezone issues and you are not using docker-compose,
|
||||||
you may need to add a <code>TZ</code> environment variable with the <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">TZ identifier</a> of
|
you may need to add a <code>TZ</code> environment variable with the <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">TZ identifier</a> of
|
||||||
your local timezone.</p>
|
your local timezone.</p>
|
||||||
|
<h2>Rootless Docker Image</h2>
|
||||||
|
<aside class="admonition note">
|
||||||
|
<p>Please keep in mind that the data directory is at <code>/home/trilium/trilium-data</code> instead
|
||||||
|
of the typical <code>/home/node/trilium-data</code>. This is because a new
|
||||||
|
user is created and used to run Trilium within the rootless containers.</p>
|
||||||
|
</aside>
|
||||||
|
<p>If you would prefer to run Trilium without having to run the Docker container
|
||||||
|
as <code>root</code>, you can use either of the provided Debian (default)
|
||||||
|
and Alpine-based images with the <code>rootless</code> tag. </p>
|
||||||
|
<p><em><strong>If you're unsure, stick to the “rootful” Docker image referenced above.</strong></em>
|
||||||
|
</p>
|
||||||
|
<p>Below are some commands to pull the rootless images:</p><pre><code class="language-text-x-trilium-auto"># For Debian-based image
|
||||||
|
docker pull triliumnext/notes:rootless
|
||||||
|
|
||||||
|
# For Alpine-based image
|
||||||
|
docker pull triliumnext/notes:rootless-alpine</code></pre>
|
||||||
|
<h3>Why Rootless?</h3>
|
||||||
|
<p>Running containers as non-root is a security best practice that reduces
|
||||||
|
the potential impact of container breakouts. If an attacker manages to
|
||||||
|
escape the container, they'll only have the permissions of the non-root
|
||||||
|
user instead of full root access to the host.</p>
|
||||||
|
<h3>How It Works</h3>
|
||||||
|
<p>The rootless Trilium image:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Creates a non-root user (<code>trilium</code>) during build time</li>
|
||||||
|
<li>Configures the application to run as this non-root user</li>
|
||||||
|
<li>Allows runtime customization of the user's UID/GID via Docker's <code>--user</code> flag</li>
|
||||||
|
<li>Does not require a separate Docker <code>entrypoint</code> script</li>
|
||||||
|
</ol>
|
||||||
|
<h3>Usage</h3>
|
||||||
|
<h4><strong>Using docker-compose (Recommended)</strong></h4><pre><code class="language-text-x-trilium-auto"># Run with default UID/GID (1000:1000)
|
||||||
|
docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
|
||||||
|
# Run with custom UID/GID (e.g., match your host user)
|
||||||
|
TRILIUM_UID=$(id -u) TRILIUM_GID=$(id -g) docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
|
||||||
|
# Specify a custom data directory
|
||||||
|
TRILIUM_DATA_DIR=/path/to/your/data TRILIUM_UID=$(id -u) TRILIUM_GID=$(id -g) docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
</code></pre>
|
||||||
|
<h4><strong>Using Docker CLI</strong></h4><pre><code class="language-text-x-trilium-auto"># Build the image
|
||||||
|
docker build -t triliumnext/notes:rootless -f apps/server/Dockerfile.rootless .
|
||||||
|
|
||||||
|
# Run with default UID/GID (1000:1000)
|
||||||
|
docker run -d --name trilium -p 8080:8080 -v ~/trilium-data:/home/trilium/trilium-data triliumnext/notes:rootless
|
||||||
|
|
||||||
|
# Run with custom UID/GID
|
||||||
|
docker run -d --name trilium -p 8080:8080 --user $(id -u):$(id -g) -v ~/trilium-data:/home/trilium/trilium-data triliumnext/notes:rootless
|
||||||
|
</code></pre>
|
||||||
|
<h3>Environment Variables</h3>
|
||||||
|
<ul>
|
||||||
|
<li><code>TRILIUM_UID</code>: UID to use for the container process (passed
|
||||||
|
to Docker's <code>--user</code> flag)</li>
|
||||||
|
<li><code>TRILIUM_GID</code>: GID to use for the container process (passed
|
||||||
|
to Docker's <code>--user</code> flag)</li>
|
||||||
|
<li><code>TRILIUM_DATA_DIR</code>: Path to the data directory inside the container
|
||||||
|
(default: <code>/home/node/trilium-data</code>)</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Volume Permissions</h3>
|
||||||
|
<p>If you encounter permission issues with the data volume, ensure that:</p>
|
||||||
|
<ol>
|
||||||
|
<li>The host directory has appropriate permissions for the UID/GID you're
|
||||||
|
using</li>
|
||||||
|
<li>You're setting both <code>TRILIUM_UID</code> and <code>TRILIUM_GID</code> to
|
||||||
|
match the owner of the host directory</li>
|
||||||
|
</ol><pre><code class="language-text-x-trilium-auto"># For example, if your data directory is owned by UID 1001 and GID 1001:
|
||||||
|
TRILIUM_UID=1001 TRILIUM_GID=1001 docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
</code></pre>
|
||||||
|
<h3>Considerations</h3>
|
||||||
|
<ul>
|
||||||
|
<li>The container starts with a specific UID/GID which can be customized at
|
||||||
|
runtime</li>
|
||||||
|
<li>Unlike the traditional setup, this approach does not use a separate entrypoint
|
||||||
|
script with <code>usermod</code>/<code>groupmod</code> commands</li>
|
||||||
|
<li>The container cannot modify its own UID/GID at runtime, which is a security
|
||||||
|
feature of rootless containers</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Available Rootless Images</h3>
|
||||||
|
<p>Two rootless variants are provided:</p>
|
||||||
|
<ol>
|
||||||
|
<li><strong>Debian-based</strong> (default): Uses the Debian Bullseye Slim
|
||||||
|
base image
|
||||||
|
<ul>
|
||||||
|
<li>Dockerfile: <code>apps/server/Dockerfile.rootless</code>
|
||||||
|
</li>
|
||||||
|
<li>Recommended for most users</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><strong>Alpine-based</strong>: Uses the Alpine base image for smaller
|
||||||
|
size
|
||||||
|
<ul>
|
||||||
|
<li>Dockerfile: <code>apps/server/Dockerfile.alpine.rootless</code>
|
||||||
|
</li>
|
||||||
|
<li>Smaller image size, but may have compatibility issues with some systems</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<h3>Building Custom Rootless Images</h3>
|
||||||
|
<p>If you would prefer, you can also customize the UID/GID at build time:</p><pre><code class="language-text-x-trilium-auto"># For Debian-based image with custom UID/GID
|
||||||
|
docker build --build-arg USER=myuser --build-arg UID=1001 --build-arg GID=1001 \
|
||||||
|
-t triliumnext/notes:rootless-custom -f apps/server/Dockerfile.rootless .
|
||||||
|
|
||||||
|
# For Alpine-based image with custom UID/GID
|
||||||
|
docker build --build-arg USER=myuser --build-arg UID=1001 --build-arg GID=1001 \
|
||||||
|
-t triliumnext/notes:alpine-rootless-custom -f apps/server/Dockerfile.alpine.rootless .
|
||||||
|
</code></pre>
|
||||||
|
<p>Available build arguments:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>USER</code>: Username for the non-root user (default: trilium)</li>
|
||||||
|
<li><code>UID</code>: User ID for the non-root user (default: 1000)</li>
|
||||||
|
<li><code>GID</code>: Group ID for the non-root user (default: 1000)</li>
|
||||||
|
</ul>
|
31
docker-compose.rootless.yml
Normal file
31
docker-compose.rootless.yml
Normal file
@ -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
|
@ -54,6 +54,7 @@
|
|||||||
* For read-only notes, a floating button allows copying the code snippet to clipboard.
|
* For read-only notes, a floating button allows copying the code snippet to clipboard.
|
||||||
* [Math in text notes: equations can now be displayed on multiple lines](https://github.com/TriliumNext/Notes/pull/2003) by @SiriusXT
|
* [Math in text notes: equations can now be displayed on multiple lines](https://github.com/TriliumNext/Notes/pull/2003) by @SiriusXT
|
||||||
* [Metrics endpoint](https://github.com/TriliumNext/Notes/pull/2024) by @perfectra1n
|
* [Metrics endpoint](https://github.com/TriliumNext/Notes/pull/2024) by @perfectra1n
|
||||||
|
* Docker: Rootless [Dockerfiles are now available](https://github.com/TriliumNext/Notes/pull/1923/files) by @perfectra1n
|
||||||
|
|
||||||
## 📖 Documentation
|
## 📖 Documentation
|
||||||
|
|
||||||
|
@ -117,4 +117,123 @@ The `--user` directive is unsupported. Instead, use the `USER_UID` and `USER_GID
|
|||||||
|
|
||||||
### Note on timezones
|
### Note on timezones
|
||||||
|
|
||||||
If you are having timezone issues and you are not using docker-compose, you may need to add a `TZ` environment variable with the [TZ identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) of your local timezone.
|
If you are having timezone issues and you are not using docker-compose, you may need to add a `TZ` environment variable with the [TZ identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) of your local timezone.
|
||||||
|
|
||||||
|
## Rootless Docker Image
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Please keep in mind that the data directory is at `/home/trilium/trilium-data` instead of the typical `/home/node/trilium-data`. This is because a new user is created and used to run Trilium within the rootless containers.
|
||||||
|
|
||||||
|
If you would prefer to run Trilium without having to run the Docker container as `root`, you can use either of the provided Debian (default) and Alpine-based images with the `rootless` tag.
|
||||||
|
|
||||||
|
_**If you're unsure, stick to the “rootful” Docker image referenced above.**_
|
||||||
|
|
||||||
|
Below are some commands to pull the rootless images:
|
||||||
|
|
||||||
|
```
|
||||||
|
# For Debian-based image
|
||||||
|
docker pull triliumnext/notes:rootless
|
||||||
|
|
||||||
|
# For Alpine-based image
|
||||||
|
docker pull triliumnext/notes:rootless-alpine
|
||||||
|
```
|
||||||
|
|
||||||
|
### Why Rootless?
|
||||||
|
|
||||||
|
Running containers as non-root is a security best practice that reduces the potential impact of container breakouts. If an attacker manages to escape the container, they'll only have the permissions of the non-root user instead of full root access to the host.
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
The rootless Trilium image:
|
||||||
|
|
||||||
|
1. Creates a non-root user (`trilium`) during build time
|
||||||
|
2. Configures the application to run as this non-root user
|
||||||
|
3. Allows runtime customization of the user's UID/GID via Docker's `--user` flag
|
||||||
|
4. Does not require a separate Docker `entrypoint` script
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
#### **Using docker-compose (Recommended)**
|
||||||
|
|
||||||
|
```
|
||||||
|
# Run with default UID/GID (1000:1000)
|
||||||
|
docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
|
||||||
|
# Run with custom UID/GID (e.g., match your host user)
|
||||||
|
TRILIUM_UID=$(id -u) TRILIUM_GID=$(id -g) docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
|
||||||
|
# Specify a custom data directory
|
||||||
|
TRILIUM_DATA_DIR=/path/to/your/data TRILIUM_UID=$(id -u) TRILIUM_GID=$(id -g) docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **Using Docker CLI**
|
||||||
|
|
||||||
|
```
|
||||||
|
# Build the image
|
||||||
|
docker build -t triliumnext/notes:rootless -f apps/server/Dockerfile.rootless .
|
||||||
|
|
||||||
|
# Run with default UID/GID (1000:1000)
|
||||||
|
docker run -d --name trilium -p 8080:8080 -v ~/trilium-data:/home/trilium/trilium-data triliumnext/notes:rootless
|
||||||
|
|
||||||
|
# Run with custom UID/GID
|
||||||
|
docker run -d --name trilium -p 8080:8080 --user $(id -u):$(id -g) -v ~/trilium-data:/home/trilium/trilium-data triliumnext/notes:rootless
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
* `TRILIUM_UID`: UID to use for the container process (passed to Docker's `--user` flag)
|
||||||
|
* `TRILIUM_GID`: GID to use for the container process (passed to Docker's `--user` flag)
|
||||||
|
* `TRILIUM_DATA_DIR`: Path to the data directory inside the container (default: `/home/node/trilium-data`)
|
||||||
|
|
||||||
|
### Volume Permissions
|
||||||
|
|
||||||
|
If you encounter permission issues with the data volume, ensure that:
|
||||||
|
|
||||||
|
1. The host directory has appropriate permissions for the UID/GID you're using
|
||||||
|
2. You're setting both `TRILIUM_UID` and `TRILIUM_GID` to match the owner of the host directory
|
||||||
|
|
||||||
|
```
|
||||||
|
# For example, if your data directory is owned by UID 1001 and GID 1001:
|
||||||
|
TRILIUM_UID=1001 TRILIUM_GID=1001 docker-compose -f docker-compose.rootless.yml up -d
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Considerations
|
||||||
|
|
||||||
|
* The container starts with a specific UID/GID which can be customized at runtime
|
||||||
|
* Unlike the traditional setup, this approach does not use a separate entrypoint script with `usermod`/`groupmod` commands
|
||||||
|
* The container cannot modify its own UID/GID at runtime, which is a security feature of rootless containers
|
||||||
|
|
||||||
|
### Available Rootless Images
|
||||||
|
|
||||||
|
Two rootless variants are provided:
|
||||||
|
|
||||||
|
1. **Debian-based** (default): Uses the Debian Bullseye Slim base image
|
||||||
|
* Dockerfile: `apps/server/Dockerfile.rootless`
|
||||||
|
* Recommended for most users
|
||||||
|
2. **Alpine-based**: Uses the Alpine base image for smaller size
|
||||||
|
* Dockerfile: `apps/server/Dockerfile.alpine.rootless`
|
||||||
|
* Smaller image size, but may have compatibility issues with some systems
|
||||||
|
|
||||||
|
### Building Custom Rootless Images
|
||||||
|
|
||||||
|
If you would prefer, you can also customize the UID/GID at build time:
|
||||||
|
|
||||||
|
```
|
||||||
|
# For Debian-based image with custom UID/GID
|
||||||
|
docker build --build-arg USER=myuser --build-arg UID=1001 --build-arg GID=1001 \
|
||||||
|
-t triliumnext/notes:rootless-custom -f apps/server/Dockerfile.rootless .
|
||||||
|
|
||||||
|
# For Alpine-based image with custom UID/GID
|
||||||
|
docker build --build-arg USER=myuser --build-arg UID=1001 --build-arg GID=1001 \
|
||||||
|
-t triliumnext/notes:alpine-rootless-custom -f apps/server/Dockerfile.alpine.rootless .
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Available build arguments:
|
||||||
|
|
||||||
|
* `USER`: Username for the non-root user (default: trilium)
|
||||||
|
* `UID`: User ID for the non-root user (default: 1000)
|
||||||
|
* `GID`: Group ID for the non-root user (default: 1000)
|
Loading…
x
Reference in New Issue
Block a user