instabox 云沙盒保活:为什么在机器里做什么都没用
这篇文章针对 instabox 这类「一段时间不操作就把整台 VM 冻结」的沙盒平台。下面的结论和脚本都在 instabox 上实测过;同类平台思路通用,但端口映射规则和网关地址要按实际情况改。
先说结论
云沙盒这类「一段时间不操作就整台 VM 冻结」的平台,判定发生在宿主机层。
这意味着:
| 做法 | 结果 |
|---|---|
| 沙盒内制造 CPU 负载 | 无效,照样被冻 |
| 沙盒内定时发网络请求 | 无效 |
| 从外部访问沙盒的端口映射地址 | 有效 |
沙盒里跑什么,宿主机根本不看。要续命只能从外面碰它。
这条结论不是猜的,是跑了 45 小时后拿数据换来的。
三条证据
一、心跳在跑,机器照样被冻
沙盒内每分钟执行一次心跳脚本,日志显示断档:
1
2
3
04:17:44 → 04:18:49 → 04:19:54 → 04:20:59
SUSPENDED_GAP: 941s ← 被冻结 15 分 41 秒
04:36:40 → 04:37:42 → 04:38:46
断档前后都是准点条目。进程没死,是整台机器被冻住了。
二、平台自己的 agent 也被冻
沙盒内的 guest agent 每 5 分钟向宿主机上报一次,同一时间窗口一起断档。连平台自己的组件都停了,说明冻结在 VM 层,不在应用层。
三、恢复时出现 VM 级动作
1
2
3
04:36:34 op=sync_clock ← 重新校时
04:36:34 op=configure ← 重新下发配置
04:36:35 op=configure_ipv6
只有 VM 从挂起状态恢复才会走这套流程。
三条同时成立,就可以定性了:继续在沙盒内部研究「制造什么活动」是浪费时间。
一个很容易踩的坑
对 guest agent 做 strings,能看到一堆看着像开关的符号:
1
2
3
4
5
internal/guestagent/activity.go
guestagent.(*Agent).activity
guestagent.activityTimeout
guestagent.ActivityProbes
guestagent.RunProbe / probeSignal / probeTimeout
看起来像在检测 CPU busy、服务状态,很容易得出「造 CPU 负载就能保活」的结论。
但这是错的。 如果 CPU busy 真能续命,第一条证据里的 941 秒冻结就不可能发生。
这些探针只是使用统计,不参与暂停决策。
教训:二进制里有 activity 相关符号,不等于找到了控制开关。必须用行为验证,不能靠符号推断。
怎么搭
前提是先拿到端口映射地址。平台通常把沙盒端口映射成 <端口>-<机器ID>.<通配域>,注意裸域往往不解析,只有子域指向统一网关。
1
2
3
4
5
# 机器 ID,在沙盒内执行
cat /etc/instabox/identity | sed 's/^m_//'
# 验证网关可达
curl -sS -m 10 https://3000-<MACHINE_ID>.instabox.tech
返回 Nothing is listening on this port in the sandbox 说明网关通了、沙盒该端口空着。这个 URL 不需要登录态,比控制台 API 好自动化得多。
第一步:沙盒内起监听
1
curl -fsSL https://raw.githubusercontent.com/poisonhs/instabox-keepalive/main/scripts/sandbox-side.sh | sh -s -- 3000
脚本装一个 systemd 服务,用 python3 在指定端口常驻。验证:
1
2
systemctl is-active ka-http
ss -tlnp | grep ':3000'
第二步:外部机器定时敲门
必须是另一台机器。 沙盒自己访问自己,流量没离开机器,网关看不到,等于没做。
1
curl -fsSL https://raw.githubusercontent.com/poisonhs/instabox-keepalive/main/scripts/outside-side.sh | sh -s -- 3000-<MACHINE_ID>.instabox.tech
装一个 5 分钟一次的 systemd timer。
不一定要公网 VPS——家里的树莓派、路由器 cron、另一台云主机都行,关键是常开且不能是沙盒自己。
第三步:可选的长连接加固
定时任务是「新建连接、请求完就断」,长连接则是一次 TLS 握手后复用同一 TCP,每 60 秒打一次,网关看到的是持续会话。
两种可以同时挂,但那样就无法区分哪条在起作用。验收按整体判就行。
怎么算通过
不要凭「现在能通」下结论。 单次 200 什么都证明不了,必须等过了平台的空闲窗口再看。
| 指标 | 合格线 |
|---|---|
uptime | 连续不少于 2 天 |
心跳日志 SUSPENDED_GAP | 0 条 |
敲门日志 502 | 0 条 |
三条同时成立才算保活成立。
状态码怎么读
| 码 | 含义 | 动作 |
|---|---|---|
200 | 链路通,沙盒活着 | 正常 |
502 | 沙盒内该端口没服务 | 先查沙盒侧进程 |
429 | 请求太密,网关限流 | 间隔拉到 60 秒以上 |
000 | DNS / 网络 / 超时 | 查域名拼写和 DNS |
关键一条:429 和 000 都不代表沙盒挂了,只有 502 指向沙盒侧。 报告问题时这点要说清楚,否则容易把限流当故障。
实测
| 指标 | 数值 |
|---|---|
| 连续运行 | 45.6 小时 |
| 系统 uptime | 2 天 24 分 |
SUSPENDED_GAP | 0 次 |
| 敲门成功 | 511 / 521 |
502 出现次数 | 0 |
对照组:只跑内部心跳时,停止操作 941 秒即被冻结。
一点想法
这个项目里最值得抄的不是脚本,是诊断顺序:先用行为数据排除层级,再去猜实现细节。反过来做的话,很容易被二进制里几个像样的符号骗着走上岔路。
仓库:poisonhs/instabox-keepalive,MIT 许可。仅用于自己拥有或经授权管理的沙盒实例。