OpenClaw 最近确实火得不行,我身边好几个圈子都在聊它,GitHub 上的 star 涨得飞快,各种“AI Agent 自主干活”的演示视频看得人热血沸腾。我自己也跟进部署过几轮,从 Ubuntu 到 Docker,从接模型到接 Teams、Obsidian,前前后后折腾了不少时间。但在这过程中我发现一个非常普遍的问题:很多人的 OpenClaw 部署完之后,其实是处于一种“裸奔”状态——服务直接暴露在公网、API Key 明文躺在配置文件里、Agent 的权限边界完全没有收敛。换句话说,大家把精力花在了“怎么跑起来”,却几乎没有花在“怎么安全地跑”上。
这篇文章不聊那些花里胡哨的功能演示,我就想把部署 OpenClaw 时最容易忽略的安全坑一个个翻出来,讲清楚为什么默认部署不安全,以及怎么一步步把它“穿上衣服”。内容会覆盖部署形态选型、密钥管理、端口收敛、认证配置、权限沙箱这些实操环节,也整理了我在实际部署中遇到过的典型报错和排查思路。不管你是刚接触 Agent 的新手,还是已经部署完正准备深度使用的开发者,这篇文章应该都能帮你少走不少弯路。
1. OpenClaw 为什么会“裸奔”:部署现状与风险画像
1.1 “裸奔”的三种典型姿态
先说个类比。OpenClaw 这类 AI Agent 就像一辆动力很强的车,你把它开回家、停好车,这本身没毛病。但如果你停完车不锁车门、不关车窗,甚至把钥匙留在座位上,那后面发生什么就只能看运气了。我在帮朋友排查部署问题时,发现大多数 OpenClaw 实例至少存在下面三种“不锁车门”的行为。
第一种是端口暴露。很多人图方便,部署时直接让服务监听所有网络接口,也就是俗称的0.0.0.0。如果这台机器又恰好有公网 IP,或者跑在云服务器上,那你的 OpenClaw 接口就等于向整个互联网敞开。更麻烦的是,OpenClaw 这类 Agent 框架往往自带控制接口或管理面板,一旦可以被外部访问,别人就能直接调用你的 Agent 能力,让它去读文件、发消息、调工具。
第二种是密钥明文落盘。模型 API Key、数据库密码、Webhook 签名密钥、OAuth Token,这些东西如果直接写在配置文件里,而且文件的权限还是默认的644(所有用户可读),那一旦服务器上有其他低权限进程被攻破,或者你的配置目录被扫描到,密钥就会批量泄露。密钥泄露意味着别人可以用你的账号调用模型服务,烧的是你的钱,留下的是你的账单。
第三种是权限边界缺失。Agent 的能力本质上就是“调用工具”,而很多人在部署时把能开的工具全开了:文件读写、浏览器操作、命令执行、网络请求,统统授权。好处是 Agent 确实“什么都能干”,坏处是如果它的会话被劫持或者提示词被注入,损失范围也变成了“什么都可能丢”。我在实际使用中见过不少朋友把 Agent 的工作目录直接指向~,它想读哪个文件就读哪个文件,这种权限放得太宽了。
1.2 威胁模型:到底谁在盯着你的 Agent
讲风险不能只凭感觉,得有一个清晰的威胁模型。针对 OpenClaw 这类自部署 Agent,主要的威胁来源其实是四类。
第一类是互联网扫描器。这些自动化脚本全天候扫描公网 IP 的常见端口。它们不针对你个人,但只要你把端口暴露在公网,被扫到只是时间问题。扫描器发现 OpenClaw 的端口后,会尝试默认口令、目录遍历、版本探测,一旦发现漏洞就会自动利用。
第二类是恶意 MCP 服务器。MCP 是 Agent 连接外部工具的标准协议,OpenClaw 支持配置各种 MCP 服务器来扩展能力,比如连接文件系统、数据库、网页浏览器等。但如果你从不可信的来源直接加载了恶意 MCP 服务,你的 Agent 就等于把“手”伸进了一个不信任的黑盒里,对方可以让你的 Agent 执行任意操作。
第三类是共驻进程攻击。如果 OpenClaw 所在的主机上还跑了其他服务,比如一个 WordPress 站点或者某个存在漏洞的 Web 应用,攻击者先拿下那个服务,再横向移动,利用权限过大的配置文件和进程拿到 Agent 的控制权。这属于连锁攻击,很多人没想过。
第四类是供应链风险。OpenClaw 依赖大量 npm、pip、Docker 镜像等第三方组件,这些依赖如果被投毒,你拉取、安装的那一刻就已经中招了。这也是我在后面会专门强调锁版本、验镜像的原因。
1.3 默认部署为什么不安全
很多人的误区是“本地部署 = 安全”,以为只要服务跑在自己服务器上就万事大吉。但安全问题的核心从来不是“谁在跑”,而是“谁能访问到它”。OpenClaw 这类项目本身的定位是“本地优先”的自主 Agent,它的设计重心是把功能做得强大好用,而不是默认把安全配置拉满。原因也很简单:安全配置一旦拉满,易用性就会直线下降,新手连跑起来都费劲。
举个最直观的例子:如果你部署 OpenClaw 是为了让它调用本地的 Obsidian 笔记库、管理本地文件,那它天然就需要读你文件系统的权限。项目没法替你判断哪些文件是敏感的,只能默认全都给你读。同理,模型 API Key 是你自己配置的,项目也不可能替你加密保管。所以“裸奔”的责任不在项目本身,而在部署者没有主动补齐安全配置。理解了这一点,后面的加固思路就顺了:凡是默认配置和安全冲突的地方,都要自己操刀解决。
2. 部署前的安全基线:先把暴露面想清楚
2.1 部署形态选型与暴露面对照
我见过有人为了“随时访问”OpenClaw,直接把它部署在一台有公网 IP 的云服务器上,然后把端口完全开放。部署形态本身没有绝对的好坏,但不同形态对应的安全投入完全不同。
| 部署形态 | 默认暴露面 | 需要的安全措施 |
|---|---|---|
| 本机部署(仅回环) | 最小,仅本机可访问 | 配置密钥权限、Agent 权限收敛 |
| 局域网部署 | 中等,同网段设备可访问 | 防火墙限制来源 IP、启用认证 |
| 云服务器公网部署 | 最大,整个互联网可访问 | 反向代理 + HTTPS + 强制认证 + 端口收敛 |
| Docker 容器部署 | 取决于端口映射方式 | 按需映射端口、最小化容器权限 |
如果你只是自己调试、自己用,最稳妥的方案是让 OpenClaw 只绑定本机地址127.0.0.1,通过 SSH 隧道或者内网环境来访问。如果确实需要远程访问,那必须先经过一层带认证的反向代理,而不是把原始端口暴露出去。
对于 Docker 部署,还有一个容易被忽略的点:-p 3000:3000会把容器的 3000 端口映射到宿主的0.0.0.0上,这种写法最危险。更安全的写法是-p 127.0.0.1:3000:3000,这样只有宿主机自己能访问,外部网络无法直连容器端口。
2.2 API 密钥与配置文件的保管方案
OpenClaw 连接模型服务需要各种 API Key,这些密钥是部署安全的第一道关卡。先说结论:不要把密钥直接写在项目源码里,不要提交进 Git 仓库,不要用root权限去运行能读到密钥的服务。
推荐的做法是使用环境变量来传递密钥,OpenClaw 的部署文档里也支持从环境变量读取配置。在systemd服务里可以写一个独立的EnvironmentFile,在 Docker 部署时可以配合env_file或--env参数。无论哪种方式,存放密钥的文件权限都要设置成600,也就是只有属主可读写。
这里我多说一句:很多教程会教你“把环境变量写进.env文件”,但.env文件同样需要保护。.env文件不要放在 Web 根目录下,不要被docker-compose.yml所在的目录默认共享出去,同时要在.gitignore里把这个文件排除掉。我见过有人把.env直接提交到 GitHub 仓库,几分钟之内就被爬虫抓取,模型 API Key 被人拿去刷了一晚上的对话额度,账单感人。
2.3 Agent 权限边界的设计原则
Agent 权限边界,是“裸奔”问题里最容易被忽略、也是出事之后影响最大的一项。在把 OpenClaw 接入任何工具之前,先列一张清单:这个 Agent 到底需要访问哪些资源?它需要读哪些目录、写哪些目录?它需要调用哪些网络接口?它需要执行哪些命令?
我把这个思路叫“最小工具集原则”:只给 Agent 完成当前任务必需的工具,不要让它拥有“全量工具”。
- 文件系统类 MCP:限制工作目录,只允许访问指定的目录,例如
/data/workspace,而不是整个用户目录。 - 浏览器类工具:如果需要操控网页,尽量使用独立的浏览器配置文件,不要直接读取你常用浏览器里的 Cookie 和登录态。
- 命令执行类工具:这是风险最高的能力。如果业务上确实需要,务必通过子进程隔离、资源限额、超时控制来约束,并且用独立低权限账号来运行。
- 网络请求类工具:注意目标域名白名单,防止 Agent 被诱导发起对任意地址的请求。
另外要重点检查 MCP 配置的来源。OpenClaw 的生态里有很多第三方的 MCP 服务器,安装前最好确认项目是否有足够的维护活跃度,代码是否有人审过,镜像是否来自官方源。这个行业里已经出现过伪装成“工具扩展”的恶意包,目标就是盗取运行环境中的密钥。
3. 安全部署实操:一步步把 OpenClaw“穿上衣服”
3.1 第一步:把网络端口收回来
不管你的 OpenClaw 是裸机部署还是 Docker 部署,第一步永远是先把网络暴露面收敛到最小。具体来说,确保服务只绑定在回环地址,或者只对可信来源开放。
如果使用 Docker 部署,docker-compose.yml里的端口映射可以写成这样:
services: openclaw: image: your-openclaw-image:tag ports: - "127.0.0.1:3000:3000" environment: - OPENCLAW_BIND_ADDR=127.0.0.1如果服务本身支持配置监听地址,建议同时设置监听地址为127.0.0.1,这样即便代码里的默认值被重新读出来,也不会直接绑到公网地址。这在 OpenClaw 的启动配置里通常是一个名为host或bind的选项,具体参数名以你的版本文档为准,但思路是一致的:绑定地址永远不要用0.0.0.0除非你明确知道自己在做什么。
如果是在 Linux 裸机上部署,配置本地防火墙是第二道保险。以ufw为例:
# 先拒绝所有入站,再放行 SSH 和回环 sudo ufw default deny incoming sudo ufw allow from 127.0.0.1 sudo ufw allow ssh sudo ufw enable对于已经跑在云服务器上的 OpenClaw,需要在云控制台的安全组里同样配置:只放行你需要管理服务的来源 IP 段,不要配0.0.0.0/0。安全组规则和系统防火墙要同时配置,任何一层漏了都可能导致意外暴露。
有人可能会问:那我本机部署是不是不用管防火墙?其实也要管。本机部署虽然外部网络访问不到,但如果你同时运行着其他服务,这些服务之间可能存在跳板。一个典型的场景:你的主机上运行着一个暴露在公网的 Nginx,Nginx 配了反向代理把请求转发到本机的 OpenClaw 端口,那这个端口实际上还是通过代理暴露了出去。所以检查时要连带看一眼有没有其他服务在转发流量。
3.2 第二步:加上身份认证与会话保护
端口收到回环之后,OpenClaw 默认是“只要能在本机访问到,谁都能用”的状态。如果你的机器上还有其他用户,或者你通过 SSH 隧道把端口转发了出去,那访问端口的任何人其实都能直接操作 Agent。所以第二步是给服务本身加上身份认证。
OpenClaw 这类 Agent 框架通常会在配置里支持设置访问令牌或者启用认证插件。我在实际部署中遇到过几种做法,按推荐程度排序:
第一是启用内置的访问令牌认证。在启动配置里设置一个足够长的随机 Token(至少 32 位,建议用openssl rand -hex 32生成),然后在客户端请求的 Header 中带上Authorization: Bearer <token>。这个方案的优点是简单、不引入额外组件,缺点是只能提供单一的共享凭据,没法做到用户级别的权限区分,适合个人使用。
第二是用反向代理做一层 Basic Auth 或 OAuth2 Proxy。如果你通过域名访问 OpenClaw,我强烈建议在前面加一层 Nginx 或者 Caddy,由反向代理来终结 TLS 并处理认证。Caddy 可以自动申请证书,配置一个简单的密码认证也很快:
your-domain.example.com { reverse_proxy 127.0.0.1:3000 basicauth { user $2a$14$xxxxxxxxxxxxxxx } }这样做的好处是 OpenClaw 本身不用管认证逻辑,反向代理挡住所有未认证请求,TLS 加密也一并解决。这是我目前最推荐的方式,适合那些需要从外部设备访问 OpenClaw 的场景。
第三是结合已有的 OAuth 体系。如果你所在的组织里已经有一套 SSO 或者 OAuth2 服务,可以通过oauth2-proxy这类组件把认证接到现有体系上。这个配置稍微复杂一点,但好处是能做到用户级别审计,适合团队共同使用一台部署实例的场景。
另外,部署时还要注意会话文件的问题。OpenClaw 的会话数据通常会写入本地文件,如果多个客户端同时操作同一个会话,就可能会出现“session file locked”的报错。这不仅是体验问题,也和安全有关——会话文件里往往包含你与 Agent 之间的对话记录,这些文件默认权限如果过宽,别人也能读到。建议将会话目录放在仅服务运行用户可读写的路径下。
3.3 第三步:密钥与配置文件的落地加密
前面说过密钥不能明文写在配置文件里,但更推荐的实践是把密钥和配置交给专门的密钥管理工具。这里分几个层次来落地。
最基础的操作是修改文件权限。在 Linux 中,存放密钥的.env文件必须设置成只有属主可读写:
chmod 600 ~/.openclaw/.env chown openclaw-user:openclaw-user ~/.openclaw/.env然后在启动服务时通过EnvironmentFile或者docker-compose的env_file读入这些变量。这样做的一个额外好处是,即使有人拿到了进程的命令行参数列表,也看不到密钥内容,因为它没有出现在启动命令里。
如果使用 Docker 部署,容器内的环境变量可以通过docker inspect看到明文,所以更安全的做法是使用 Docker Secret。把密钥写入 Secret 文件,然后在docker-compose里以 Secret 方式挂载进容器:
services: openclaw: image: your-openclaw-image:tag secrets: - api_key secrets: api_key: file: ./secrets/api_key.txt应用代码从/run/secrets/api_key读取密钥,避免明文出现在环境变量或镜像层中。对于个人项目来说这可能有点“过重”,但如果你部署 OpenClaw 的服务器上还跑着其他服务,密钥管理规范一些,总比哪天真被拖库了才后悔要好。
还有一个很容易忽视的点:配置备份文件。很多人喜欢把整个配置目录打包传到网盘或者 GitHub 私有仓库,结果配置目录里不仅有config,还有.env、session数据、日志文件,等于把密钥和对话历史一起打包泄露了。我这里建议备份时只备份不含密钥的配置文件,密钥单独用密码管理器保存。如果你确实需要备份.env,务必先加密,例如用gpg对称加密后再上传。
3.4 第四步:限制运行权限与文件系统访问
整个加固流程走到这里,OpenClaw 已经不再是“能直连、能白嫖、能偷密钥”的状态了,但最后一步同样关键:限制 Agent 进程本身的系统权限。
先说裸机部署。很多人喜欢用root跑 OpenClaw,理由是“省事、不用处理权限问题”。但 Agent 一旦具备root权限,它读任何文件、杀任何进程、改任何系统配置都是合法的,如果 Agent 被恶意 MCP 或提示词注入利用,破坏力直接拉满。正确做法是创建一个专用低权限用户:
sudo useradd --system --create-home --shell /usr/sbin/nologin openclaw sudo chown -R openclaw:openclaw /opt/openclaw然后用systemd启动服务,指定运行用户:
[Service] User=openclaw Group=openclaw WorkingDirectory=/opt/openclaw EnvironmentFile=/opt/openclaw/.env ExecStart=/usr/bin/node /opt/openclaw/dist/index.js Restart=on-failure容器部署同样有对应的最佳实践。在docker-compose.yml中,可以通过cap_drop移除容器内进程的能力,通过read_only将根文件系统设成只读:
services: openclaw: image: your-openclaw-image:tag user: "1000:1000" read_only: true cap_drop: - ALL cap_add: - NET_BIND_SERVICE volumes: - openclaw-data:/data - workspace:/workspace这里解释一下这样做的逻辑:cap_drop: ALL表示容器里的进程不拥有任何 Linux 能力,不能去更改系统网络、加载内核模块之类;cap_add: NET_BIND_SERVICE则是允许它绑定 1024 以下的端口,当然如果你不用 80/443 端口,这一步也可以不加。read_only: true配合专门的volume存放数据,让 Agent 只能写它该写的目录,而不是在容器任意角落落盘。
文件系统访问限制方面,OpenClaw 配置里的工作目录也应该指定到一个专门目录,例如/data/workspace。如果 Agent 需要读写笔记库,你可以把笔记目录单独挂载进去,但主目录和/root、/home这种敏感路径不要让它看到。
4. 常见问题排查与加固清单实录
4.1 “session file locked”到底是什么问题
很多人在 OpenClaw 社区里遇到过一个报错:agent failed before reply: session file locked (timeout 60000ms)。字面意思是会话文件被锁,等待 60 秒超时。这个报错表面上看着像是“并发写文件”的性能问题,但我在排查过程中发现,它往往和你部署方式的安全配置也有关系。
最常见的原因是运行 OpenClaw 的用户没有足够权限操作会话目录,导致文件锁无法正常释放。比如你用root启动过服务,生成了root属主的会话文件,后来又改用普通用户重启服务,那普通用户去写这些文件时就会卡住,最终触发锁超时。解决方法是把整个数据目录的属主统一改成服务运行用户,并且清掉历史 session 文件:
# 备份旧会话数据后统一授权 sudo chown -R openclaw:openclaw /opt/openclaw/data sudo find /opt/openclaw/data -type f -exec chmod 600 {} \;第二种情况是多个 OpenClaw 进程同时操作同一个 session。比如你用systemd管理服务的同时,又手动执行了一次启动命令,结果两个进程抢同一个会话文件。这类问题排查起来需要先确认当前系统里到底跑着几个 OpenClaw 进程:
ps aux | grep -i openclaw systemctl status openclaw如果发现存在重复进程,先把手动启动的进程停掉,然后只保留systemd托管的那个。要避免这种问题,最稳的办法是给启动方式做唯一化:要么只用 Docker,要么只用 systemd,不要混着来。
还有第三种情况和存储介质有关。如果你的数据目录放在网络文件系统(如 NFS)上,文件锁机制在跨主机场景下会变得不可靠,会导致 session 锁迟迟不释放。所以尽量把 session 数据放在本地磁盘,不要用共享存储来跑这类高频读写的服务。
排查这类问题有一个通用思路:先看服务日志里锁文件的路径,再检查运行用户对该路径的读写权限,最后确认没有并发进程。绝大多数 session 锁问题都能用这三步解决。
4.2 端口暴露自查三板斧
部署完成后,很多人想知道自己的 OpenClaw 到底有没有暴露出去。我建议做一遍“端口暴露自查”,三个命令就能看个大概。
第一板斧,看监听地址。在 OpenClaw 所在机器上执行:
ss -tlnp | grep 3000如果输出里的地址是0.0.0.0:3000或者*:3000,说明服务监听在所有网卡上,需要按 3.1 节的思路改配置;如果是127.0.0.1:3000,说明只监听了本机回环地址,这一步是安全的。
第二板斧,看防火墙例外。执行:
sudo iptables -L -n | grep 3000 # 或者 sudo ufw status verbose看是否有针对 3000 端口或其他业务端口的放行规则。如果有ALLOW且来源是0.0.0.0/0,就说明防火墙层面没有拦截外部访问,需要立刻收紧。
第三板斧,做外部探测。如果你在云上,可以换一台机器去扫一下自己的公网 IP 端口:
nc -vz your-server-ip 3000如果提示open或者succeeded,说明公网层面确实能访问到这个端口,这是最高优先级的风险信号。如果你不确定自己有没有公网 IP,也可以通过在线端口扫描工具自查(注意选择可靠的服务)。这里特别提醒一句:关掉不需要的端口,比任何防火墙规则都管用。
4.3 加固清单速查表
为了方便你直接对照操作,我把前面提到的安全加固项整理成一张速查表。你可以按顺序逐项检查,也可以把它贴在自己的部署文档里长期维护:
| 检查项 | 合格标准 | 不合格时的风险 |
|---|---|---|
| 端口监听地址 | 仅127.0.0.1,未监听0.0.0.0 | 公网可直连服务,完全暴露 |
| 防火墙/安全组规则 | 仅放行可信来源 IP,不放行0.0.0.0/0 | 外部扫描可访问到端口 |
| API Key 存储位置 | 环境变量/Secret,文件权限 600 | 密钥泄露,服务被白嫖 |
| 密钥文件备份 | 加密后才进入网盘/Git 仓库 | 备份泄露连带密钥泄露 |
| 服务运行用户 | 非 root 专用用户 | 进程被攻击后权限过大 |
| 容器能力 | cap_drop: ALL,最小化能力 | 容器逃逸风险升高 |
| Agent 工作目录 | 限制在独立工作目录 | 敏感文件被任意读取 |
| MCP 工具配置 | 仅启用必要工具 | 恶意工具可执行任意操作 |
| 会话文件权限 | 仅服务用户可读写 | 对话内容被其他用户读取 |
| 依赖版本 | 锁定版本,定期更新 | 漏洞依赖被利用 |
4.4 我踩过的一些坑
整理这篇文章的时候,我把自己的部署记录翻了一遍,有几次印象特别深的翻车现场。
第一次是刚接触 OpenClaw 时,按照网上的教程用docker run -p 3000:3000跑在云服务器上,结果第二天发现日志里有人在反复探测端口。当时我还没意识到“端口映射到0.0.0.0”意味着什么,直到在服务访问日志里看到一个来自陌生 IP 的请求尝试调用模型接口,才惊出一身冷汗。后来我把端口改成映射到回环地址,并在云安全组加上了来源 IP 白名单,这个探测才慢慢消失。
第二次是帮一个朋友排查“OpenClaw 没反应”的问题,发现他居然用root跑服务,而且把整个家目录都设成了工作目录。他本意是方便 Agent 访问桌面文件,结果 Agent 确实什么都能读,包括浏览器保存的各种登录态 Cookie。虽然当时没有出事,但这个状态一旦被利用,后果不堪设想。我帮他改了配置,把工作目录限制到一个专门的workspace文件夹,并用独立用户运行,他后来反馈说 Agent 的日常使用几乎没有影响,反而很多无关的误触发少了很多。
第三次是关于 MCP 工具的。我一开始为了图方便,把所有能装的 MCP 服务器全装了一遍,结果 Agent 经常出现一些“出乎意料”的工具调用。后来我做了一次减法,只保留实际会用到的文件系统和浏览器工具,稳定性反而有明显的提升。这也验证了一个观点:工具越少越好管,权限越小越安全。
5. 写在最后的几点心得
部署 OpenClaw 这类 Agent 项目,真正考验人的不是“把它跑起来”,而是“能不能在复杂环境里控制住它的影响面”。我在实际操作中最大的感受是,安全加固这件事不需要一步到位,你可以先做最低成本的几项——把端口绑定到回环、把密钥文件权限改成 600、不要把.env提交到 Git——这三项大概十分钟就能完成,但已经把最常见的裸奔风险挡住了。之后再根据自己的使用场景决定要不要上反向代理、要不要做容器沙箱、要不要接更完整的认证体系。
还有一点想特别提醒:Agent 项目的特性决定了它会比其他 Web 服务更“敏感”,因为它不是在被动地等待请求,而是在主动地操作工具、读取文件、调用接口。你给它多少权限,它就能在多大范围内替你干活,同时也意味着别人一旦控制了它,就能在多大范围内搞破坏。所以部署之后每隔一段时间,我都会重新看一下配置:有没有新增的未认证接口、有没有多余的 MCP 工具、有没有哪个目录的权限被不小心放开。这个习惯养成之后,再复杂的 Agent 项目也能在心里有数地跑下去。
最后再分享一个小技巧:如果你用的是 Docker 部署 OpenClaw,建议每次启动前都执行一下docker compose config看看渲染出来的完整配置,确认环境变量里没有意外泄漏的密钥,端口映射没有被改成0.0.0.0。这一条命令花不了十秒,但对排查“自己是不是裸奔”非常有效。