Joplin Server本身虽然有接口,但是并不能直接获取笔记数据,了解后发现Joplin Terminal是支持Data API的,这样的话,可以通过在服务器部署一套Joplin Terminal程序来从服务器提供笔记数据,唯一的问题可能就是会导致服务器存储两份笔记数据,不过也不是很大的问题,这里以通过Docker容器部署为例。
# 创建数据存储文件夹
mkdir -p joplin/cli
cd joplin/cli
npm i joplin
# 同步配置参考官方文档 https://joplinapp.org/help/apps/terminal/
# 同步数据
npx joplin sync
修改项目的package.json,增加一个启动脚本。
{
"type": "module",
"scripts": {
"joplin": "joplin server start",
...
},
"dependencies": {
"joplin": "^3.4.1"
}
}
npm run joplin
services:
...
joplin-api:
image: node:22.12.0
restart: unless-stopped
# 这个应该根据实际的uid和gid设置,与挂载目录的/home/test有关
user: 1000:1000
volumes:
# 挂载这个文件主要是为了保持权限一致,避免本地修改容器不能运行
- /etc/passwd:/etc/passwd:ro
# 挂载项目代码
- ./joplin/cli:/app
# joplin数据保存位置
- ./joplin/data:/home/test/.config/joplin
- ./joplin/.npm:/home/test/.npm/
# 这个start命令参考下面
command: ["sh", "-c", "chdir /app && npm start"]
joplin terminal启动的data api默认是写死的绑定127.0.0.1,需要本地启动一个反向代理服务器来做一下请求转发,同时也配置一下定时任务。 我这里服务器用的h3,用什么其实都可以,感觉JS的Web框架语法都差不太多,这里选h3主要是为了资源占用少。
import { H3 } from "h3"
import { createServer } from 'node:http'
import { toNodeHandler } from "h3/node"
import cron from 'node-cron'
import { exec } from "node:child_process"
/**
* 运行node-cron定时任务
* /30 * * * /path/to/joplin sync
*/
cron.schedule('*/15 * * * *', joplinSync)
/**
* 同步数据
*/
export async function joplinSync() {
exec('/app/node_modules/.bin/joplin sync', (_, stdout) => {
console.log('joplin sync: ', stdout)
})
}
export const app = new H3()
/**
* 反向代理外界请求到本机的41184端口
* joplin Data API Server默认监听41184,因为Docker环境,也不太可能出现冲突的问题
*/
app.use(
async (event) => {
const { url } = event.req
const proxyUrl = new URL(url)
proxyUrl.protocol = 'http'
proxyUrl.host = 'localhost:41184'
const proxy = await fetch(proxyUrl.toString())
return proxy.body
}
)
createServer(toNodeHandler(app)).listen(3000, '0.0.0.0')
{
"type": "module",
"scripts": {
"proxy": "node --experimental-strip-types index.ts",
"joplin": "joplin server start",
"start": "npm run proxy & npm run joplin"
},
"dependencies": {
"h3": "^2.0.1-rc.2",
"joplin": "^3.4.1",
"node-cron": "^4.2.1"
},
"devDependencies": {
"@types/node": "^24.7.1"
}
}
后面其实就简单了,感觉直接开放到公共网络不是很安全,最好还是通过容器间通信使用,真正的权限鉴定放在h3这一层。