Trilium v0.106.0 Docker Compose 部署指南

Trilium v0.106.0 在 Ubuntu 22.04 上的 Docker Compose 从零部署实录:镜像选型、初始化(新建/同步服务器)、健康验证、数据持久化、环境变量与升级回滚演练,全部命令与回显实测。

TriliumTriliumDocker2026/10/22

Trilium v0.106.0 Docker Compose 部署指南

目标:在一台 Ubuntu 22.04 服务器上用 Docker Compose 从零部署 Trilium(TriliumNext/Trilium)v0.106.0 自托管笔记服务器,覆盖镜像选型、初始化(新建/同步服务器两种模式)、数据持久化验证、升级与回滚。已在 Ubuntu 22.04 + Docker 29.8.1 + Compose v5.5.1 环境实测通过:服务监听 8139 端口、数据目录 /opt/trilium/data,健康检查、重启重建与升级演练全部验证成功。组件背景与选型见 《Trilium 介绍与选型指南》。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)。
  • Docker:Docker version 29.8.1, build 4a63305;Docker Compose:Docker Compose version v5.5.1(docker --version、docker compose version 实测回显)。
  • Trilium 版本:v0.106.0(官方最新稳定版,2026-09-25 发布;镜像构建元数据 org.opencontainers.image.version=v0.106.0)。
  • 服务端口:宿主机 8139 → 服务 8080(本机实验环境统一规划 8128–8152 段,按需可改)。
  • 数据目录:/opt/trilium/data(bind mount 到服务内 /home/node/trilium-data)。
  • 部署形态:单服务编排,无外部数据库依赖(数据落 SQLite document.db)。

二、镜像选型说明

Trilium 官方在 Docker Hub 维护多套镜像,选型依据如下(来源:官方 Docker 安装文档与仓库 compose 文件,2026-10-22 查询):

镜像特点适用
triliumnext/trilium:<版本>官方主镜像,AMD64 / ARMv7 / ARM64-v8 三架构,容器内以 node 用户运行(entrypoint 用 su-exec 降权)常规自托管部署(本文采用)
triliumnext/notes:rootless官方 rootless 变体,通过 TRILIUM_UID/GID 以任意非特权用户运行禁止 root 运行的托管环境
triliumnext/trilium(Alpine 变体)rootless compose 中以 TRILIUM_VARIANT=alpine 启用的 Alpine 底座追求更小镜像体积

tag 策略:官方 compose 文件注释明确提醒 "Using latest may cause unintended updates to the container"(使用 latest 可能引发非预期升级)。生产部署必须锚定版本 tag(如 v0.106.0),升级时手动改 tag,避免自动跟随 latest 出现数据库 sync 版本跨代问题。

实测拉取(docker pull triliumnext/trilium:latest,镜像即 v0.106.0):

Digest: sha256:be93e82699b12950ac4e2e7b565ce092fe215b8dd6ddfc47921e37b49e6a0e8b
Status: Downloaded newer image for triliumnext/trilium:latest
docker.io/triliumnext/trilium:latest

镜像大小实测 513 MB,内置运行时 Node.js v24.21.0。关键元数据(docker inspect 实测):version=v0.106.0、build=2026-09-25T18:09:40.802Z、licenses=AGPL-3.0。

三、前置条件

  1. 已安装 Docker Engine 与 Compose v2 插件(验证命令与回显):
docker --version && docker compose version
Docker version 29.8.1, build 4a63305
Docker Compose version v5.5.1
  1. 确认目标端口未被占用(以 8139 为例,无输出即空闲):
ss -ltn | grep 8139

(实测部署后再次执行,出现监听行即服务已起:)

LISTEN 0      4096         0.0.0.0:8139       0.0.0.0:*
LISTEN 0      4096            [::]:8139          [::]:*
  1. 规划数据目录并确认磁盘余量(Trilium 单库 SQLite,10 万条笔记量级亦在 GB 以内):
mkdir -p /opt/trilium/data
df -h /opt/trilium | tail -1
786G total, 409G avail

四、部署步骤

4.1 编写 docker-compose.yml

在部署目录(本文取 /opt/trilium/compose/)创建 docker-compose.yml。骨架沿用官方 v0.106.0 仓库根 compose 文件,锚定版本 tag 并显式声明项目名:

name: trilium-0.106.0-stack

services:
  trilium:
    image: triliumnext/trilium:v0.106.0
    container_name: trilium-app
    restart: unless-stopped
    environment:
      - TRILIUM_DATA_DIR=/home/node/trilium-data
    ports:
      - '8139:8080'
    volumes:
      - /opt/trilium/data:/home/node/trilium-data
      - /etc/localtime:/etc/localtime:ro

networks:
  trilium-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.71.0/24

要点说明:

  • name: 显式指定 Compose 项目名,避免多套部署同名目录互相干扰;⚠️ 实测 Docker Compose 会把项目名中的点规范化:trilium-0.106.0-stack 实际生效为 trilium-01060-stack(见下文 docker compose down 回显),属正常现象。
  • image: 锚定 v0.106.0,升级流程见十、10.3 节。
  • TRILIUM_DATA_DIR 指向数据目录,与 volumes 的容器侧路径保持一致;宿主侧 /opt/trilium/data 需可写(容器内 entrypoint 会 chown 为 node 用户)。
  • /etc/localtime 只读挂载让笔记时间戳与宿主时区一致(官方 compose 同款做法)。
  • restart: unless-stopped 与官方 compose 一致:随服务自启,手动停止后不自动拉起。

4.2 启动服务

docker compose up -d
 Container trilium-0.106.0-app Created
 Container trilium-0.106.0-app Starting
 Container trilium-0.106.0-app Started

等待数十秒后查看状态(镜像自带健康检查:每 60 秒执行一次,启动宽限期 30 秒):

docker compose ps
NAME                  IMAGE                          COMMAND                   SERVICE   CREATED          STATUS                   PORTS
trilium-0.106.0-app   triliumnext/trilium:v0.106.0   "docker-entrypoint.s…"   trilium   20 seconds ago   Up 8 seconds (healthy)   0.0.0.0:8139->8080/tcp, [::]:8139->8080/tcp

STATUS 出现 (healthy) 即部署成功。启动日志横幅(docker compose logs trilium | head -12 实测节选):

No USER_UID specified, leaving 1000
No USER_GID specified, leaving 1000
Becca (note cache) load took 17ms

 _____     _ _ _
|_   _| __(_) (_)_   _ _ __ ___   | \ | | ___ | |_ ___  ___
  | || '__| | | | | | | '_ ` _ \  |  \| |/ _ \| __/ _ \/ __|
  | || |  | | | | |_| | | | | | | |\  | (_) | ||  __/\__ \
  |_||_|  |_|_|_|\__,_|_| |_| |_| |_| \_|\___/ \__\___||___/ 0.106.0

📦 Versions:    app=0.106.0 db=240 sync=39 clipper=1.0
🔧 Build:       2026-09-25 18:09:29 (c0fdceba3b)
📂 Data dir:    /home/node/trilium-data
💻 CPU:         Intel(R) Core(TM) i7-14700KF (12-core @ 0 Mhz)
💾 DB size:     3.2 MiB
Listening on port 8080

app=0.106.0 db=240 sync=39 三个版本号是排查客户端/服务器同步兼容性的关键依据。

4.3 服务健康验证

curl -s http://localhost:8139/api/health-check
{"status":"ok"}

返回 {"status":"ok"}(HTTP 200)即服务健康。镜像内置健康检查使用的正是该端点(数据目录 healthcheck-url 文件内容实测为 http://127.0.0.1:8080/api/health-check)。

4.4 初始化:新建文档 / 同步服务器 二选一

浏览器访问 http://<服务器IP>:8139,首次进入会出现官方初始化选择页(来源:官方服务器安装文档,2026-10-22 查询):

  • New document(新建文档):本机作为全新知识库或独立同步服务器。个人新装选这个。
  • Sync from server(从服务器同步):本机作为已有 Trilium 服务器的从属副本,需填入主服务器地址与同步密码,首次同步会拉取种子数据。

两种模式的判定可通过状态接口实时确认(部署后、初始化前实测):

curl -s http://localhost:8139/api/setup/status
{"isInitialized":false,"schemaExists":false,"authRequired":false,"secondFactorRequired":false,"hasExistingData":false,"syncVersion":39,"setupOperation":null}

isInitialized:false 表示尚未初始化。选择 New document 后界面会要求设置登录密码;设置完成即进入主界面(内置 577 条演示/帮助笔记,初始化日志实测 Table counts: notes: 577, revisions: 0, attachments: 19, branches: 592, attributes: 1411)。

⚠️ 初始化操作也可全部走接口完成,适合无人值守部署(以下命令均为实测):

# 1. 新建文档(首次调用返回 204,应用日志可见 "Setup operation 'new-document' finished")
curl -s -X POST http://localhost:8139/api/setup/new-document

# 2. 设置登录密码(表单字段 password1/password2,成功后 302 跳转)
curl -i -X POST http://localhost:8139/set-password -d "password1=<你的密码>&password2=<你的密码>"
# 实测回显:HTTP/1.1 302 Found … Location: login

# 3. 登录(成功后 302 跳转并下发会话 Cookie)
curl -i -c cookies.txt -X POST http://localhost:8139/login -d "password=<你的密码>"
# 实测回显:HTTP/1.1 302 Found … Location: .

⚠️ 已初始化后再次调用 POST /api/setup/new-document 会被拒绝,实测回显:{"message":"App already initialized."}(HTTP 401)——这是正常防护,不是故障。

4.5 登录验证

浏览器访问 http://<服务器IP>:8139 输入密码进入主界面;或用上述 Cookie 复验:

curl -s -b cookies.txt -o /dev/null -w "GET / -> %{http_code}\n" http://localhost:8139/
GET / -> 200

五、数据持久化说明

Trilium 全部状态都在数据目录 /opt/trilium/data(容器内 /home/node/trilium-data),不含任何外部数据库,备份该目录即备份全部数据。初始化完成后的目录结构(实测):

backup/           # 备份产出目录(backup-<名称>.db)
config.ini        # 服务配置(首次启动自动生成)
document.db       # SQLite 主库:全部笔记/属性/附件元数据
document.db-wal   # SQLite WAL 预写日志
document.db-shm   # SQLite 共享内存文件
healthcheck-url   # 健康检查端点说明文件
log/              # 运行日志
session_secret.txt
tmp/              # 临时文件

重建验证(真实实测):docker compose down 移除容器与网络但数据目录原样保留,docker compose up -d 重建后笔记原样可查:

docker compose down
 Network trilium-01060-stack_trilium-net Removing
 Network trilium-01060-stack_trilium-net Removed
docker compose up -d && sleep 8 && docker compose ps
 Container trilium-0.106.0-app Started
NAME                  IMAGE                          COMMAND                   SERVICE   CREATED          STATUS                   PORTS
trilium-0.106.0-app   triliumnext/trilium:v0.106.0   "docker-entrypoint.s…"   trilium   7 seconds ago   Up 7 seconds (healthy)   0.0.0.0:8139->8080/tcp, [::]:8139->8080/tcp

💡 技术拓展:数据目录挂载方式不止 bind mount 一种,常见选项对比——

方式特点适用
bind mount(本方案)路径直观、便于 rsync/快照备份物理机/常规服务器
named volumeDocker 统一管理,迁移需 docker volume 操作纯容器化运维体系
网络存储挂载可跨机漂移,但需注意文件锁SMB 需加 nobrl,noperm(官方文档明确要求)

本方案采用 bind mount:路径透明、备份直观,与官方 compose 默认行为一致。

六、环境变量表

实测验证过的环境变量(docker compose up -d 注入后实测确认):

环境变量默认值说明
TRILIUM_DATA_DIR/home/node/trilium-data数据目录;必须与 volumes 容器侧路径一致
TRILIUM_PORT8080服务监听端口;实测注入 TRILIUM_PORT=8090 后容器内改听 8090(/proc/net/tcp 出现 1F9A),原映射端口随即不通
USER_UID / USER_GID未设置时保持 1000启动脚本 start-docker.sh 读取,用于重设容器内 node 用户的 uid/gid(实测未设置时输出 No USER_UID specified, leaving 1000)

另有官方支持但本文未逐项实测的变量:TRILIUM_PROFILE(多 profile 数据目录)、TRILIUM_BACKUP_DIR、TRILIUM_LOG_DIR、TRILIUM_TMP_DIR、TRILIUM_CONFIG_INI_PATH(配置文件自定义路径)、TRILIUM_SAFE_MODE(安全模式)、TRILIUM_ENV、TRILIUM_RESOURCE_DIR(来源:官方镜像内程序对 TRILIUM_ 前缀环境变量的枚举,2026-10-22 查询)。rootless 变体另有 TRILIUM_UID/TRILIUM_GID/TRILIUM_VARIANT(来源:官方 docker-compose.rootless.yml)。

七、配置参数说明

首次启动会在数据目录生成 config.ini,其内容与官方 config-sample.ini 完全一致(逐行比对实测),即官方样例就是默认值。常用项速览(完整逐项解析见 《Trilium v0.106.0 配置参数详解》):

  • [Network] port=8080:config.ini 中的监听端口,与环境变量 TRILIUM_PORT 均可控制,后者优先级更高(实测见六);
  • [General] noAuthentication=false:改为 true 可免密码访问,仅建议纯内网 + 防火墙封禁的场景;
  • [Security] backendScriptingEnabled=false:后端脚本执行开关。实测改为 true 重启后,启动日志出现 WARNING: Backend script execution is ENABLED. Backend scripts have full server access including filesystem, network, and OS commands. Only enable in trusted environments.;默认 false 时日志为 Backend script execution is DISABLED. Set [Security] backendScriptingEnabled=true in config.ini to enable.。

修改 config.ini 后需 docker compose restart 生效(实测生效流程:编辑 → restart → 日志变化)。

八、配置文件挂载

config.ini 位于数据目录内,随 /opt/trilium/data bind mount 天然持久化,无需额外挂载条目;直接在宿主机编辑即可:

vi /opt/trilium/data/config.ini
docker compose restart trilium

⚠️ 首次启动前也可以在宿主机预放一份 config.ini(内容可从官方仓库 assets/config-sample.ini 获取),服务启动时直接采用;首次启动后 config.ini 已存在,编辑即可。

⚠️ 不要把 config.ini 挂载成单独的只读文件:服务可能在运行期改写该文件(UI 设置项会落盘),单独挂载会引发写入失败。

九、等价 docker run

不使用 Compose 的等价命令(已在独立数据目录实测:容器 healthy、首启状态接口返回 isInitialized:false):

docker run -d \
  --name trilium-app \
  --restart unless-stopped \
  -p 8139:8080 \
  -v /opt/trilium/data:/home/node/trilium-data \
  -e TRILIUM_DATA_DIR=/home/node/trilium-data \
  triliumnext/trilium:v0.106.0
7a9567e66d46b2e23f08528aae2021b15ac1860f26174581a437163dbb3a4847
docker ps --filter name=trilium-app --format '{{.Names}} {{.Status}} {{.Ports}}'
trilium-0.106.0-runtest Up 8 seconds (healthy) 0.0.0.0:8136->8080/tcp, [::]:8136->8080/tcp

(该验证实例使用独立数据目录与 8136 端口,首启状态实测:)

curl -s http://localhost:8136/api/setup/status
{"isInitialized":false,"schemaExists":false,"authRequired":false,"secondFactorRequired":false,"hasExistingData":false,"syncVersion":39,"setupOperation":null}

生产环境仍建议用 Compose:配置即文件、升级回滚可追溯。

十、常用运维命令

以下命令均在部署目录 /opt/trilium/compose/ 下执行。

10.1 日常启停与状态

docker compose ps                 # 状态与健康(见 4.2 回显)
docker compose logs -f trilium    # 跟踪日志(Ctrl+C 退出)
docker compose stop               # 停止(保留容器)
docker compose start              # 启动
docker compose restart trilium    # 重启(改 config.ini 后使用)
docker compose down               # 停止并移除容器/网络,数据目录不受影响(见五回显)

10.2 数据库备份

用 ETAPI 触发在线备份(实测 HTTP 204,产物为数据目录下 backup/backup-now.db):

curl -s -X PUT http://localhost:8139/etapi/backup/now -H "Authorization: <ETAPI token>" -w "HTTP %{http_code}\n"
HTTP 204

⚠️ 是 PUT 不是 POST:实测 POST /etapi/backup/now 返回 {"message":"Router not found for request POST /etapi/backup/now"}(HTTP 404)。备份名即文件名组成部分:backup-now.db。ETAPI 用法详见 《Trilium v0.106.0 常用 CLI 命令与工具详解》。

10.3 升级与回滚(已实测演练)

升级三步:改 tag → pull → up -d(Compose 自动重建容器,数据目录不动):

# 1. 编辑 docker-compose.yml 把 image: triliumnext/trilium:v0.106.0 改为目标版本(如 v0.107.0)
vi docker-compose.yml

# 2. 拉取新镜像
docker compose pull
 Image triliumnext/trilium:latest Pulling
 Image triliumnext/trilium:latest Pulled
# 3. 重建(实测输出)
docker compose up -d
 Container trilium-0.106.0-app Starting
 Container trilium-0.106.0-app Started
docker compose ps --format '{{.Name}} {{.Image}} {{.Status}}'
trilium-0.106.0-app triliumnext/trilium:latest Up 6 seconds (healthy)

回滚:把 tag 改回旧版本再 docker compose up -d 即可(实测回锚 v0.106.0 后 /api/health-check 返回 200)。若升级后数据异常,先 docker compose down,用 backup/ 中的 backup-<日期>.db 覆盖 document.db 再回锚启动。

⚠️ 官方 v0.106.0 Release Notes 特别提示:升级后若容器显示 unhealthy,先检查 compose 中是否自定义覆盖了 healthcheck(新版健康检查脚本为 docker_healthcheck.sh,自定义覆盖会导致检查路径失效),必要时删除旧容器由 Compose 重建。

⚠️ 跨大代际升级(zadam v0.63.x 时代 → TriliumNext)不可一步到位直接同步旧客户端,官方明确 sync 版本已递增;先升级服务器并按官方升级文档处理,再同步各客户端(见 《Trilium 介绍与选型指南》2.2 节溯源)。

十一、常见问题

Q1:curl 健康检查返回 000 / 连接被拒? 先看 docker compose ps 是否 healthy:若一直 starting,docker compose logs trilium 查看监听端口——若注入过 TRILIUM_PORT 而端口映射仍指向 8080 就会出现映射错位(实测:TRILIUM_PORT=8090 时宿主 8139 → 容器 8080 映射失效,curl 返回 000)。要么去掉该变量,要么把 ports: 同步改成 '8139:8090'。

Q2:POST /api/setup/new-document 返回 401 "App already initialized"? 应用已初始化过(数据目录里已有 document.db)。这是防护逻辑不是故障;如需重新初始化,备份后清空数据目录再 up -d。

Q3:修改 config.ini 后不生效? config.ini 仅在启动时读取,修改后必须 docker compose restart trilium。确认改的是数据目录内生效文件(/opt/trilium/data/config.ini),不是部署目录里的 compose 文件。

Q4:docker compose down 会删数据吗? 不会。down 只移除容器与网络(见五回显),bind mount 的数据目录原样保留;但不要对数据目录执行 docker compose down -v 之外的清理脚本——-v 对 bind mount 同样无影响,真正危险的是手动 rm -rf /opt/trilium/data。

Q5:数据目录放 NAS/SMB 上可行吗? 可行但需挂载参数 nobrl 与 noperm(来源:官方 Docker 安装文档引用上游 issue #415,2026-10-22 查询),否则 SQLite 文件锁在 SMB 上会异常。

Q6:Compose 项目名怎么和写的不一样? 项目名中的点会被规范化:name: trilium-0.106.0-stack 实际生效为 trilium-01060-stack(down 回显可证)。想避免歧义就用不含点的名字,如 trilium-0-106-0-stack。

十二、参考链接