在 8.222.155.72 上按需拉起隔离开发环境;合上笔记本后 agent 继续跑,开机秒回原 session。
harness = Claude Code,模型 = MiniMax-M3。
jinghao.site,nginx 占着 80/443,证书续期依赖 80 端口的 HTTP-01。apt。 实际是 Alibaba Cloud Linux 4,RHEL 系,dnf。你的文档已记录 certbot 不在仓库里——docker-ce 也得实测。MiniMax-M3。这改变了「无人值守」的风险计算。见 §5。接 MiniMax 意味着你本机的 Claude 官方账号和 OAuth 凭证完全不需要上服务器。这台公网机器上永远不会有你的 Anthropic 长期凭证。攻击面反而比 v1 小。
| 你的决定 | 直接后果 |
|---|---|
| 语言动态 不同容器不同语言 |
不能造一个胖镜像。走「瘦 base 镜像 + 每项目 devcontainer.json + Features」。这恰好也让 CLI 和 VS Code 共用一套配置。见 §4 |
| MiniMax key 注入 不用 Claude 官方账号 |
Anthropic 凭证不上服务器(好)。但模型换成 MiniMax-M3,且端点/key 有国内站 vs 国际站的同源问题。见 §5 |
| git + VS Code Remote-SSH 两种都要 |
代码放 /srv/dev/<proj>,两条路径共用同一 bind mount。但 git 凭证与"离线运行"直接冲突。见 §6 |
| 保持 root 直登 | 宿主机不动。但容器内仍必须跑非 root——否则 bind mount 出来的文件全是 root 所有,你在 VS Code 里改不动。 |
Claude Code 只是个普通前台进程。关机杀死它的是 SIGHUP,不是什么状态问题。
| 层 | 机制 | 挡住什么 | 挡不住什么 |
|---|---|---|---|
| L1 | 容器内 tmux server,claude 跑在 tmux window 里 | SSH 断线、合盖、关机、网络抖动 | 容器被删 / 进程被 OOM kill |
| L2 | 容器 PID1 ≠ claude | claude 一退整个容器消失 | 宿主机重启(除非配 --restart) |
| L3 | ~/.claude 挂 named volume | 容器重建后彻底丢历史 | 进程被杀时正在进行的那一轮 |
devcontainer 规范里,基于 image / dockerFile 的配置默认 overrideCommand: true,容器 PID1 会被替换成一个无限 sleep 循环。用 devcontainer.json 就自动拿到 L2,不用自己 sleep infinity。
claude --resume 能捞回历史对话,但捞不回"关机瞬间正跑到一半的那次工具调用"。真正让 agent 在你睡觉时干活的只有 L1。L3 是兜底。
Windows 笔记本
│
│ ssh myserver (22,密钥,root)
│ ssh -L 5173:localhost:5173 myserver ← dev server 走隧道,不开安全组
▼
8.222.155.72 Alibaba Cloud Linux 4 · 新加坡
│
├─ nginx :80 :443 ────► jinghao.site 【生产站点,不许碰】
│ └─ acme.sh cron,靠 :80 的 /.well-known/ 续期
│
├─ dockerd (unix socket only;容器一律不 publish 到 0.0.0.0)
│
├─ /etc/devbox/minimax.env chmod 600, root:root ← MiniMax key + BASE_URL
│ (无任何 Anthropic 凭证)
│ 出网 → api.minimaxi.com 【新加坡→国内站,待实测,见 §5 坑一】
│
└─ 容器 devbox-<project>
│ PID1 = sleep loop ← L2(devcontainer 默认给的)
│ 以非 root 用户 dev 运行,uid 对齐宿主
│
├─ tmux server ← L1
│ └─ session "main"
│ └─ claude .......... ← agent 在这里跑
│
├─ /workspaces/<proj> ← bind mount ← /srv/dev/<proj> (git clone 在这)
│
└─ /home/dev/.claude ← named volume (L3)
└─ projects/<cwd>/*.jsonl 会话历史
重连:
ssh -t myserver docker exec -it -u dev devbox-myproj tmux attach -t main
这台机器上跑着一个活的、有 TLS 证书自动续期的站点。以下每条都不是建议,是约束。
0.0.0.0。 一律不带 -p,或只 -p 127.0.0.1:5173:5173。dev server 通过 SSH 本地端口转发访问 —— 既不碰 80/443,也不用改安全组。DEPLOYMENT.md §7 里有现成的假 token 脚本,专门验 /.well-known/acme-challenge/ 仍走明文 HTTP。那条路径被吃掉 = 证书两个月后静默过期 = 站点挂了你才知道。firewalld inactive、INPUT 策略 ACCEPT,唯一网络关卡是安全组。这意味着即使容器误 publish 了端口,外网也进不来。这是好事,但不要把它当唯一防线——安全组是你手动维护的,哪天放行了别的端口就漏了。docker system df。你要"不同容器不同语言",又要"CLI 和 VS Code 两种入口"。如果分别配,必然漂移成两套系统。
解法是把语言声明推进每个项目的 .devcontainer/devcontainer.json,用官方 Features 声明式装工具链:
// /srv/dev/myproj/.devcontainer/devcontainer.json
{
"name": "myproj",
"image": "devbox-base:latest", // 瘦 base:claude-code + tmux + git + rg/fd/jq
"features": {
"ghcr.io/devcontainers/features/go:1": { "version": "1.23" },
"ghcr.io/devcontainers/features/python:1": { "version": "3.12" }
},
"remoteUser": "dev",
"runArgs": ["--env-file", "/etc/devbox/anthropic.env"],
"mounts": [
"source=devbox-claude-myproj,target=/home/dev/.claude,type=volume" // L3
]
}
然后两个入口读同一份配置:
| 入口 | 命令 |
|---|---|
| 终端 / tmux | devcontainer up --workspace-folder /srv/dev/myproj |
| VS Code | Remote-SSH 连上 → 打开 /srv/dev/myproj → Reopen in Container |
VS Code 的 Dev Containers 扩展应当能复用 CLI 已创建的容器(两者都用 devcontainer.local_folder 这个 label 做查找)。但我没在你这台机器上验证过。 如果它不复用而是新建一个,两个入口就会各起一个容器、tmux session 对不上,整个"重连原 session"的体验就断了。
Phase 3 必须实测这一条。 若不复用,退路是:VS Code 只当编辑器,claude 一律从 devbox attach 进 tmux 跑。
Features 从 ghcr.io 拉取,需要出网。新加坡节点应该没问题,但 Phase 0 要测。
Claude Code 可以指向任何 Anthropic 协议兼容的网关。MiniMax 提供了一个。配置不难,难的是它带来的四件事。
按官方文档(platform.minimaxi.com/docs/token-plan/claude-code):
# /etc/devbox/minimax.env chmod 600, root:root
ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic
ANTHROPIC_AUTH_TOKEN=<你的 MiniMax key>
ANTHROPIC_MODEL=MiniMax-M3
ANTHROPIC_DEFAULT_SONNET_MODEL=MiniMax-M3
ANTHROPIC_DEFAULT_OPUS_MODEL=MiniMax-M3
ANTHROPIC_DEFAULT_HAIKU_MODEL=MiniMax-M3
CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000 # M3 是 1M 上下文
文档给的是 ANTHROPIC_AUTH_TOKEN。这两个变量在 Claude Code 里走的路径不同 —— 前者直接设 Authorization 头,后者会触发"检测到 API key"的确认流程。指向第三方网关时用文档给的那个,别顺手改成 ANTHROPIC_API_KEY。
文档里有两个端点:
https://api.minimaxi.com/anthropic —— 国内站https://api.minimax.io/anthropic —— 国际站你给的链接是 minimaxi.com(国内站),key 也从 platform.minimaxi.com/user-center/payment/token-plan 取。国内站与国际站是两套独立账号体系,key 通常不通用。
而你这台 ECS 在 ap-southeast-1(新加坡)。于是有两个必须弄清的问题:
api.minimaxi.com?延迟多少?—— Phase 0 我来实测Claude Code 是 harness,MiniMax-M3 是模型。三个模型槽位(Opus / Sonnet / Haiku)全部映射到 M3 —— 包括 Claude Code 内部拿"小快模型"做的那些活。
这不是贬低 M3。这是一个必须摆在桌面上的事实:你在 §7 里要开 --dangerously-skip-permissions,也就是把无人监督的 shell 执行权,交给一个你尚未在这个 harness 里摸过底的模型。 Claude Code 的工具调用约定是围绕 Claude 调优的;换模型后的失败模式(误删文件、循环重试、卡在错误的假设上)需要你自己积累经验。
建议:前几次不要无人值守。 先盯着它跑,看清它在你的项目里怎么用工具,再放它单飞。这条比任何配置都重要。
那份文档里没有任何关于订阅制 / 按量计费 / 速率限制 / 并发限制的说明。我不知道你的 token plan 是预付费额度包还是后付费。所以我也收回 v2 里"去 Anthropic Console 设 spend limit"那句 —— 那是错的,你根本不用 Anthropic 计费。
但无论哪种模式,「无人值守」+「跳过权限确认」都会消耗它。跑偏一整夜的结果,要么是账单,要么是额度归零。开工前去 MiniMax 控制台确认计费模式,看有没有额度告警可设。
文档说联网搜索需要另外按 MCP 教程配置。容器里的 claude 默认没有 web search 能力。如果你的工作流依赖它(查文档、查报错),Phase 5 要单独处理。
聊天内容会写进你 Windows 上的 ~/.claude/projects/*.jsonl(明文落盘),并作为对话的一部分发送到模型服务商。一个能自主执行命令的 agent 的对话记录里躺着一把付费 key,是不必要的暴露。
你自己 ssh 上去写,我全程不需要看见它:
ssh myserver
mkdir -p /etc/devbox && chmod 700 /etc/devbox
cat > /etc/devbox/minimax.env <<'EOF'
ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic
ANTHROPIC_MODEL=MiniMax-M3
ANTHROPIC_DEFAULT_SONNET_MODEL=MiniMax-M3
ANTHROPIC_DEFAULT_OPUS_MODEL=MiniMax-M3
ANTHROPIC_DEFAULT_HAIKU_MODEL=MiniMax-M3
CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000
EOF
# key 单独追加,read -rs 让它不进 shell history
read -rs KEY && printf 'ANTHROPIC_AUTH_TOKEN=%s\n' "$KEY" >> /etc/devbox/minimax.env
unset KEY
chmod 600 /etc/devbox/minimax.env
docker history 能扒出来devcontainer.json —— 那文件在 git 里,会被 push 到远端docker run 命令行 —— ps aux 就能看到--env-file。残留提示:key 仍会出现在 docker inspect 的 Config.Env 里。这台机器 docker 只有 root 能用,可以接受,但你要知道它在那儿。你选了 git 同步。那么当 agent 在你合盖之后想 git push 时,会发生什么?
SSH agent forwarding(ForwardAgent yes)只在你连着的时候有效。 你一合盖,forwarded socket 就没了。agent 执行 git push → 认证失败 → 要么报错,要么卡在密码提示上,然后一整晚什么都没干。
| 方案 | 做法 | 评价 |
|---|---|---|
| 约定 claude 不 push | 只 commit 到本地分支,你回来自己 push。写进 CLAUDE.md |
推荐。 无凭证暴露;agent 的产出你回来能审一遍再推 |
| 服务器侧 deploy key | 为该 repo 生成专用 SSH key,只给写权限 | 可行。每个 repo 一把,权限最小化 |
| fine-grained PAT | GitHub token 写进 /etc/devbox/ |
可行但又多一份长期凭证在公网机器上 |
| 与本方案的核心目标直接矛盾,不要用 |
Claude 把当前这轮任务干完就会停下来等输入。"关机后继续运行" = 它能把手头这轮跑完,不是 24 小时自主工作。 心理预期是后者的话,方案再完美也会失望。
你人不在,它弹 Allow Bash(npm install)?,然后永远等在那里。你回来看到一个一动没动的进度条。
解法是容器内使用 --dangerously-skip-permissions —— 这正是 dev container 存在的意义,隔离的一次性环境里这个 flag 是合理的。Anthropic 官方 devcontainer 参考实现就是这个思路,配 init-firewall.sh 做出网白名单。注意白名单里要放的是 api.minimaxi.com,不是 api.anthropic.com。
但请把它和 §5 坑二、坑三连起来读:跳过权限 + 换了个未摸底的模型 + 无人看管 + 计费模式未知,四者叠加。头几次盯着跑,不是客套话。
配一个 Stop hook:claude 跑完 → 打 webhook → 手机收消息(ntfy / 飞书 / Slack)。否则你不知道什么时候该开机去看结果,只能瞎猜。
DEPLOYMENT.md 已经替我回答了一半:OS = Alibaba Cloud Linux 4,内核 6.6.102,磁盘 40G/22%,SELinux disabled,firewalld inactive,iptables INPUT ACCEPT。仍然未知的:
dnf 里有没有 docker-ce —— RHEL 系需要挂 CentOS/阿里云镜像仓库,不是一句 apt installapi.minimaxi.com 与 api.minimax.io(两个都测,见 §5 坑一)、ghcr.io(Features)、registry-1.docker.io(镜像)。不再需要 api.anthropic.com。curl -I https://jinghao.site/ + 假 token 测 acme-challenge,记录基线dnf 装 docker-ce(仓库需实测);不开 TCP socket/srv/dev/devbox-base:latest:@anthropic-ai/claude-code、tmux(set -g mouse on)、git、ripgrep、fd、jq、gh。非 root 用户 dev,uid/gid 与宿主对齐。语言工具链一律不装 —— 交给各项目的 Features。
| 命令 | 作用 |
|---|---|
devbox up <proj> | devcontainer up + 建 tmux session main |
devbox attach <proj> | 一路 attach 进 tmux |
devbox ls | 列出所有 devbox 及 tmux session 状态 |
devbox down / nuke | 停容器(留 volume) / 连 volume 一起删 |
① 断连持久化:attach 进去让 claude 跑个几分钟的任务 → 直接合盖(不要优雅退出)→ 五分钟后开机 devbox attach → 断言任务已跑完,能向上滚动看到你不在时的中间输出。
② VS Code 容器复用:CLI 起容器 → VS Code Remote-SSH → Reopen in Container → 断言没有新建第二个容器,且 VS Code 终端里 tmux attach 能接上 CLI 那个 session。(见 §4 的待实测假设)
③ 生产站点无损:全程 https://jinghao.site/ 返回 200,acme-challenge 路径返回 200 明文。
见 §5「key 怎么交给服务器」。命令我给你,你自己执行,我不接触 key。之后 devcontainer.json 里只出现 --env-file /etc/devbox/minimax.env 这个路径,不出现 key 本身。
验收:容器里 claude -p "回复 OK" 能拿到 MiniMax 的响应;/status 显示的模型是 MiniMax-M3。
动手前先去 MiniMax 控制台确认计费模式(§5 坑三)。
settings.json / CLAUDE.md / commands/ / agents/ 放进一个 git repo,容器启动时 symlink 进 ~/.claude/,可版本化。CLAUDE.md 里写死"不要 git push"(§6)。加 Stop hook 通知。
ANTHROPIC_BASE_URL 填哪个(§5 坑一)api.minimaxi.com 的连通性与延迟docker-ce 在 Alibaba Cloud Linux 4 上的确切安装路径(仓库可能要手动加)ghcr.io / registry-1.docker.io 的出网是否通畅