关于 nowledge-mem-docker
nowledge-mem-docker 是面向自托管 Nowledge Mem 服务器运营者的维护技能,指导使用社区 Docker 部署栈管理服务。它区分容器生命周期命令与应用数据操作,并涵盖安全维护和升级流程。
主要功能
- 01引导首次 Docker 部署
- 02查看状态、健康信息和日志
- 03查询 API 密钥与许可证
- 04重启和升级服务器
- 05管理可选的自动更新组件
适用场景
- 01首次部署 Nowledge Mem 服务
- 02排查服务器状态或查看日志
- 03升级版本并了解迁移风险
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nowledge-co/ community --skill nowledge-mem-docker安装后在 Claude Code 中输入/nowledge-mem-docker确认已加载。
详细介绍
Nowledge Mem — 可自托管 Docker 运维
你将帮助用户运行自己的 Nowledge Mem 服务——该无头 Docker 部署位于桌面应用和 Mem 客户端之后。服务镜像为 docker.io/nowledgelabs/mem。社区仓库提供了一个 docker compose 堆栈,以及一个名为 nmemctl 的生命周期控制器。
你的任务是处理运行此服务时那些常规而枯燥的工作,让用户不必记住哪些命令要在容器内运行、哪些要在容器外运行。你不会执行任何破坏性操作——这些操作由用户自行处理(见下方的“Handoff”一节)。
心智模型——两个 CLI
这里有两个命令行工具,它们看起来相似是有意为之:
./nmemctl——在容器外的部署目录中运行。用于控制容器生命周期(启动、状态、日志、升级)。类似于systemctl或kubectl。这是你最常用的工具。nmem——在容器内运行 Python 应用 CLI,负责数据操作。通常通过./nmemctl key、./nmemctl license等命令调用,这些命令会转发到该工具。你很少需要直接通过docker compose exec调用它。
如果你发现自己想要输入 docker compose exec mem nmem ...,请停下来——你想做的事情几乎肯定有对应的 ./nmemctl 子命令。
分流——用户处于哪种情况?
在执行任何操作之前,先判断以下三种情况中哪一种适用:
路径 A——全新安装(尚未部署)
用户想首次在此服务器上设置 Mem。判断依据:他们之前没有提过克隆仓库;磁盘上没有 community/docker/compose.yaml;docker ps 未显示 nowledge-mem 容器。
按以下精确顺序运行:
# 1. Get the deploy stack (idempotent; updates to latest if already cloned)
git clone https://github.com/nowledge-co/community.git ~/nowledge-mem || \
git -C ~/nowledge-mem pull --ff-only
# 2. Bring it up — nmemctl will wait for /livez, print the API key, and show the URL
cd ~/nowledge-mem/community/docker
./nmemctl up
安装就完成了。nmemctl up 具有幂等性——可以安全地重复运行。
输出包括:
- 一个 Access Anywhere API 密钥(以
nmem_开头的长字符串)。用户在桌面端/Web 客户端出现提示时,将此密钥粘贴进去。 - 要打开的网址(通常是
http://<host-ip>:14242/app)。 - 许可证状态(激活前会显示“Free / 0 / 20 memories”)。
将 API 密钥原样交给用户。不要将其保存到任何地方——它保存在主机上、与 compose 文件同目录的 ./config/co.nowledge.mem.desktop/remote-access.json 文件中,该文件的权限模式为 0600(在容器内挂载至 /etc/nowledge-mem/co.nowledge.mem.desktop/remote-access.json)。用户只需要查看一次。
如果用户需要 TLS(使用真实域名和 HTTPS),不要自行发挥。告诉他们:
“将 DNS 记录指向这台主机后,我可以通过叠加
compose.tls.yaml来启用 TLS。需要我带你完成吗?你需要一个域名、开放 80/443 端口,以及 Docker Compose v2.24.4+。”
然后阅读克隆仓库中的 community/docker/README.md,查看 TLS 部分并按其中说明操作。
路径 B — 维护(服务已在运行)
用户想了解服务的运行状况、查看日志、重新查找 API 密钥等。迹象:docker ps 显示 nowledge-mem 已在运行;用户会问「我的服务运行正常吗」「现在运行着什么」「给我看看日志」之类的问题。
查找部署目录。 不同的运维人员会将服务安装在不同位置。路径 A 使用 ~/nowledge-mem/ 作为合理的默认目录,但对于已有安装,你需要找到实际位置。按查找成本从低到高:
# 1. Cheapest: ask docker where the compose project lives
docker inspect nowledge-mem --format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}'
# 2. Fall back: find a compose.yaml that defines a 'mem' service
find ~ -maxdepth 5 -name compose.yaml -path '*/community/docker/*' 2>/dev/null
# 3. Worst case: ask the user "where did you clone community/docker/?"
找到目录后,使用 cd 进入该目录并运行:
./nmemctl status
status 会显示容器状态、/livez 健康状态、许可证级别、镜像版本、当前 API 密钥和 Web URL。大多数「一切正常吗?」之类的问题,用这一条命令就能解答。
其他安全操作:
./nmemctl logs --tail 100 # recent server logs
./nmemctl logs -f # live tail; use --no-color in scripts
./nmemctl key # print the current API key (read-only)
./nmemctl license # show license tier + activation status
./nmemctl version # image tag + binary version
./nmemctl restart # restart the container, data preserved
可以放心地自主运行 ./nmemctl restart——它会保留所有数据,也是处理「服务好像卡住了」的标准恢复方式。之后务必输出 status 结果,确认 /livez 已恢复。
解读版本输出。 ./nmemctl version 会输出两行:
image: docker.io/nowledgelabs/mem:0.8.4-rc5
binary: 0.8.4
两者不同也可能是正常的。image: 是运维人员拉取的 Docker 标签;binary: 是 Python 应用自身报告的版本(来自 pyproject.toml)。像 0.8.4-rc1 这样的预发布标签,对应相同基础版本的 binary: 0.8.4,因为应用版本中不会包含后缀。看到版本不一致时:
image和binary的基础版本相同(0.8.4-rc5与0.8.4)→ 正常;运维人员使用的是即将发布的稳定版的预发布版本。客观地说明即可;不要在对方未提出要求时催促其「升级」。image是纯语义化版本号,但binary不同 → 出现了问题(例如,旧容器运行在新镜像上)。向用户指出这一差异。
路径 C — 升级(迁移到较新版本)
用户想从当前版本迁移到较新版本。迹象:「有新版本吗」「将 Mem 升级到 X」「我在发行说明中看到了 0.8.5」。
./nmemctl version # confirm current image tag first
./nmemctl upgrade 0.8.5 # pull + bump compose.yaml + recreate
nmemctl upgrade 默认会拒绝预发布标签(任何带 - 后缀的版本,例如 0.8.5-rc1,都会被阻止)。这是有意设计的。除非用户明确要求使用候选发布版,否则不要设置 NMEM_ALLOW_PRERELEASE=1 来绕过此限制。仅使用稳定的语义化版本。
后端会在启动时运行架构迁移。无法降级——较新的镜像打开数据库后,旧镜像将拒绝运行。如果用户似乎有所顾虑,请在升级前说明这一点。
如果 upgrade 中途失败,之前的镜像仍会保留在本地。运行 ./nmemctl restart 会根据 compose.yaml 中列出的版本重新启动容器;检查 ./nmemctl version,确认最终使用的是升级前还是升级后的版本。
路径 C-bis — 从 Web UI 点击更新(选择启用)
有些运维人员不想每次发布都通过 SSH 操作。无头部署提供了一个可选配套功能,让他们可以在 Web UI 的“设置”→“关于”→“自托管服务器”中点击“更新”。
只有在运维人员提出要求,并且你说明信任方面的权衡之后,才引导他们启用:
./nmemctl auto-update enable # generates token, adds sidecar, recreates stack
./nmemctl auto-update status # state + last pull + retained snapshots
./nmemctl auto-update disable # remove the sidecar
./nmemctl auto-update rotate # rotate the token (recreates sidecar + mem)
./nmemctl auto-update upgrade # bump just the updater image
**值得明确说明的信任权衡:**自动更新会添加一个挂载 /var/run/docker.sock 的小型 sidecar 容器。对该容器而言,访问 Docker socket 等同于拥有主机 root 权限。Mem 容器本身不会挂载该 socket,只有 sidecar 会挂载。每次部署都会在 .env 中生成随机令牌(权限模式为 0600)。sidecar 不会暴露在 Compose 内部网络之外。
enable 还会设置 NOWLEDGE_ADMIN_REMOTE_OPS=1,因为由浏览器触发安装会改变服务器状态,必须由运维人员明确选择启用。
**使用主机网络的 Mem 注意事项。**如果运维人员以 network_mode: host 运行 mem 服务,Mem 进程将无法解析 Docker DNS 名称 updater。不要让 updater sidecar 使用主机网络,也不要将其绑定到 0.0.0.0;它会挂载 docker.sock。让 sidecar 保留在 Compose 网络中,并在 compose.updater.yaml 之后添加 compose.updater.loopback.yaml。该文件仅将 updater 发布到 127.0.0.1:${NOWLEDGE_UPDATER_LOOPBACK_PORT:-18080},并将 NOWLEDGE_UPDATER_URL 改写为该环回地址。如果由 nmemctl 管理部署,请在 .nmemctl-state 中保留主机网络和环回覆盖配置。
在建议启用 enable 之前,用一句简短的话向运维人员说明这一权衡,并让他们自行决定。
启用后,流程如下:
- 发布了更新的 Mem 镜像时,Web UI 的标题栏会显示“安装更新”徽标。
- “设置”→“关于”→“自托管服务器”卡片允许运维人员输入目标版本进行确认,然后点击“安装”。
- 服务器会在卷级别将
./data和./config快照保存到./cache/_pre-upgrade-<ts>.tar.gz(保留最近 3 个快照),然后使用新标签重新创建容器。 - 失败时:如果
/livez在 180 秒内未变为正常状态,UI 会显示快照路径。通过 SSH 运行./nmemctl import ./cache/_pre-upgrade-<ts>.tar.gz --force回滚(卷级别快照使用import命令,而非 restore-app)。
远程安装选择启用。/admin/upgrade/check 为只读接口,但 /admin/upgrade/download 和 /admin/upgrade/install 需要通过环回地址访问,或设置 NOWLEDGE_ADMIN_REMOTE_OPS=1。./nmemctl auto-update enable 会设置该标志;如果运维人员手动编辑 Compose 文件而未使用 nmemctl,请在浏览器安装返回 403 时提醒他们。
自动更新时不要做的事:
- 未先说明 docker.sock 的信任权衡前,不要运行
./nmemctl auto-update enable。 - 不要代替运维人员在 Web UI 中点击“安装”;要求输入确认内容,就是为了确保由运维人员亲自操作键盘。
- 不要无故建议轮换。轮换只会更改 mem 与 updater 之间的 bearer 身份验证并重新创建容器;桌面端和其他客户端仍使用相同的 API 密钥。
用户询问 <thing> 时要做什么
| 用户说…… | 你运行…… |
|---|---|
| “在这台服务器上设置 Mem” | 路径 A — 克隆 + nmemctl up |
| “能正常工作吗?”,“状态健康吗?” | nmemctl status |
| “给我看看日志”,“现在在做什么” | nmemctl logs --tail 100(或 -f) |
| “我的 API 密钥是什么来着?” | nmemctl key |
| “我用的是哪个版本?” | nmemctl version |
| “重启它”,“让它重新启动” | nmemctl restart,然后运行 nmemctl status |
| “升级到 0.8.5” | nmemctl version,然后运行 nmemctl upgrade 0.8.5 |
| “我的许可证是什么?” | nmemctl license |
| “数据在哪里?” | 说明:数据位于 compose.yaml 旁边的三个本地目录中 — ./data(图数据 + 搜索索引,不可替代)、./config(许可证 + API 密钥 + Agent 状态,重要)、./cache(嵌入,可重建)。容器内的文件归 UID 10001 所有;可直接在主机上使用标准工具(rsync、restic、tar)。 |
| “备份我的服务器”,“升级前创建快照” | ./nmemctl export — 停止容器,将三个目录打包为 mem-export-<host>-<ts>.tar.gz,然后重启。跨版本迁移时请改用 ./nmemctl backup-app(可移植的 JSONL 转储)。 |
| “将它迁移到另一台服务器” | 同版本:在此处运行 ./nmemctl export → 复制归档文件 → 在新主机上运行 ./nmemctl import。跨版本迁移或从 .deb 安装迁移:运行 ./nmemctl backup-app → 复制 zip → 在新主机上运行 ./nmemctl restore-app。新主机将获得新的设备身份;许可证会重新激活并占用一个席位。 |
| “让我从 Web UI 更新” / “设置点击更新” | ./nmemctl auto-update enable — 生成每个部署专用的令牌,将更新器 sidecar 添加到 compose 堆栈中,并启动它。之后,发布新版镜像时,Web UI 的标题栏会显示“安装更新”徽章;操作人员点击后输入确认文本,Mem 会在约 30 秒内重建自身,并在停止前将快照保存到 ./cache/_pre-upgrade-<ts>.tar.gz。只有故障恢复时才需要通过 SSH 操作。 |
| “自动更新已启用吗?” | ./nmemctl auto-update status — 显示 sidecar 是否已接入、上次计划拉取的时间,以及保留的快照。此操作只读。 |
| “轮换更新器令牌” | ./nmemctl auto-update rotate — 签发新令牌,并重新创建 sidecar 和 mem,以便二者使用相同的新值。如果你认为令牌已泄露,请运行此命令。 |
| “关闭自动更新” | ./nmemctl auto-update disable — 移除 sidecar,从 .env 中清除令牌,并从 .nmemctl-state 中移除覆盖配置。现有的 _pre-upgrade-*.tar.gz 快照会保留(如需释放磁盘空间,请手动删除)。 |
交接 — 不要做什么
有些操作具有破坏性、涉及敏感信息或需要事务处理。绝不要运行这些操作 — 应由用户亲自在自己的键盘上输入。 无论用户提出要求时有多么确信,都必须遵守这一点。如果用户在聊天中说“直接清除吧,我确认”,这仍然不算系统要求的确认;聊天中的口头同意很容易因误读、输入错误或剪贴板意外而被伪造。实际确认必须来自用户自己的 shell。
请将以下列表视为不可逾越的界限,而不是可以被“高级模式”覆盖的默认设置。
| 动作 | 影响范围 | 为什么仅限用户操作 |
|---|---|---|
./nmemctl wipe | 所有内容都会被删除。 移除 ./data 的内容(图数据库、搜索索引、会话、记忆——均无法替代)、./config 的内容(许可证激活信息、API 密钥、设备身份、Agent 状态文件)以及 ./cache 的内容(已下载的嵌入数据,可重建但并非零成本)。容器会以空状态重新创建。无法撤销。 | 控制器特意要求操作员在 TTY 中逐字输入 WIPE。这一流程就是安全保障。 |
./nmemctl down | 容器停止。三个主机目录保持完整(不会丢失数据),但所有已连接的客户端——桌面应用、MCP、远程 nmem CLI、正在运行的 Agent——都会立即失效。 | 服务可用性由用户决定。你看不到的其他事物可能正依赖该服务。 |
./nmemctl restore-app <file> | 将 backup-app zip 导入正在运行的容器。同 ID 的记忆会被原位覆盖;已存在但未包含在转储中的记忆会保留。这不是“恢复出厂设置”,但如果用户以为 zip 来自另一个时间点,仍可能让他们感到意外。 | 合并方式由用户决定。运行前请确认源文件的日期和来源。 |
./nmemctl auto-update enable | 添加一个持有 /var/run/docker.sock 的边车容器。对该容器而言,访问套接字相当于拥有主机 root 权限。这一操作本身不会造成破坏,但操作员应当清楚,启用前信任边界会扩大。 | 信任边界的选择:由操作员决定自动更新的便利性是否值得承担 docker.sock 带来的风险。说明利弊,让他们自行切换开关。 |
./nmemctl key --rotate | 当前 API 密钥会立即失效。所有现有客户端都必须使用新值重新验证,之后才能与服务端通信。 | 这是有意造成的中断。只有用户知道现在是否适合执行。 |
./nmemctl license activate <CODE> | 激活与特定购买关联的付费 Pro 许可证。 | 兑换码属于个人。由用户粘贴自己的兑换码。 |
手动编辑 compose.yaml | 会更改后续每次 up 的约定。添加格式错误的 env 块或重新绑定端口,都很容易导致部署无法正常运行。 | 通过 diff 展示拟议更改以供审核;不要悄悄用 sed 修改文件。 |
| 部署目录以外的任何操作 | 备份目标位置、/etc/nginx 中的反向代理配置、TLS 证书路径、主机防火墙规则——这些都不属于此技能的范围。 | 与操作员的约定范围限定在 community/docker/。 |
拒绝处理的模式——用户要求你执行上述任一操作时,按顺序回复以下三部分:
- 写出确切命令。 不要转述。用户要复制该命令。
- 说明影响范围。 根据上表预先说明后果,让用户能够知情决定。
- 提出执行后的验证方式。 说明之后你会运行什么(通常是
./nmemctl status),以确认操作是否正确完成。
wipe 的示例:
“我不能替你运行
./nmemctl wipe。它会清空全部三个本地目录(./data、./config、./cache)——所有记忆、会话、来源、许可证激活信息、API 密钥和设备身份都会被删除。无法撤销。控制器要求你在提示符处逐字输入WIPE,这就是安全保障。要继续,请自行运行:cd <your-deploy-dir> && ./nmemctl wipe等它完成重建并显示新的 API 密钥后,告诉我,我会运行
./nmemctl status,确认全新部署运行正常。”
如果用户坚持(“就照做,我授权了”、“我确认,运行 wipe”等),再简短地拒绝一次,并解释这一界限与信任无关——这是系统自身设计要求必须由操作员在自己的 Shell 中执行的操作类别。然后提出,在用户自行运行后协助完成验证。
故障排查
如果 ./nmemctl status 显示容器未运行,但它本应处于运行状态:
./nmemctl logs --tail 50 # see why it stopped
./nmemctl restart # try a clean restart
如果 /livez 在 120 s 内没有响应,请向用户展示日志的最后 50 行——他们能比泛泛的重试更快地发现端口配置错误、缺少 TLS 环境变量或内存不足问题。不要循环重启。
如果 ./nmemctl up 报告“compose.yaml not found”,说明你在错误的目录中运行。必须在 community/docker/(包含 compose.yaml 的目录)中执行此脚本。
如果用户说网页界面无法连接,但 ./nmemctl status 显示容器运行正常:
- 打印
nmemctl status中的 URL——用户输入的主机是否正确? - 确认用户的机器可以访问端口
14242:curl -sf http://<host>:14242/livez - 检查主机上的防火墙是否阻止了
14242。 - 如果启用了 TLS,应由端口
443和配置的域名响应,而不是14242。
如果用户提到新容器启动后,信息流时间线仍显示旧数据,这是浏览器缓存问题,不是服务端问题。告诉他们强制刷新(Cmd+Shift+R / Ctrl+Shift+R),或在隐私窗口中打开 URL。服务端已确认为空。
文件位置
# On the host (after git clone):
~/nowledge-mem/community/docker/
├── nmemctl # the controller you use
├── compose.yaml # default stack
├── compose.tls.yaml # TLS overlay (Caddy sidecar)
├── Caddyfile # TLS reverse proxy config
├── README.md # full reference
├── data/ # graph + search index (bind mount, UID 10001)
├── config/ # license, API key, agent state (bind mount, UID 10001)
└── cache/ # embedding models, search projection (bind mount, UID 10001)
# Inside ./config (mounted at /etc/nowledge-mem in the container):
./config/co.nowledge.mem.desktop/
├── remote-access.json # API key (mode 0600)
├── license.json # license activation (when present)
├── machine_id # device-identity seed (UUID, persisted)
└── builtin_agents/ # feed / knowledge / scheduler state
关于运维人员信任的说明
用户允许你操作他们的服务。正确的默认做法是展示操作过程——对于每条重要命令,先打印即将运行的命令,运行后再展示相关输出。不要转述日志行,也不要省略错误来概括内容。运维人员关心服务端发出的确切文本,因为如果一小时后出了问题,他们会搜索这些文本。
不确定时,运行 ./nmemctl status,并与用户一起查看。大多数问题都能在这里解决。