前言
在这个数据爆炸的时代,个人数据的价值愈发凸显,成为我们生活与工作中无可替代的重要资产。上一篇文章里,我介绍了从印象笔记迁移至 Joplin 的过程,这是我寻求数据自主掌控的关键一步。在探索同步方案时,我尝试了 OneDrive,原以为它能提供稳定高效的同步服务,可实际使用时却发现它对小文件缺乏优化,同步速度极慢,极大影响了使用体验。虽说目前还不确定是否存在数据丢失问题,但这样的效率实在难以满足我的需求。
于是,我决定深入研究,最终将目光锁定在 Joplin Server 笔记同步服务上。这不仅是一次技术探索,更是构建个人数据保全计划的核心之举。部署专属的 Joplin Server,意味着数据安全将得到更可靠的保障,访问更加便捷,从此彻底告别第三方云服务带来的种种隐患,真正实现个人数据的自主管理与全方位守护。接下来,我就为大家分享这一过程,希望能给同样在数据同步中迷茫的你一些启发。
准备 docker-compose 配置
官网文档:
根据官网文档,我整理了一下 docker-compose 配置
version: '3'
services:
app:
image: joplin/server:latest
ports:
- "22300:22300"
restart: unless-stopped
networks:
- pgsql
environment:
- 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镜像基本都挂了
我重新找了一个临时能用的(),先凑合着用,不知道啥时候就又停了
需要在 Container Station 里配置一下,(路径:属性 - Registry 服务器)
如果不行的话,可以在这个 gist 里找找有无其他可用镜像:
提取镜像
现在没法搜索镜像了(因为连不上 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 ,还是没解决
一开始我把环境变量设置为 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 服务
据说使用下面这个命令可以重启全部服务,不过我没有尝试
参考:
/etc/init.d/services.sh restart
我试了下通过 QNAP 管理界面操作:
- 登录 QNAP 的管理控制台。
- 前往「控制面板」->「系统设置」->「网络与文件服务」中的「Telnet/SSH」设置页面。
- 先关闭 SSH 服务,再重新启用,理论上似乎能达到重启服务的效果?
不过尝试之后很遗憾还是不行(摊手)
那就没有静态资源凑合使用吧… (所以说 QNAP 这系统是真的垃圾)
尝试使用 nginx 转发
我尝试了增加一个 nginx 容器做转发
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
restart: unless-stopped
networks:
- default
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- 22380:8000
depends_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;
不过折腾了半天还是没成功
参考:
重新配置QNAP的反向代理
最终还是在QNAP控制台里重新配置代理
把目标从 localhost:22300 改成 domain:22300 才搞定……
登录控制台
输入默认邮箱和密码登录
进入后台之后按照官方的建议选择创建个新用户来同步。
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 的数据。