1. 为什么选择 PVE + Linux + Trilium 这套组合
1.1 PVE 是折腾笔记服务的理想底座
先说结论:如果你手头有一台常年开机的 x86 小主机或者退役 PC,那么 Proxmox VE 这套虚拟化平台就是用来跑自托管服务的首选底座。PVE 基于 Debian,支持 KVM 虚拟机和 LXC 容器,自带 Web 管理界面,装好之后就是一个完整的私有云基础设施。
我见过不少人直接在物理机上裸装 Debian,然后把 Trilium、Nextcloud、Gitea 全部塞进同一个系统里。这种做法短期没问题,一旦你想升级系统、换发行版、或者测试一个高风险配置,就得提心吊胆——因为所有服务绑在同一台机器上,一个包损坏就是全军覆没。PVE 的价值在于隔离:每个服务一个虚拟机,系统坏了直接删掉重建,宿主机永远干干净净。
而且 PVE 的快照功能非常实用。部署 Trilium 之前打一个快照,部署过程中就算把系统搞挂了,一条命令回滚到之前的干净状态,整个过程不超过两分钟。这一点是裸机安装完全做不到的。
1.2 Trilium 与其他笔记方案的差异
Trilium 是一款开源层级笔记应用,主打树形结构管理笔记,支持笔记间双向链接、思维导图、加密、版本历史、代码块高亮,还支持通过脚本扩展功能。它和市面上常见的笔记工具有一定差异,我实际用了两年多,简单对比一下:
| 对比项 | Trilium | 传统云笔记 | 纯本地 Markdown 工具 |
|---|---|---|---|
| 数据归属 | 完全自托管,数据在本机 | 数据在第三方服务器 | 数据在本机,但同步繁琐 |
| 层级组织 | 树形结构天然支持 | 标签/文件夹混用,层级弱 | 靠目录结构模拟 |
| 联网要求 | 局域网/公网均可访问 | 必须联网 | 不需要,但多设备同步难 |
| 扩展性 | 支持脚本和主题定制 | 受平台限制 | 依赖插件生态 |
| 数据格式 | SQLite 数据库 + 资源目录 | 私有格式 | 普通文件 |
Trilium 的树形笔记结构是我最看重的一点。传统笔记工具靠标签和文件夹组织内容,笔记多了之后找东西全靠搜索;Trilium 允许你像建目录树一样组织笔记,父节点可以包含子节点,整棵知识树就和你的思维结构完全对应,跨笔记引用也不会乱。
1.3 方案取舍:虚拟化方式与系统选型
在 PVE 中部署服务有两条路:LXC 容器和 KVM 虚拟机。Trilium 官方推荐 Node.js 环境,LXC 也能跑,但我实际测试下来,更推荐用 KVM 虚拟机。
理由有三个。第一,LXC 容器和宿主机共享内核,如果你后续想折腾不同发行版(比如 Debian、Ubuntu、Rocky Linux 换着用),容器能提供的隔离性有限;KVM 是完整虚拟化,系统随便换,内核互相不干扰。第二,Trilium 的备份、迁移、快照在 KVM 虚拟机上操作更简单——整个虚拟机的磁盘就是一个文件,备份就是复制文件,恢复就是粘贴回去。第三,KVM 虚拟机的内存分配方式更灵活,后续资源不足时热添加内存也很方便。
至于 Linux 发行版的选择,我用的是 Debian。原因很简单:Debian 稳定、占用小、文档多,社区问题积累深厚,踩坑之后基本都能搜索到答案。如果你个人更熟悉 Ubuntu,用 Ubuntu Server 也完全没问题,操作步骤几乎相同,只是包管理命令一致,没有本质区别。
2. 部署前置:PVE 环境准备与虚拟机创建
2.1 PVE 源优化与系统更新
在创建虚拟机之前,我建议先把你手头的 PVE 源处理一下。默认安装的 PVE 企业源在没有订阅密钥的情况下会报错,虽然不影响功能,但每次 apt 更新都刷红字,看着心烦,而且企业源在国内的访问速度通常不理想。
编辑/etc/apt/sources.list,把 debian 相关的源替换成国内可用的镜像源。再编辑/etc/apt/sources.list.d/pve-enterprise.list,要么注释掉企业源,要么替换为无订阅版本的源。具体操作不展开,网上资料很多,核心思路就是让apt update能正常跑、速度还快。
然后执行:
apt update && apt dist-upgrade -y把宿主机系统升级到最新。这一步很重要,PVE 的内核和 KVM 模块会持续更新,旧版本对较新的 CPU 特性支持可能不完整,直接影响到虚拟机的性能。如果你在 PVE 7.x 版本并且正打算升级到更高级别,建议先看一下官方升级文档,按步骤操作,不要在带业务的环境里贸然跳版本升级。
2.2 创建 Linux 虚拟机:关键参数与踩坑
创建虚拟机的入口在 PVE Web 界面的右上角“创建虚拟机”。我按生产环境的标准,梳理一份适合 Trilium 的参数表:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| 虚拟机 ID | 104(按自己习惯) | 建议单独分配一个号段,方便管理 |
| 名称 | trilium | 一眼能认出用途 |
| ISO 镜像 | Debian 12 netinst | 网络安装镜像,体积小 |
| 系统类型 | Linux 6.x - 2.6.32 Kernel | 选这个兼容性最好 |
| 磁盘控制器 | VirtIO Block | 性能比 IDE 好很多 |
| 硬盘 | 32 GB | Trilium 本体不大,但笔记资源文件会增长 |
| CPU | 2 核 host 类型 | host 模式可以让虚拟机直接使用宿主 CPU 特性 |
| 内存 | 2048 MB | Trilium 服务端 + Node.js 实测占用约 800MB-1GB |
| 网络 | VirtIO 桥接模式 | 和宿主机同一网段,便于访问 |
有几个坑需要提前说。第一,CPU 类型要选 host,不要选 kvm64 或者 qemu64。后者是一颗虚拟的通用 CPU,不支持硬件加速指令集,跑 Node.js 这类对性能敏感的应用差距巨大。第二,硬盘一定要用 VirtIO,默认可能是 IDE,性能差好几倍,装系统之前就要选好。第三,磁盘空间我给的是 32GB,如果你打算上传大量 PDF 或者图片作为笔记附件,建议直接给 64GB,虚拟机磁盘扩容虽然也支持,但挂载新分区或者用 growpart 扩容步骤多一点,不如一次性给够。
2.3 无头安装 Linux 与网络配置
创建完虚拟机之后,启动并从 ISO 引导,进入 Debian 安装界面。PVE 的 noVNC 控制台支持鼠标键盘操作,整个安装流程和物理机一模一样。唯一要注意的是,安装到“软件选择”这一步,不要勾选任何桌面环境,只需要标准系统工具和 SSH Server 即可。Trilium 是 Web 应用,部署完成后通过浏览器访问,虚拟机本身不需要图形界面,装桌面纯属浪费内存。
安装完成之后,进入系统第一件事是设置静态 IP。Debian 12 使用/etc/network/interfaces或/etc/network/interfaces.d/配置网络:
source /etc/network/interfaces.d/* auto enp6s18 iface enp6s18 inet static address 192.168.1.50/24 gateway 192.168.1.1 dns-nameservers 223.5.5.5 119.29.29.29网卡名称不一定是 enp6s18,用ip a查看实际接口名替换即可。配置完重启网络服务:
systemctl restart networking静态 IP 是对自托管服务的基本要求。如果使用 DHCP,路由器重启后虚拟机 IP 变了,你前一天记的192.168.1.50第二天就打不开了,到时候还要去 PVE 控制台翻 IP,纯属给自己找麻烦。
3. Trilium 部署实操:两种路径与完整配置
3.1 原生 Node.js 部署:适合喜欢看日志的人
Trilium 官方提供两种部署方式:一种是直接下载 GitHub Release 包运行,另一种是 Docker 镜像。先讲原生部署。
先安装依赖:
apt install -y curl wget unzip然后去 GitHub Releases 页面找到最新版本,下载trilium-server-*.zip这个包。这里有个经验:下载之前用curl -s https://api.github.com/repos/zadam/trilium/releases/latest先看一下当前版本号,避免手动翻页面。
解压并移动到合适的位置:
mkdir -p /opt/trilium unzip trilium-server-*.zip -d /opt/triliumTrilium 服务端是 Node.js 应用,自带一个二进制文件(Linux 版的 trilium 包里已经打包了 Node.js runtime),不需要额外安装 Node.js。直接启动测试:
cd /opt/trilium ./trilium.sh默认监听0.0.0.0:8080,如果端口被占用,可以在环境变量中修改TRILIUM_PORT。浏览器访问http://192.168.1.50:8080,第一次访问会让你设置密码,这个密码就是管理员密码,后续所有数据都受它保护。
为了让它作为系统服务常驻运行,在/etc/systemd/system/trilium.service写一个服务文件:
[Unit] Description=Trilium Notes Server After=network.target [Service] Type=simple User=root WorkingDirectory=/opt/trilium ExecStart=/opt/trilium/trilium.sh Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target这里我直接用了 root 用户跑,如果你比较在意安全性,可以单独建一个用户,但那样需要处理目录权限,稍微麻烦一点。家用环境用 root 没有太大问题,公司环境建议还是按最小权限原则来。
生效并设置开机自启:
systemctl daemon-reload systemctl enable --now trilium3.2 Docker 部署:更省心的选择
如果你本来就装了 Docker,或者对 Node.js 环境不太熟悉,直接跑容器是更省心的选择。Trilium 官方提供了镜像,支持的架构很全,更新升级也简单。
官方推荐的 Docker Compose 方式:
version: "3.8" services: trilium: image: zadam/trilium:latest container_name: trilium restart: unless-stopped ports: - "8080:8080" volumes: - ./trilium-data:/home/node/trilium-data environment: - TRILIUM_DATA_DIR=/home/node/trilium-data启动之前先建好数据目录并设置写权限:
mkdir -p /opt/trilium-docker/trilium-data chown -R 1000:1000 /opt/trilium-docker/trilium-data cd /opt/trilium-docker docker compose up -d这里有个细节:容器内的 Node 用户 UID 是 1000,所以宿主机目录要 chown 给 1000,否则容器写数据会报权限错误。我一开始忽略了这个,结果启动之后页面能打开,但一创建笔记就报错,排查了半天才发现是权限问题。
原生部署和 Docker 部署怎么选?我的建议是:如果你已经在 PVE 里跑了其他 Docker 服务,那保持一致,用 Docker;如果你是为 Trilium 单独建了一台虚拟机,而且长期只跑这一个服务,那原生部署更轻量,少一层容器开销,日志查看也更直观。两种方案长期运行时我实测都很稳定,你自己看习惯选。
3.3 HTTPS 与反向代理:Nginx 配置
Trilium 默认跑在 8080 端口,直接 HTTP 明文访问。家用局域网问题不大,但如果你的 PVE 主机有公网端口转发,或者你打算通过异地网络访问笔记服务,那必须先套一层 HTTPS,否则所有笔记内容在网络里都是明文传输,密码、隐私、自己的思考记录都属于裸奔状态。
我在虚拟机里装了 Nginx 做反向代理,同时用 acme.sh 或者 certbot 签发证书。Trilium 本身不负责 TLS 握手,它只需要监听本地回环地址,由 Nginx 统一处理外部请求。
一个简化后的 Nginx 配置:
server { listen 80; server_name notes.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name notes.example.com; ssl_certificate /etc/nginx/ssl/notes.pem; ssl_certificate_key /etc/nginx/ssl/notes.key; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }最后两个 Header 很关键,因为 Trilium 前后端通信用了 WebSocket,Nginx 必须把 Upgrade 和 Connection 头正确转发,否则笔记编辑时会频繁掉线、保存失败。这个问题在中文社区里出现频率很高,排查询问时优先检查这一条。
走 Docker 部署的话,Nginx 容器和 Trilium 容器可以挂在同一个自定义 bridge 网络上,用容器名互相访问,这样就不用暴露 8080 端口了,更安全。
3.4 备份策略与开机自启
自托管服务最怕的就是硬盘突然挂掉,什么都没有了。Trilium 的所有笔记数据都存放在一个 SQLite 数据库文件里,路径在trilium-data/document.db,另外还有一个trilium-data/backup目录存放自动备份的文件。资源文件(比如你插入的图片、PDF 附件)存在trilium-data下的对应目录里。
我每三天跑一次备份脚本,把整个trilium-data目录压缩后复制到宿主机 PVE 的存储上:
#!/bin/bash # 备份脚本,放在 /usr/local/bin/trilium-backup.sh BACKUP_DIR="/backup/trilium" DATA_DIR="/opt/trilium/trilium-data" TIMESTAMP=$(date +%Y%m%d_%H%M%S) mkdir -p $BACKUP_DIR cd $DATA_DIR tar czf "$BACKUP_DIR/trilium_$TIMESTAMP.tar.gz" . # 只保留最近 14 天的备份 find $BACKUP_DIR -name "trilium_*.tar.gz" -mtime +14 -delete如果你用的是 Docker 部署,数据目录在宿主机/opt/trilium-docker/trilium-data,脚本里改一下路径即可。
开机自启这一点,原生部署已经通过 systemd 服务实现了,Docker 部署在 compose 文件里配置了restart: unless-stopped,宿主机重启时也会自动跟着启动。这套机制我实际验证过,PVE 断电恢复后,虚拟机起来,Trilium 自己就回来了,不需要任何人工干预。
4. 踩坑实录:常见问题与排查方法
4.1 PVE 控制台无法粘贴内容的解决办法
这个坑几乎是所有 PVE 新手都会遇到:用 noVNC 控制台操作虚拟机时,想复制一条命令进去,右键粘贴一点反应都没有。原因在于 noVNC 默认不捕获宿主机剪贴板,你从浏览器外部复制的文本无法直接粘贴进虚拟机的终端。
解决办法有两个。第一个,使用 xterm.js 终端时,可以在 PVE 的虚拟机控制台面板右上角打开“粘贴”按钮,它会弹出一个文本输入框,把内容粘贴到那里再点确定即可完成输入。第二个,如果你觉得每次弹输入框太麻烦,改用 SSH 连接虚拟机操作。装上 SSH Server 之后,所有命令操作都在你自己的终端工具里进行,复制粘贴完全正常。
4.2 Trilium 内存占用与优化
Trilium 服务端加上内置的 Node.js 进程,平时 idle 状态下大概占用 500MB-800MB 内存,如果你开启了全文索引或者笔记数量非常多,内存占用可能会上升到 1GB 以上。我设置的 2GB 内存配置在长时间运行下完全够用,内存压力指标一直保持在正常范围。
如果你只有一台内存较小的小主机,比如 8GB 或者 4GB,可以调整 JVM 堆大小(Trilium 依赖 Java 的 Lucene 做全文搜索)来控制内存占用。在启动参数中添加:
TRILIUM_JAVA_OPTS="-Xmx512m"不是所有版本都支持这个环境变量,具体要以你下载版本对应的官方文档为准。如果发现内存还是不够,优先检查是不是笔记里嵌入了大量大图片,Trilium 的缩略图缓存偶尔会积累很多文件。
4.3 数据备份恢复与版本升级
版本升级是自托管服务绕不开的话题。Trilium 发版频率不低,经常有新功能或者 bug 修复。我升级之前一定会做两件事:第一,把虚拟机的快照打一个;第二,把document.db单独用 SQLite 的命令行工具导出一份副本。
先说快照。在 PVE Web 界面选中 Trilium 虚拟机,点击“快照”按钮,填写描述后确认。快照不会中断服务,整个过程瞬间完成,但前提是磁盘格式支持(qcow2 或 zfs)。快照的好处是升级后如果发现问题,可以一瞬间回到升级前的状态,包括数据。
再说 SQLite 导出。在 Trilium 服务停止的状态下执行:
sqlite3 /opt/trilium/trilium-data/document.db ".backup '/backup/trilium/document_before_upgrade.db'"这个备份不依赖 Trilium 自带的备份机制,是数据库层面的完整快照,即使后续版本回滚也没有兼容性问题。
恢复备份同样简单:把解压出来的trilium-data整个目录覆盖回去,重启服务即可。需要注意,恢复时务必先停止 Trilium 服务,不要在服务运行中覆盖数据库文件,否则可能出现数据损坏。
4.4 其他高频问题速查表
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 页面能打开但登录后白屏 | Nginx 没有转发 WebSocket 头 | 检查 Upgrade/Connection 头配置 |
| 创建笔记时提示权限错误 | 数据目录属主不正确 | 重新 chown 目录 |
| 修改端口后浏览器连不上 | 防火墙没放行对应端口 | 使用ufw allow 端口/tcp放行 |
| 移动端访问排版异常 | 浏览器版本过老,不支持现代 JS | 使用较新的浏览器访问 |
| 同步到其他设备失败 | Trilium 本身不支持多客户端同步 | 使用 TriliumNext 分支或官方同步功能配置 |
| PVE 重启后虚拟机没有自动启动 | 虚拟机未设置开机自启 | 在虚拟机选项里勾选“开机自启”,设置启动顺序 |
Trilium 的官方同步功能只在较新版本里才比较稳定,如果你有手机端和电脑端同时编辑大量笔记的硬需求,建议直接看 TriliumNext 社区分支,它对移动端适配和同步功能做了大量改进。如果只是家用场景固定一个浏览器访问,原版完全足够。
5. 写在最后的个人经验
这套 PVE + Debian + Trilium 的组合我稳定运行了一年半,中间经历过三次 PVE 大版本升级、两次 Trilium 版本跨更、一次宿主机断电,笔记数据一次都没有丢过。最大的心得就两条。
第一,一切配置都要围绕“可恢复”来做。快照随手打,数据目录集中放,备份脚本自动化。Trilium 的数据结构本身很简单,但正因为简单,覆盖恢复才如此可靠。我见过不少人在虚拟机上跑了一两年笔记服务,却从来没有做过一次完整恢复演练——等到真出事的那天才发现备份根目录权限不对、脚本早就跑失败了。建议你部署完成后,花半小时做一次“从备份恢复到全新虚拟机”的完整流程,走通一遍之后才有真正的安全感。
第二,别在版本选择上花太多时间。Trilium 官方版、TriliumNext、第三方 Docker 镜像,每个之间有一些细微差别。选一个文档全、社区活跃的版本用起来,遇到问题查得到解决,比纠结某个冷门功能能不能用更重要。
这个部署方案的扩展方向也很多:后续可以在这个 Linux 虚拟机里再装一个 WebDAV 服务,让手机上的笔记附件自动同步过来;也可以在另一台虚拟机里部署自动化流程工具,通过 API 把浏览器收藏的文章抓取后写入 Trilium;甚至可以把整棵知识树里的笔记定时导出为 Markdown 存档,做一个公开的知识库站点。基础打好了,上面的玩法就全看你自己的想象力了。