Note Mark Docker Compose 部署指南(基于 1.1.1 实测)

使用 Docker Compose 部署 Note Mark 1.1.1:官方镜像与国内拉取方案、compose 编排、初始化管理员、数据持久化布局、Unix Socket 监听、运维命令与常见问题排障全流程实录。

Note Mark自托管笔记MarkdownDocker ComposeDocker2026/10/30

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 笔记与分享服务》。