在家中保护全天候运行的 AI 智能体:一段充满死胡同的旅程
TL;DR
我在家里一台闲置的迷你主机上运行着一个拥有 shell 访问权限、全天候在线的 AI 智能体(AI agent)。真正难的部分不是把它搭建起来,而是确保一旦它被攻破,问题不会扩散出去。原地给智能体加防火墙这条路走不通:它的整个工作就是发起对外连接,所以出站流量过滤(egress filtering)要么会把它废掉,要么会退化成一份你得时时照看的白名单。真正奏效的办法,是把这台机器搬到它自己的路由器上,彻底脱离我的家庭局域网,这样即便它被完全攻破,攻击者也只能触达互联网,碰不到我的笔记本电脑或 NAS。远程访问走的是 ngrok 隧道连到仅限密钥登录的 SSH;剩下的是这台机器本身的纵深防御(defense in depth),外加一份诚实的清单,列出这套方案到底防不住什么。
这是我如何为 Hermes Agent 做安全加固的记录——它是 Nous Research 出品的一款全天候运行、基于命令行(CLI)的 AI 助手,跑在我家里一台闲置的迷你主机上。这不是一篇"完美方案"的文章,而是三次失败尝试和一次成功方案的诚实记录。
目标
我想要一个在家里 24 小时运行的 AI 智能体,并且能从任何地方连上它:我的手机、别人网络下的笔记本电脑、出差时的酒店房间。Hermes 可以执行 shell 命令、读写文件、浏览网页,还能调用外部 API。这正是它有用的原因,也正是它危险的原因。一个拥有 shell 访问权限、全天候运行的进程,如果就这么待在你的家庭网络里,一旦搞砸了后果会很严重。
于是这个项目变成了:我要如何运行这东西,才能做到 (a) 我能远程访问它,(b) 它碰不到我家庭网络里的其他设备,(c) 万一它本身或者它所在的机器被攻破,影响范围(blast radius)能被我压到最小?
宿主机是一台运行 Linux 的 Dell OptiPlex 9020M:便宜、低功耗,几乎无风扇噪音的迷你主机。我在 2026 年 6 月中旬安装了 Hermes 的最终原版(stock version)。
有一件事我在这里跳过不谈:为什么选 Hermes,而不是其他自托管(self-hosted)智能体。那是一个独立的决定,主要考量是安全姿态(security posture),以及它出自一家独立实验室而非前沿大厂这一事实。我在另一篇文章里详细梳理过这个对比,见 Hermes vs. OpenClaw。这篇文章接着那篇的结尾往下讲:智能体已经选好、装好了,现在我得想办法运行它,同时不让它变成我网络里最薄弱的一环。
尝试一:原地加固,留在家庭局域网里
我最初的直觉是教科书式的做法:把机器留在我的家庭网络里,然后死死锁住它。激进的防火墙规则、严格的出站流量过滤、最小化服务,一样不落。把这台机器加固到足以和其他一切设备安全共处的程度。
这条路失败了,但失败得很有价值。加固措施太严格,以至于智能体没法正常工作。最基本的能力——访问网络——直接坏掉了。智能体需要的出站流量(调用模型提供商的 API、网页搜索、抓取页面)全被我为拦截坏流量而撒下的那张网一并挡住了。于是我开始一个个打洞。每打一个洞,都感觉是在拆掉我刚加上的安全措施。我在追一个不断移动的目标:智能体每用上一个新工具,就需要一个新的出站目的地,而我在手工维护一份白名单——它既紧到没法用,又漏到让人不放心。
还有第二个独立的问题。加固措施并没有停留在操作系统层面。要真正落实它,就得对 Hermes 自身的源代码做大量修改,而这让升级变得非常脆弱。Hermes 正在活跃开发中,更新频繁,每次更新都会把我打的补丁冲掉,逼着我手动重新应用每一处定制。我实际上是在维护一个私有的智能体分支(fork),就为了让我的安全规则保持生效,而这些规则本身已经证明太脆弱,撑不起这份工作。
事后看很明显的两个教训。一个智能体全部的价值都在于对现实世界采取行动,这种智能体和出站流量过滤天生互斥。你没法真的对一个整个工作就是发起出站请求的进程说"全部拦截";你要么把它废掉,要么维护一份永远落后于现实的脆弱白名单。而通过打补丁改智能体自身源码来实现加固是个陷阱,因为这会让你的安全措施直接和项目的发布节奏对着干。
与其继续打这场仗,我干脆改变了网络拓扑(topology)。
尝试二:把这台机器搬出家庭网络
于是我不再试图让智能体在我的网络内部保持安全,而是把它搬到外部去。
我家的网络接入是通过 ISP 路由器进来的。OptiPlex 直接挂在这台 ISP 路由器上,从未接触过我的家庭局域网。在它下游,我放了第二台路由器来管理家庭局域网,我真正在意的一切(笔记本电脑、手机、NAS)都待在它后面,与 OptiPlex 隔离开。OptiPlex 处在 ISP 路由器的子网上,即 192.168.2.x;家庭局域网则在自己的子网上,即 192.168.100.x。
效果是:智能体所在的机器处在路由器边界的互联网一侧,而我的家庭网络在自己的路由器后面,与它隔离。OptiPlex 没有通往家庭局域网的路由。即便智能体或这台机器被彻底攻破,攻击者落脚的子网也只能触达更广阔的互联网,碰不到我的私人设备。"智能体机器被攻陷"这件事的影响范围,从"我整个家庭网络"收缩成了"一台孤立的机器和它的 API 密钥"。
┌──────────────────────────────────────┐
Internet ───► │ ISP router │
└───────────────┬──────────────────────┘
│
┌───────────────┴──────────────────────┐
│ │
┌─────────▼──────────┐ ┌────────────▼──────────────┐
│ Second router │ │ OptiPlex (Hermes agent) │
│ (home LAN gateway)│ │ 192.168.2.66 │
└─────────┬──────────┘ │ no route to home LAN │
│ └───────────────────────────┘
┌─────────▼───────────┐
│ Home LAN │
│ 192.168.100.x │
│ (laptops, phones, │
│ NAS, etc.) │
└─────────────────────┘
这是整个项目里最大的一次安全胜利,而且不花一分软件成本。网络分段(segmentation)胜过我能写出的任何防火墙规则。它还一次性解决了尝试一里的两个问题。智能体现在可以自由访问互联网,因为这已经没问题了:我原本担心它会碰到的东西——我的家庭网络——待在一道它跨不过去的路由器边界的另一侧。而且因为这种隔离来自网络层面,而不是对智能体代码的修改,我又可以运行原版 Hermes 了。不用私有分支,不用在每次更新时重新打补丁。
关于拓扑选择的一点说明。对这个安全模型真正重要的,是智能体机器和家庭局域网之间的路由器边界,在我的设置里,这道边界就是第二台路由器的 WAN 防火墙。我其实不需要第二台路由器也能得到类似的边界:把 OptiPlex 放进它自己的 VLAN,或者放在 ISP 路由器上一个独立的子网里,再加一条禁止两个网段互通的跨区防火墙规则就行。我的 ISP 路由器完全可配置,支持这么做;很多发烧友级和商用级路由器也都支持。在最关键的威胁模型(一台被攻破的智能体机器试图触达家庭网络设备)下,这两种做法的隔离效果是等价的:两种方案都设置了一道智能体流量跨不过去的防火墙边界。
我选择双路由器方案是出于一个原因:这种隔离是结构性的,而不是依赖配置的。用两台物理路由器,就不存在什么 VLAN 标签、跨区防火墙规则,或者交换机端口分配——这些东西都可能被意外配错,或者被一次固件更新悄悄覆盖,从而在两个网段之间打开一条通路。这道边界的存在,仅仅是因为网线插在了哪里。这个理由听起来比实际更有说服力(一台维护良好的路由器上正确配置的 VLAN 完全值得信赖),但我就是喜欢这种隔离能扛住配置失误、固件变更,还有我自己的健忘。如果我手头没有现成的第二台路由器,或者是在一个只有一台路由器、又不想添置额外硬件的地方搭这套系统,单路由器 VLAN 方案完全合理,我也会毫不犹豫地采用。
关于"没有通往家庭局域网的路由"这个说法,有一个诚实的补充说明:这道边界本身也是一台设备,而这台设备就处在我视为已被攻破的那台机器的可触达范围内。OptiPlex 和第二台路由器的 WAN 侧共享 ISP 路由器的子网,所以一台被攻破的 OptiPlex 没法穿过第二台路由器路由过去,但它可以直接攻击这台路由器本身,一旦得手,它就站到了边界的另一侧。我已经尽我所能封死了这条路径。第二台路由器的管理界面在 WAN 侧被禁用,并设有强密码保护,所以从智能体所在的那个子网望过去,根本没有任何管理接口可以触达。通往家庭局域网的路由并不存在,而唯一能创造出这条路由的那台设备,也无法从智能体所在的位置进行管理。
但这又制造了一个新问题。如果这台机器待在自己的一小块子网里,我要怎么连上它?
尝试三:Tailscale,栽在与 VPN 的冲突上
远程访问方面,我的第一选择是 Tailscale。它搭建的是一个 WireGuard 网状覆盖网络(mesh overlay):在目标机器和客户端上都装上它,它们会通过 Tailscale 的协调服务器找到彼此,然后打开一条直连的加密隧道。干净利落,端到端加密,还带 ACL 和设备标签。我在 OptiPlex 上用一个隔离标签(tag:isolated)和 Tailscale 内置的 SSH 服务器把它跑了起来:
sudo tailscale up --advertise-tags=tag:isolated --ssh
计划是让 OptiPlex 只能通过 Tailnet 访问,而且只能从我授权过的设备访问,加密和身份验证都交给 Tailscale 处理。不暴露端口,路由器上不做端口转发,也没有公网 IP。
我花了一段时间调试它:查看 netmap、检查 SSH 策略、在 tailscale0 上跑 tcpdump 观察流量。设置本身没问题,真正要了它的命的,是和我的 VPN 之间的冲突。
这是一类广为人知、也很让人头疼的问题。Tailscale 本身就是一个 WireGuard 客户端,所以它想要管理路由表和一块虚拟网卡。商用 VPN 客户端想要的东西一模一样,尤其是当它本身也基于 WireGuard,或者带有会劫持默认路由的"杀断开关"(kill switch)时。在我用来连接的笔记本电脑或手机上,同时跑我个人的 VPN 和 Tailscale,意味着总有一个会败下阵来。连接要么不稳定,要么干脆连不上。
我本可以用基于策略的路由、分流隧道(split tunneling),或者每次要连智能体时就关掉 VPN 来绕过这个问题。但这些办法都违背了我的初衷。我想要的是那种在任何设备、任何网络状态下都能"直接能用"的东西。在我的设置里,Tailscale 做不到这点。于是我把它彻底卸掉了:
sudo apt-get remove --purge -y tailscale
sudo apt-get remove -y tailscale-archive-keyring
这完全不是在贬低 Tailscale。它非常出色,如果我的客户端设备上没有跑消费级 VPN,它本该是正确答案。这个冲突是我个人使用习惯特有的问题,不是工具本身的问题。
尝试四:通过 ngrok 做一条 TCP 隧道(我现在用的方案)
我需要一种不在乎客户端路由表或 VPN 状态的远程访问方式:连接一个固定的公网地址,它会把连接中继回那台机器。我最终选定了 ngrok。
ngrok 在 OptiPlex 上作为一个常驻服务运行。它主动拨号连到 ngrok 的中继基础设施,并保持一条隧道常开。ngrok 会分配一个公网 TCP 端点,转发到本地的某个端口。我把它指向了本地的 SSH 端口:
ngrok tunnel: tcp://<region>.ngrok.io:<port> ──► localhost:22
现在,无论在哪里,我都可以 SSH 连接到 <region>.ngrok.io 的 <port> 端口,ngrok 会把连接中继到 OptiPlex 的 SSH 守护进程。我家路由器上没有为这台机器开放任何入站端口。没有端口转发,我的连接也不暴露公网 IP,没有动态 DNS(Dynamic DNS)。是 OptiPlex 主动拨出去的连接,隧道是从内部维持住的。
(术语说明:人们经常把这种做法叫作"反向 SSH 隧道"(reverse SSH tunnel),类比的是 ssh -R——在一台远程服务器上开一个端口,转发回你的本地机器。ngrok 实现的是同样的"从外部连进来"的效果,但中继的是 ngrok 自己的基础设施,而不是某台 SSH 服务器的反向端口转发。概念相同,都是"一个隧道通向内部服务的公网地址",但机制不同。)
为了保证可靠性,ngrok 作为一个系统级的 systemd 服务运行,失败后会自动重启,所以隧道在重启或网络抖动之后会自己恢复。它背后的 SSH 守护进程被锁定为仅支持基于密钥的身份验证:没有密码登录,也没有键盘交互式登录。所以要连上这个智能体,你得拥有正确的私钥、知道 ngrok 的 TCP 地址和端口,并且连接到一个只接受我授权过的那两把密钥的服务。
这就是我目前使用的访问路径,一直很稳定。
我保留下来的:这台机器本身的纵深防御
把机器搬出家庭网络、同时保证可访问,解决了网络层面的问题。但我仍然希望这台机器本身是加固过的,这样即便是"孤立子网"这个最坏情况,也能被尽量控制住。以下是留存下来的加固措施。和尝试一不同,这些措施没有一项会破坏智能体的正常运作,因为它们针对的是入站流量和智能体自身的行为,而不是出站连接。而且没有一项碰智能体的源代码:全都是系统级配置、文件系统布局,以及通过配置打开的内置功能。
主机防火墙(nftables,入站默认拒绝)。 这台机器运行 nftables,对入站流量采取默认 DROP 策略。除非是已建立的连接、回环流量、DHCP 或 ICMP,否则什么都到不了这台机器。这一层叠加在 NAT 和网络分段之上,所以入站防护有三层:ISP 路由器、第二台路由器的边界,以及主机防火墙。
SSH,仅限密钥登录。 密码登录和键盘交互式登录都被禁用了。只有两把授权密钥,都是我自己的。SSH 是 ngrok 隧道暴露出来的唯一服务,所以这是唯一现实入口上的凭证关卡。
智能体自身的进程内防御。 Hermes 自带好几层防御机制,我都保留开启:
- 一个执行前命令扫描器(Tirith),在智能体想要运行的每一条 shell 命令执行之前,检查其中是否存在基于 URL 的威胁、同形异义字符攻击(homograph attacks)、管道传给解释器的模式,以及终端注入。
- 对所有工具输出做密钥脱敏(secret redaction),所以如果 API 密钥出现在某个文件或某条命令的标准输出里,它会在进入智能体上下文之前被遮蔽(也就没法通过模型泄露出去)。这项设置在启动时就被快照固定,会话中途无法关闭。这是刻意为之:智能体不能关掉自己的脱敏功能。
- 对破坏性命令(
rm -rf、强制推送等)设有人工批准关卡。智能体在运行它们之前必须先请求许可。(通过 cron 调度的任务用的是更严格的模式,破坏性命令会被自动拒绝。) - 对项目上下文文件(也就是被注入系统提示词的
.hermes.md/AGENTS.md文件)设有威胁扫描器,用来消解提示词注入(prompt-injection)模式。 - 在 Telegram 网关上设有主叫方白名单,这是智能体监听的唯一一个通道。
数据分离。 智能体的大量数据(会话、日志、缓存)存放在一块专用的外接 SSD 上,而安全关键文件(存有 API 密钥的 .env、配置文件、会话数据库)留在系统盘上,权限设为 600。
一个锁死的次要档案。 我保留了第二个 Hermes 档案,把大部分危险工具集(编码、电脑操作等)都禁用了,用于那些不需要完整能力的研究类任务。
最终落点:一份诚实的评估
下面是这套最终方案实际能防住什么,又防不住什么。
能防住的:
- 智能体机器被攻破后被用来攻击我的家庭网络(它没法路由到那里)。
- 来自互联网的未经请求的入站连接(我的路由器上没有开放端口;主机防火墙默认拒绝)。
- 未经授权的人通过 Telegram 联系到这个智能体(白名单机制)。
- 智能体把我的 API 密钥泄露进它自己的上下文或聊天记录里(密钥脱敏)。
- 智能体意外或者因为一次拙劣的提示词注入而运行了破坏性命令(批准关卡 + 命令扫描器)。
- SSH 密码暴力破解(仅限密钥登录)。
防不住的(我心里清楚):
- 一次足够精心设计、能一路串联到 shell 的提示词注入。智能体的终端后端是在本地运行的,以我的用户身份,还带 sudo 权限。如果攻击者能构造出说服智能体运行任意 shell 命令的输入,智能体和宿主机之间并没有操作系统级的沙箱。进程内扫描器和批准关卡确实提高了门槛,但它们是启发式手段,不是一道遏制边界。
- 这台机器被物理盗窃。磁盘没有加密。谁拿到了这台机器,谁就拿到了 API 密钥和会话历史。
- 一个在智能体进程内以完整权限运行的恶意技能或插件。我通过不加载第三方插件来缓解这一点,但这是一道信任边界,而不是技术边界。
- ngrok 端点本身。如果 ngrok 被攻破,或者我的 ngrok 凭证泄露,SSH 端口就会通过它们的中继暴露出去。我把 ngrok 纳入了我的信任链之中,这是一次有意识的取舍,用它换取不必自己运营中继服务的便利。
- 从这台机器本身发生的数据外泄。自由的出站访问正是这套设计的一部分;正是它让智能体变得有用,也正是它让我不用再和出站流量过滤死磕。反过来的代价是,一台被攻破的主机可以读取自己的磁盘(
.env、会话数据库),然后把内容 POST 到任何它想去的地方,这台机器上没有任何东西能阻止它。密钥脱敏防的是密钥泄露进模型的上下文;对于一台直接读取文件的被攻破主机,它无能为力。这一点我是故意接受的:智能体持有的每一把 API 密钥,作用域都限定在一个设有硬性消费上限的服务上,所以密钥泄露的最坏情况是一笔封顶的账单,而不是无限度的滥用。
诚实地总结一下:我用智能体的操作系统级隔离,换取了本地后端带来的便利,并通过在网络层面隔离这台机器来做补偿,让智能体的影响范围由一道路由器边界来限定,而不是由一个容器来限定。对于一个个人使用、单用户、单租户的智能体来说,这是一笔合理的交易。但如果这个智能体要服务不受信任的用户、摄入不受信任的内容(比如解析任意邮件),或者跑在共享环境里,这就不是正确的交易了。
我的收获
如果要我给第一次搭建全天候智能体的人一条建议,那就是:不要试图仅凭防火墙规则就让智能体变安全。 智能体全部的工作就是伸手触及外部世界,而出站流量过滤在每一步都在跟这个目标对着干。正确的做法是,把智能体放在一个网段里,让它可能伤害到的东西够不着它,然后放手让它自由地和互联网通信。网络分段是一次性的物理/配置动作,不会随着智能体行为的演变而失效;而出站白名单则是一项维护负担,你一不留神它就会腐烂。
第二条原则,是我吃了苦头才学到的:如果确实要加固智能体本身,优先选择配置和内置功能,而不是给它的源代码打补丁。活在智能体源码里的定制,会在下一次更新时死掉;而活在配置或网络层面的定制,能挺过每一次升级。
剩下的部分,是给分段防不住的那些漏洞做的纵深防御:仅限密钥的 SSH、默认拒绝的主机防火墙,以及智能体自身的命令扫描和密钥脱敏。但在这整套方案里,网络分段起到的作用比其他所有措施加起来还大,这也是我本该最先做的那一步。
宿主机:Dell OptiPlex 9020M,Linux。智能体:Hermes(Nous Research)。远程访问:ngrok TCP 隧道连到仅限密钥登录的 SSH。写于 2026 年 7 月。