Note Mark Docker Compose 部署指南(基于 1.1.1 实测)
使用 Docker Compose 部署 Note Mark 1.1.1:官方镜像与国内拉取方案、compose 编排、初始化管理员、数据持久化布局、Unix Socket 监听、运维命令与常见问题排障全流程实录。
Note Mark Docker Compose 部署指南(基于 1.1.1 实测)
目标:在一台 Linux 服务器上以 Docker Compose 部署 Note Mark 1.1.1(官方容器镜像为主推方式),覆盖镜像选型与国内拉取方案、compose 编排、管理员初始化、数据持久化布局验证、Unix Socket 监听实验、日常运维命令与常见问题排障。全流程已在 Ubuntu 22.04 服务器(内网 192.168.1.200)实测通过。
一、环境信息
| 项 | 值 |
|---|---|
| 服务器 | Ubuntu 22.04(内网 192.168.1.200) |
| 软件版本 | Note Mark 1.1.1(当前最新稳定版) |
| 服务端口 | 8136(宿主)→ 8080(服务默认监听) |
| 部署目录 | /opt/note-mark/stack |
| 示例账号 | admin / q1w2e3r4(本文所有登录示例均使用该账号) |
版本说明:撰写本文时经 shields.io 实时徽章核实,Note Mark 最新稳定版为 v1.1.1(查询日期 2026-10-30)。组件背景与选型分析见《Note Mark 介绍与选型指南:轻量级自托管 Markdown 笔记与分享服务》。
二、镜像选型与国内拉取实测
官方唯一分发镜像为:
ghcr.io/enchant97/note-mark:1.1.1
实测该镜像为 distroless 静态底座构建,压缩后拉取体积小,解压后约 49.3MB,摘要:
ghcr.io/enchant97/note-mark@sha256:71412c7f319db72e48117a0e3be6718da9475ff5966f6a3082d6b0220a25b8f9
当 ghcr 直连缓慢时,可使用 DaoCloud 公共镜像加速前缀拉取(实测可用):
docker.m.daocloud.io/enchant97/note-mark:1.1.1
拉取后打回原 tag 即可让 compose 直接引用官方名:
docker pull docker.m.daocloud.io/enchant97/note-mark:1.1.1
docker tag docker.m.daocloud.io/enchant97/note-mark:1.1.1 ghcr.io/enchant97/note-mark:1.1.1
注意:官方镜像内不含任何 shell(distroless),
docker exec ... sh会直接报executable file not found。这既是安全优点也是运维注意点,后文排障章节详述。
三、编写 compose 编排文件
部署目录 /opt/note-mark/stack/docker-compose.yml 完整内容(与实测环境一致):
name: note-mark-1-1-1-stack
networks:
note-mark-net:
driver: bridge
ipam:
config:
- subnet: 10.89.61.0/24
volumes:
data:
services:
note-mark:
image: ghcr.io/enchant97/note-mark:1.1.1
container_name: note-mark-1.1.1-web
restart: unless-stopped
networks:
note-mark-net:
ipv4_address: 10.89.61.10
volumes:
- data:/data
environment:
AUTH_TOKEN__SECRET: "<替换为下方生成的密钥>"
PUBLIC_URL: "http://192.168.1.200:8136"
LOGGING__LEVEL: "info"
ports:
- "8136:8080"
几个编排要点:
name: note-mark-1-1-1-stack:显式指定 compose 项目名。注意 Docker Compose 会把项目名中的点号规范化为短横线(note-mark-1.1.1-stack若直接写点号,实际生成的项目名是note-mark-1-1-1-stack),后续docker compose -p系列命令、卷名前缀都以规范化名为准,混用会导致 down 不掉资源。AUTH_TOKEN__SECRET:JWT 签名密钥,必填,Base64 解码后需不少于 32 字节。生成方式:
openssl rand -base64 96 | tr -d '\n'
PUBLIC_URL:对外访问地址,必填,末尾不能带斜杠(服务启动校验endsnotwith=/,否则起不来)。它同时是 CORS 白名单来源,影响 Web 界面跨域行为。- 网络:自定义网段从空闲池中显式分配(本文取
10.89.61.0/24),避免与既有自定义网络冲突;静态 IP 非必需,按需保留。 - 数据卷:单一命名卷挂载到
/data,SQLite 数据库与笔记文件都在其中。
启动:
cd /opt/note-mark/stack
docker compose up -d
docker compose ps
实测 docker compose ps 输出状态为 Up,端口映射 0.0.0.0:8136->8080/tcp。
四、初始化管理员账号
Note Mark 首次启动不会引导注册管理员,需要用内置 CLI 创建。镜像内可直接执行二进制(无需 shell):
docker exec note-mark-1.1.1-web /note-mark user add -u admin -p q1w2e3r4
CLI 成功后无报错输出;若用户已存在会提示唯一性冲突。创建后打开 http://192.168.1.200:8136 用 admin / q1w2e3r4 登录即可。
CLI 还支持以下子命令(docker exec note-mark-1.1.1-web /note-mark <子命令>):
| 子命令 | 用途 |
|---|---|
user add -u <名> -p <密码> | 新建用户 |
user set-password -u <名> -p <新密码> | 重置密码(实测改后立即可登录) |
user remove -u <名> | 删除用户 |
user remove-password -u <名> | 移除密码(配合 OIDC 登录) |
user add-oidc-mapping -u <名> --user-sub <sub> | 绑定 OIDC 身份 |
clear-cache [-u <名>] | 清空笔记树缓存(外部直接改文件后必须执行) |
clean trash | 永久清理所有用户回收站 |
clean users | 永久清除已标记删除的用户 |
五、验证服务与数据布局
5.1 健康检查
curl http://127.0.0.1:8136/heartbeat # 返回 ".",HTTP 200
curl http://127.0.0.1:8136/api/info
/api/info 实测返回:
{"minSupportedVersion":"1.0.0","allowInternalSignup":true,"allowInternalLogin":true,"enableAnonymousUserSearch":true}
5.2 数据持久化布局
命名卷实际落盘在 /var/lib/docker/volumes/note-mark-1-1-1-stack_data/_data,实测结构:
_data/
├── db.sqlite # 用户/会话/树缓存元数据
└── notes/
└── admin/ # 每个用户一个目录
├── my-space.md # 空间首页(Markdown + frontmatter)
├── my-space/ # 空间目录,下挂笔记
│ ├── meeting.md
│ └── img.png # 附件资产
└── .trash/ # 回收站(按时间戳目录隔离)
这正是官方强调的"标准文件/文件夹系统":任何时候都可以直接备份整个 _data 目录,或用 Git 管理笔记内容。注意:若绕过服务直接改动文件,需执行 clear-cache 刷新内存中的笔记树。
5.3 Unix Socket 监听(实测)
Note Mark 支持以 Unix Socket 取代 TCP 监听。在另一实例上实测设置 BIND__UNIX_SOCKET=/data/nm.sock 后,启动日志输出:
Serving on /data/nm.sock
且 Unix Socket 生效时覆盖 TCP 监听(不再占用 8080 端口)。宿主机用 curl 验证:
curl --unix-socket /var/lib/docker/volumes/<卷名>/_data/nm.sock http://localhost/heartbeat
该模式适合前端有反向代理(Nginx/Caddy 同机部署)的场景,免除 TCP 端口暴露。全部环境变量(含 BIND__UNIX_SOCKET)的逐项说明见本专栏《Note Mark 配置参数详解》。
六、日常运维命令
cd /opt/note-mark/stack
docker compose ps # 状态
docker compose logs -f --tail 100 # 日志(JSON 格式,LOGGING__ENABLE_JSON 默认开启)
docker compose restart # 重启
docker compose down # 停止并移除(保留数据卷)
docker compose down -v # 停止并连同数据卷一起清除(危险,先备份)
升级到新版本:修改 compose 中镜像 tag → docker compose pull → docker compose up -d,数据卷沿用。降级前务必确认新版本未对 SQLite 做不兼容迁移。
七、常见问题排障实录
7.1 服务起来了但外部访问不通
服务配置未显式指定监听地址时,默认绑定 127.0.0.1,外部机器无法连接。排查思路:先在宿主机 curl http://127.0.0.1:8136/heartbeat 验证服务本身,再确认环境变量已设置 BIND__HOST=0.0.0.0(官方镜像内已内置该默认,自建配置时容易漏)。
7.2 启动即退出:PUBLIC_URL / SECRET 校验失败
实测两类高频启动失败:
PUBLIC_URL末尾带斜杠:违反endsnotwith=/校验,改为http://192.168.1.200:8136;AUTH_TOKEN__SECRET强度不足:Base64 解码后不足 32 字节直接拒绝启动,用openssl rand -base64 96生成。
排障时 docker compose logs 是第一入口,校验错误会明确打印违规字段。
7.3 无法进入容器排查
distroless 镜像无 shell,docker exec note-mark-1.1.1-web sh 报 executable file not found in $PATH。替代手段:
docker exec note-mark-1.1.1-web /note-mark --help # 直接执行主程序子命令
docker logs note-mark-1.1.1-web # 看结构化日志
需要 shell 级调试时,可临时以同一数据卷另起一个带 busybox 的实例挂载排查,排查完即删。
7.4 回收站内删除报 500
实测对回收站深层路径(如 .trash/<时间戳>/<空间>/<笔记>)调用删除接口偶发 500 unknown error occurred。规避方式:重试一次;仍失败则用 CLI 兜底清理:
docker exec note-mark-1.1.1-web /note-mark clean trash
7.5 文件被外部修改后界面不刷新
笔记树在服务内存中缓存(配合 SQLite cache 表加速),绕过服务直接改文件后必须执行 clear-cache,否则树视图与实际磁盘不一致:
docker exec note-mark-1.1.1-web /note-mark clear-cache -u admin
八、下一篇
部署完成后,建议继续阅读《Note Mark 配置参数详解》掌握全部环境变量,以及《Note Mark REST API 使用详解》实现脚本化内容管理;组件背景与选型回顾《Note Mark 介绍与选型指南:轻量级自托管 Markdown 笔记与分享服务》。