基于Tailscale构建自托管本地Markdown查看器,安全访问OpenClaw智能体日志
1. 项目概述与核心价值
如果你和我一样,深度使用 OpenClaw 这类本地优先的 AI 智能体框架,那你一定对那个不断膨胀的.openclaw目录又爱又恨。爱的是,它忠实地记录了所有智能体的思考过程、记忆日志、项目蓝图和配置文档,是数字大脑的“黑匣子”;恨的是,当你想在沙发上用手机快速回顾某个项目的决策过程,或者查看昨天智能体生成的代码草稿时,面对这个充满.md文件的本地目录,你只能望洋兴叹。把文件传到云端?这违背了本地优先、隐私至上的初衷。用 SSH 连回电脑在终端里cat?体验太差,而且对移动设备极不友好。bowen0110/openclaw-viewer就是为了解决这个“最后一公里”的痛点而生的:一个极简、自托管、专为手机浏览优化的本地文件查看器。
它的核心设计哲学非常明确:你的文件,只留在你的设备上。它不进行任何同步,不依赖任何云存储,不引入第三方服务。它仅仅是一个运行在你主机上的、内存占用极小的 Node.js 服务器,然后通过Tailscale构建的安全虚拟局域网,让你可以从任何联网的设备(尤其是手机)上,像浏览一个优雅的文档网站一样,访问你本地的.openclaw目录。无论是智能体的每日记忆日志(memory/)、战争室产出的架构图说明(war_rooms/),还是各个智能体的灵魂文件SOUL.md,你都可以在一个响应式、暗色主题的界面中轻松查阅。对于任何重视工作流隐私、追求效率,并希望将 AI 智能体产出深度融入日常的开发者或研究者来说,这个工具都是一个不可或缺的“连接器”。
2. 核心设计思路与架构解析
2.1 为什么是“本地优先”与“自托管”?
在 AI 智能体工作流中,数据隐私和所有权是首要考量。OpenClaw 等框架将一切数据保存在本地,就是为了避免敏感的项目思路、未成形的创意或内部决策日志泄露到第三方服务器。因此,一个配套的查看工具必须继承这一原则。openclaw-viewer 选择自托管,意味着数据流完全可控:你的 Markdown 文件从本地磁盘被读取,在本地内存中被渲染成 HTML,再通过本地网络接口提供服务。整个生命周期中,文件字节从未离开你的物理设备或你完全掌控的 Tailscale 虚拟网络。这与将目录推送到 GitHub Gist、Notion 或任何云笔记形成了鲜明对比,后者总会引入数据托管和隐私政策的顾虑。
2.2 网络访问安全基石:Tailscale 的妙用
让本地服务能被外网安全访问,传统方案涉及端口转发、DDNS 和 SSL 证书,复杂且有安全风险。openclaw-viewer 巧妙地利用了Tailscale。Tailscale 基于 WireGuard,在你的所有设备间建立一个加密的 mesh VPN(他们称之为 tailnet)。一旦你的手机和电脑都登录了同一个 Tailscale 账户,它们就仿佛处于同一个安全的内部局域网,即使两者都在不同的公共 Wi-Fi 或蜂窝网络下。
注意:使用 Tailscale 是该项目安全模型的核心。它替代了复杂的防火墙规则和暴露公网 IP 的风险。请确保你理解并正确配置了 Tailscale,这是服务能从手机访问的前提。
这样一来,查看器服务只需绑定到localhost:3500,但在 Tailscale 网络内,你可以通过电脑的 Tailscale 内网 IP 或主机名(如your-computer.tailnet-name.ts.net:3500)直接访问。所有通信都是端到端加密的,无需配置 HTTPS(虽然 Tailscale 流量本身是加密的,但服务本身是 HTTP,在 tailnet 内是安全的)。
2.3 技术栈选型:轻量、专注与安全
项目技术栈的选择体现了“做一件事并做好”的理念:
- Express: 轻量级 Node.js Web 框架,足以处理文件浏览、读取和搜索的 API 需求。
- Marked: 高性能的 Markdown 解析器,将
.md文件快速转换为 HTML。 - highlight.js: 为 Markdown 中的代码块提供客户端语法高亮,提升代码阅读体验。
- DOMPurify: 关键的安全组件。在将 Markdown 渲染后的 HTML 发送到客户端前,进行严格的净化(Sanitization),防止潜在的 XSS 攻击。即使你无意中打开了一个包含恶意脚本的 Markdown 文件,它也能被有效过滤。
整个应用没有前端构建步骤(No Build Step),这意味着部署就是简单的node server.js。服务器内存占用约 33MB,几乎可以忽略不计,非常适合常驻后台运行。
3. 详细部署与配置指南
3.1 基础环境准备与快速启动
部署前,请确保完成以下两步:
- 安装 Node.js 18+: 这是运行服务器的唯一硬性依赖。建议通过 nvm 管理 Node.js 版本,方便切换。
- 安装并配置 Tailscale:
- 在作为服务器的主机(你的开发机或常开电脑)上,安装 Tailscale 并登录。
- 在你的手机(iOS/Android)上,同样安装 Tailscale 应用,并使用同一账户登录。
- 确保两台设备在 Tailscale 管理后台(https://login.tailscale.com/admin/machines)都显示为 “Online” 状态。
完成上述准备后,部署查看器本身非常简单:
# 克隆仓库 git clone https://github.com/bowen0110/openclaw-viewer.git cd openclaw-viewer # 安装依赖 npm install # 启动服务器(默认使用当前目录的上一级作为根目录) npm start启动后,控制台会显示Server running on http://localhost:3500。此时,在你的电脑浏览器访问这个地址,就能看到查看器的界面。
3.2 关键配置项详解
项目通过环境变量进行配置,灵活且易于集成到各种部署环境中。
| 环境变量 | 默认值 | 说明与实操建议 |
|---|---|---|
PORT | 3500 | 服务器监听的端口。如果 3500 被占用,可以修改为其他端口,如8080。 |
WORKSPACE_ROOT | server.js所在目录的父目录 | 这是最重要的配置。它指定了服务器可以浏览的文件系统的根路径。必须将其设置为你的.openclaw目录的父目录,或者直接指向.openclaw目录本身。 |
如何正确设置WORKSPACE_ROOT:
假设你的.openclaw目录路径是/Users/yourname/.openclaw。
- 方法一(推荐): 在启动命令前设置环境变量。
WORKSPACE_ROOT=/Users/yourname/.openclaw npm start - 方法二: 创建
.env文件(项目根目录下)。
然后修改PORT=3500 WORKSPACE_ROOT=/Users/yourname/.openclawpackage.json中的start脚本,引入dotenv包来读取.env文件,或者使用npm命令npm run start:env并配置对应脚本。
实操心得:我强烈建议将
WORKSPACE_ROOT明确设置为.openclaw的绝对路径。使用默认值(父目录)可能会意外暴露你不想共享的其他目录。安全第一。
3.3 从手机访问服务
这是体现项目价值的时刻。在电脑上启动服务后,你需要找到电脑在 Tailscale 网络中的地址。
在电脑终端执行:
tailscale status你会看到类似输出:
100.xx.xx.xx your-computer-name your-email@example.com linux -或者更友好的主机名:
your-computer-name.tailnet-name.ts.net。在手机的 Tailscale App 中,确保状态为“已连接”。
打开手机浏览器,输入地址:
http://your-computer-name.tailnet-name.ts.net:3500。你应该能看到和电脑浏览器里一样的文件浏览界面。大功告成!
常见问题排查:如果手机无法访问,请依次检查:① 电脑防火墙是否允许了 3500 端口的入站连接(在 Tailscale 网络内,通常不需要额外设置);② 启动服务时是否指定了正确的
PORT;③ 手机 Tailscale 是否与电脑在同一 tailnet 中且在线。
4. 生产级持久化运行方案
我们不可能每次想用的时候都手动去启动服务。下面详细介绍如何在不同操作系统下将其设置为后台服务,实现开机自启、故障自动重启。
4.1 Linux / WSL2 方案(使用 systemd,推荐)
这是最健壮、管理最方便的方案。systemd 提供了完善的进程监控、日志收集和资源限制功能。
步骤一:创建 systemd 用户服务文件
将以下内容中的/path/to/替换为你的实际路径。
/path/to/openclaw-viewer: 项目克隆的目录。/path/to/your/.openclaw: 你的.openclaw目录绝对路径。
mkdir -p ~/.config/systemd/user cat > ~/.config/systemd/user/openclaw-viewer.service << EOF [Unit] Description=OpenClaw Viewer Service After=network.target tailscale.service Wants=tailscale.service StartLimitIntervalSec=300 StartLimitBurst=5 [Service] Type=simple User=$USER WorkingDirectory=/path/to/openclaw-viewer Environment=PATH=/usr/bin:/usr/local/bin Environment=NODE_ENV=production Environment=PORT=3500 Environment=WORKSPACE_ROOT=/path/to/your/.openclaw ExecStart=/usr/bin/node /path/to/openclaw-viewer/server.js Restart=on-failure RestartSec=10 # 资源限制 MemoryMax=256M CPUQuota=100% TimeoutStartSec=15 WatchdogSec=120 # 日志重定向 StandardOutput=journal StandardError=journal [Install] WantedBy=default.target EOF关键配置解析:
After=tailscale.service: 确保服务在 Tailscale 网络就绪后才启动,避免网络不可用。StartLimitIntervalSec和StartLimitBurst: 在 300 秒内最多重启 5 次,超过则永久停止,防止崩溃循环。MemoryMax=256M: 限制最大内存,防止内存泄漏导致系统问题。WatchdogSec=120: systemd 会监控服务,如果 120 秒内没有收到“心跳”(需要服务支持 watchdog,这里更多是进程存活监控),会认为服务僵死并重启。
步骤二:启用并启动服务
# 重新加载 systemd 配置 systemctl --user daemon-reload # 启用开机自启 systemctl --user enable openclaw-viewer.service # 立即启动服务 systemctl --user start openclaw-viewer.service步骤三:允许用户服务在用户注销后继续运行
默认情况下,用户服务会在用户退出登录时停止。我们需要启用“linger”功能。
loginctl enable-linger $USER步骤四:管理服务
# 查看服务状态 systemctl --user status openclaw-viewer.service # 查看实时日志 journalctl --user -u openclaw-viewer.service -f # 重启服务 systemctl --user restart openclaw-viewer.service # 停止服务 systemctl --user stop openclaw-viewer.service4.2 macOS 方案(使用 launchd)
macOS 使用launchd作为初始化系统。我们需要创建一个plist文件。
创建服务描述文件:
cat > ~/Library/LaunchAgents/com.user.openclawviewer.plist << EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.user.openclawviewer</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/node</string> <string>/path/to/openclaw-viewer/server.js</string> </array> <key>EnvironmentVariables</key> <dict> <key>PORT</key> <string>3500</string> <key>WORKSPACE_ROOT</key> <string>/path/to/your/.openclaw</string> </dict> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <dict> <key>SuccessfulExit</key> <false/> </dict> <key>StandardOutPath</key> <string>/tmp/openclaw-viewer.log</string> <key>StandardErrorPath</key> <string>/tmp/openclaw-viewer.log</string> <key>WorkingDirectory</key> <string>/path/to/openclaw-viewer</string> </dict> </plist> EOF注意:请确保
/usr/local/bin/node是你的 Node.js 正确路径,可以使用which node命令查看。加载并启动服务:
launchctl load ~/Library/LaunchAgents/com.user.openclawviewer.plist launchctl start com.user.openclawviewer查看日志:
tail -f /tmp/openclaw-viewer.log
4.3 Windows 方案(使用 PM2,跨平台推荐)
对于 Windows,我推荐使用PM2,这是一个功能强大的 Node.js 进程管理器,比 Windows 任务计划程序更易于管理。
全局安装 PM2:
npm install -g pm2在项目目录下启动服务并设置环境变量:
# 进入项目目录 cd C:\path\to\openclaw-viewer # 用 PM2 启动进程,并命名 pm2 start server.js --name "openclaw-viewer" --env PORT=3500 --env WORKSPACE_ROOT="C:\Users\YourName\.openclaw" # 保存当前进程列表 pm2 save # 生成开机自启动脚本(会给出需要以管理员权限运行的命令) pm2 startup执行
pm2 startup后,它会输出一条命令(如pm2 startup针对特定系统的命令),你需要以管理员身份打开 PowerShell 或 CMD,执行那条命令。常用 PM2 命令:
pm2 status # 查看所有进程状态 pm2 logs openclaw-viewer # 查看该服务的实时日志 pm2 restart openclaw-viewer # 重启服务 pm2 stop openclaw-viewer # 停止服务 pm2 delete openclaw-viewer # 删除服务
5. 功能深度使用与技巧
5.1 两种视图模式与高效浏览
打开查看器,你会看到两种主要的视图:
- 列表视图:传统的文件列表,清晰展示当前目录下的文件和文件夹。
- 树状视图:点击左上角的切换按钮,可以展开一个侧边栏式的完整目录树。这个视图对于快速跳转到深层嵌套的目录特别有用,尤其是在手机上,避免了多次点击返回。
实操技巧:你的视图偏好(列表或树状)会被保存在浏览器的localStorage中。下次访问同一设备时,会自动恢复你喜欢的模式。
5.2 文件搜索与快速定位
顶部有一个搜索框。它执行的是文件名搜索,而非文件内容搜索。输入关键词后,它会实时在所有目录中匹配包含该关键词的.md文件名,并显示最多 30 个结果。
注意:目前搜索是大小写敏感的,且只针对 Markdown 文件。如果你需要全文搜索,可以考虑将
.openclaw目录用 Obsidian 打开,并利用其强大的搜索功能,但那就失去了手机便捷浏览和本地优先的纯粹性。这个查看器的搜索定位是“快速找到已知文件”。
5.3 阅读体验优化:暗色主题与代码高亮
界面采用 GitHub Dark 风格的暗色主题,长时间阅读不伤眼。对于 Markdown 中的代码块,前端通过highlight.js自动检测语言并进行语法高亮,这使得阅读智能体生成的代码片段、配置示例或日志中的数据结构变得非常舒适。
5.4 导航与历史记录
- 面包屑导航:页面顶部的路径导航栏(面包屑)清晰显示了你的当前位置。你可以点击路径中的任何一级,快速跳转回上层目录。
- 浏览器历史:应用完全支持浏览器的前进和后退按钮。你可以像浏览普通网页一样,在查看过的文件和目录间来回切换,交互非常自然。
6. 安全考量与最佳实践
6.1 内置安全机制
- 路径遍历防护:服务器代码会严格校验请求的文件路径,防止用户通过构造类似
../../../etc/passwd的路径来访问系统敏感文件。这是通过path.relative和path.resolve函数确保请求路径不会逃逸出WORKSPACE_ROOT目录来实现的。 - HTML 净化:使用
DOMPurify对 Markdown 渲染后的 HTML 进行消毒,移除所有可能执行的脚本(<script>)、事件处理器(如onclick)等危险元素,从根本上杜绝了通过 Markdown 文件进行 XSS 攻击的可能。 - Tailscale 网络隔离:服务本身只监听
localhost。通过 Tailscale 访问,相当于在一个加密的私有局域网内访问,服务本身无需暴露在公网,极大减少了攻击面。
6.2 增强安全的最佳实践
尽管项目本身很安全,但遵循以下原则能让你的部署更稳固:
- 最小权限原则:运行 Node.js 服务的系统用户,不应该有超出
WORKSPACE_ROOT目录的读写权限。在 Linux 上,可以考虑创建一个专用用户来运行此服务。 - 定期更新:关注项目 GitHub 仓库的更新,及时拉取安全补丁或功能改进。
- 审计日志:虽然查看器本身不记录访问日志,但你可以通过系统的日志工具(如
journalctl查看 systemd 服务的输出)来监控服务的运行状态。对于更高级的需求,可以考虑在 Express 服务器前加一个 Nginx 反向代理来记录访问日志。 - 谨慎设置
WORKSPACE_ROOT:再次强调,不要将其设置为/或你的家目录。精确指向你需要共享的目录。
7. 扩展用途:不止于 OpenClaw
这个查看器的本质是一个通用的本地 Markdown 文件树服务器。虽然它因 OpenClaw 而生,但其应用场景可以非常广泛:
- Obsidian 库手机查看器:将
WORKSPACE_ROOT指向你的 Obsidian 仓库目录,就可以在手机上优雅地浏览你的笔记库。这对于快速查阅(而非编辑)特别方便。 - 文档项目预览:如果你在本地编写项目文档(如
docs/目录),可以用它来在局域网内预览效果,比启动完整的文档服务器更轻量。 - 个人知识库:管理你的 Zettelkasten(卡片盒笔记法)文件夹,实现跨设备阅读。
- 团队内部文档共享(小范围):如果团队成员都加入了同一个 Tailscale 网络,你可以将此服务运行在一台内部服务器上,作为轻量级的内部文档站点。
它的简洁性和隐私性,使其成为任何需要安全、便捷地跨设备访问本地文本文件场景的绝佳解决方案。
8. 故障排除与常见问题
Q1: 服务启动成功,但手机访问时显示“无法连接”或“拒绝连接”。A1: 这是最常见的问题。请按顺序排查: 1.确认 Tailscale 连接:在手机和电脑上分别打开 Tailscale App,确认两者都显示为“Connected”(绿色)。尝试在手机 Tailscale App 内 ping 一下电脑的主机名或 IP。 2.确认服务端口:在电脑上运行netstat -an | grep 3500(Linux/macOS)或Get-NetTCPConnection -LocalPort 3500(Windows PowerShell),查看是否有进程在监听0.0.0.0:3500或:::3500。如果只看到127.0.0.1:3500,可能需要检查服务绑定地址的代码(本项目默认应绑定0.0.0.0)。 3.检查防火墙:临时关闭电脑的防火墙进行测试。如果关闭后能访问,则需要在防火墙规则中允许 3500 端口的入站连接(TCP)。
Q2: 树状视图或文件列表加载很慢。A2: 如果你的.openclaw目录非常大(例如包含数万个文件),首次加载树状视图(/api/tree)可能会较慢,因为需要递归扫描所有目录。这是预期行为。建议: - 使用搜索功能直接定位文件,避免浏览超大目录。 - 考虑是否真的需要将所有历史文件都放在活动目录中,可以定期归档旧的日志和输出。
Q3: 某些 Markdown 文件渲染格式错乱。A3: 这通常是由于 Markdown 内容包含非标准语法或复杂的 HTML 片段,与marked解析器的配置或DOMPurify的过滤规则有关。可以尝试: - 查看浏览器开发者控制台(Console)是否有 JS 错误。 - 对比在 Obsidian 或 VS Code 中的预览效果。如果只是简单的换行或列表问题,可能是原文件格式不够规范。
Q4: 如何修改界面样式或主题?A4: 项目的前端资源(CSS、JS)是静态的。你可以直接修改项目public/目录下的style.css文件来自定义颜色、字体或布局。修改后需要重启 Node.js 服务生效。这是一个轻量级项目,自定义起来相对简单。
Q5: 能否支持图片预览或 PDF 查看?A5: 当前版本的核心定位是 Markdown 文本查看器,不支持内联图片预览或其他文件格式的直接渲染。对于图片,Markdown 中的![]()语法会渲染成一个可点击的图片链接,点击后浏览器会尝试下载或打开图片文件(取决于手机浏览器的设置)。更复杂的文件预览属于功能扩展范畴,如果需要,可以 fork 项目自行开发。
