前言
在这个数据爆炸的时代,个人数据的价值愈发凸显,成为我们生活与工作中无可替代的重要资产。上一篇文章里,我介绍了从印象笔记迁移至 Joplin 的过程,这是我寻求数据自主掌控的关键一步。在探索同步方案时,我尝试了 OneDrive,原以为它能提供稳定高效的同步服务,可实际使用时却发现它对小文件缺乏优化,同步速度极慢,极大影响了使用体验。虽说目前还不确定是否存在数据丢失问题,但这样的效率实在难以满足我的需求。
于是,我决定深入研究,最终将目光锁定在 Joplin Server 笔记同步服务上。这不仅是一次技术探索,更是构建个人数据保全计划的核心之举。部署专属的 Joplin Server,意味着数据安全将得到更可靠的保障,访问更加便捷,从此彻底告别第三方云服务带来的种种隐患,真正实现个人数据的自主管理与全方位守护。接下来,我就为大家分享这一过程,希望能给同样在数据同步中迷茫的你一些启发。
准备 docker-compose 配置
官网文档: https://github.com/laurent22/joplin/blob/dev/packages/server/README.md
根据官网文档,我整理了一下 docker-compose 配置
version: '3'services:app:image: joplin/server:latestports:- "22300:22300"restart: unless-stoppednetworks:- pgsqlenvironment:- APP_PORT=22300- APP_BASE_URL=${APP_BASE_URL}- DB_CLIENT=${DB_CLIENT}- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}- POSTGRES_DATABASE=${POSTGRES_DATABASE}- POSTGRES_USER=${POSTGRES_USER}- POSTGRES_PORT=${POSTGRES_PORT}- POSTGRES_HOST=${POSTGRES_HOST}networks:pgsql:external: true
PS:这里我用之前部署好的 PostgreSql 数据库,所以把网络桥接到 pgsql 的网络里
可以看到这个配置里面还有一些环境变量
需要在相同目录下创建一个 .env
文件,内容如下:
DB_CLIENT=pg
POSTGRES_PASSWORD=your_password
POSTGRES_DATABASE=joplin
POSTGRES_USER=joplin
POSTGRES_PORT=5432
POSTGRES_HOST=pgsql
创建数据库
在 PostgreSql 里创建一个数据库给 joplin 用。
创建 joplin 数据库:
在 psql 提示符下,执行:
CREATE DATABASE joplin;
创建 joplin 用户:
执行下面的 SQL 语句,其中 'your_password'
请替换为你希望设置的实际密码:
CREATE USER joplin WITH ENCRYPTED PASSWORD 'your_password';
注:如果希望该用户拥有创建数据库的权限,可以增加 CREATEDB
权限,例如:
CREATE USER joplin WITH ENCRYPTED PASSWORD 'your_password' CREATEDB;
授予 joplin 用户访问 joplin 数据库的权限:
执行:
GRANT ALL PRIVILEGES ON DATABASE joplin TO joplin;
配置QNAP的docker镜像
由于某些不可抗力因素,之前能用的国内docker镜像基本都挂了
我重新找了一个临时能用的(https://docker.m.daocloud.io),先凑合着用,不知道啥时候就又停了
需要在 Container Station 里配置一下,(路径:属性 - Registry 服务器)
如果不行的话,可以在这个 gist 里找找有无其他可用镜像: https://gist.github.com/y0ngb1n/7e8f16af3242c7815e7ca2f0833d3ea6
提取镜像
现在没法搜索镜像了(因为连不上 docker hub)
只能点右上角的「提取」按钮(相当于 docker pull 命令)
然后输入镜像名称 joplin/server
服务器记得选择刚才添加的国内镜像
点击提取,在右上角可以看到进度
配置存储(可选)
默认情况下,项目内容(笔记、标签等)存储在数据库中,无需额外步骤即可使其工作。
然而,由于该内容可能相当大,可以通过设置 STORAGE_DRIVER
环境变量选择将其存储在数据库外部。
继续编辑上面的 .env
文件
STORAGE_DRIVER=Type=Filesystem; Path=/joplin-storage
然后在 docker-compose 里映射一下
volumes:- ./storage:/joplin-storage
注意:使用QNAP NAS的话,请自行创建这个目录,让docker自动创建的话这个目录变成了 admin 用户,joplin容器无法访问。
使用 docker-compose 命令启动
QNAP 上的 docker 还是很老的版本
在配置文件所在的目录里执行 docker-compose up
启动
对了,如果还显示无法pull镜像
可以把 image 换成 docker.m.daocloud.io/joplin/server
时间错误问题
我启动的时候遇到以下报错
app_1 | 12:27:17 0|app | Error: The device time drift is -32027ms (Max allowed: 2000ms) - cannot continue as it could cause data loss and conflicts on the sync clients. You may increase env var MAX_TIME_DRIFT to pass the check, or set to 0 to disabled the check.
app_1 | 12:27:17 0|app | at /home/joplin/packages/server/src/app.ts:292:11
app_1 | 12:27:17 0|app | at Generator.next (<anonymous>)
app_1 | 12:27:17 0|app | at fulfilled (/home/joplin/packages/server/dist/app.js:5:58)
app_1 | 12:27:17 0|app | at processTicksAndRejections (node:internal/process/task_queues:95:5)
这个错误提示说明 Joplin Server 在启动时检测到系统时间与预期时间之间存在较大偏差,具体偏差值为 -32027 毫秒(大约 32 秒),而默认允许的最大偏差为 2000 毫秒。这种时间漂移可能会导致同步客户端出现数据冲突或者数据丢失,所以服务出于安全考虑拒绝启动。
我的解决方法是同步 docker 时间+调整时间漂移检查参数
添加以下映射
volumes:- /etc/localtime:/etc/localtime:ro
添加以下环境变量
environment:- MAX_TIME_DRIFT=40000 # 允许 40 秒的时间漂移
再次启动就正常了
Invalid origin 问题
启动之后,我访问 NAS 上的 22300 端口,却提示 Invalid origin
这问题说难不难,主要是QNAP的反向代理需要再控制面板里面设置,但里面能配置的参数又太少了
看起来 QNAP 内置的 HTTP 服务器是 Apache,我参考了一下 github issues 里相同问题的 Request Header ,还是没解决
https://github.com/laurent22/joplin/issues/6008
一开始我把环境变量设置为 APP_BASE_URL=http://localhost:22300
可以打开管理页面了,但静态资源无法加载
SSH隧道
这时候我想到了万能的 SSH 隧道
我把服务器上的 22300 端口转发到本地访问不就得了?
于是直接本地执行
ssh -L 22300:localhost:22300 用户名@NAS地址
结果提示
channel 3: open failed: administratively prohibited: open failed
很明显这是服务端拒绝了我的端口转发请求
到 NAS 上去检查一下 /etc/ssh/sshd_config
配置文件
发现了这行配置
#AllowTcpForwarding yes
OK,现在把这个注释去掉,重启 SSH 服务就行
不过我在 /etc/init.d/
下面没找到 SSH 服务
据说使用下面这个命令可以重启全部服务,不过我没有尝试
参考: https://neolee.com/2023/11/05/威联通:重启服务
/etc/init.d/services.sh restart
我试了下通过 QNAP 管理界面操作:
- 登录 QNAP 的管理控制台。
- 前往「控制面板」->「系统设置」->「网络与文件服务」中的「Telnet/SSH」设置页面。
- 先关闭 SSH 服务,再重新启用,理论上似乎能达到重启服务的效果?
不过尝试之后很遗憾还是不行(摊手)
那就没有静态资源凑合使用吧… (所以说 QNAP 这系统是真的垃圾)
尝试使用 nginx 转发
我尝试了增加一个 nginx 容器做转发
services:nginx:image: nginx:stable-alpinecontainer_name: nginxrestart: unless-stoppednetworks:- defaultvolumes:- ./nginx.conf:/etc/nginx/conf.d/default.confports:- 22380:8000depends_on:- app
nginx.conf 配置
upstream joplin {# 这里要指向 Joplin 容器的内部地址和端口server app:22300;
}server {listen 8000;server_name joplin.dealiaxy.com;charset utf-8;client_max_body_size 100M;# 关键 CORS 配置add_header 'Access-Control-Allow-Origin' "$http_origin" always;add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With' always;add_header 'Access-Control-Allow-Credentials' 'true' always;add_header Referrer-Policy "strict-origin-when-cross-origin" always;if ($request_method = OPTIONS) {return 204;}location / {proxy_pass http://joplin;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 X-Forwarded-Port $server_port;proxy_set_header X-Forwarded-Host $host;# WebSocket 支持proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";}
}access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
server_tokens off;
不过折腾了半天还是没成功
参考: https://github.com/laurent22/joplin/issues/6350
重新配置QNAP的反向代理
最终还是在QNAP控制台里重新配置代理
把目标从 localhost:22300 改成 domain:22300 才搞定……
登录控制台
By default, Joplin Server will be setup with an admin user with email admin@localhost and password admin. For security purposes, the admin user's credentials should be changed. On the Admin Page, login as the admin user. In the upper right, select the Profile button update the admin password.
输入默认邮箱和密码登录
进入后台之后按照官方的建议选择创建个新用户来同步。
While the admin user can be used for synchronisation, it is recommended to create a separate non-admin user for it. To do so, navigate to the Users page - from there you can create a new user. Once this is done, you can use the email and password you specified to sync this user account with your Joplin clients.
虽然管理员用户可用于同步,但建议为它创建一个单独的非管理员用户。要这样做,请转到“用户”页面 - 从那里您可以创建新用户。完成此操作后,您可以使用您指定的电子邮件和密码将此用户帐户与您的 Joplin 客户端同步。
配置 joplin
在同步菜单里配置我们部署的 joplin server
回到主界面点击左下角的「同步」按钮,搞定!
这次的同步速度确实比OneDrive快多了
同步完成
没多久(十分钟差不多)就跑完了
来到管理后台可以看到已经占用了一些空间
看了下一万多条笔记在数据库里占用2G多的空间,还可以。
PS:介意的话可以单独启动一个数据库来存 joplin 的数据。