devbox — 部署结构 & 操作手册

远端按需拉起隔离开发容器 · claude 跑在容器里 · 合盖离开不中断 · 纯命令行
myserver-sg · 8.222.155.72 2C / 4G MiniMax-M3 Python · Java · 无语言 最后更新 2026-07-09

这台机器同时跑着生产站点 jinghao.site。整套 devbox 与它并存,全程守着一条底线:宁可 devbox 自己撞内存墙,也绝不拖垮 nginx。核心机制只有两块基石 —— Docker + tmux —— 外加一个把它们缝起来的薄脚本。全部可读、可改、可接管。

⚡ 常用命令速查

命令里的 myserver-sg 就是这台机器(新加坡,8.222.155.72)。

开工:选/建项目,落进 tmuxssh -t myserver-sg dev
起 claude(跳过权限,在 tmux 里敲)claude-go
离开但不中断Ctrl-b 松手 d
回来接着干ssh -t myserver-sg dev → 选项目
新建指定语言容器devbox up <proj> python|java|none
列出所有项目 / 语言ssh myserver-sg devbox ls · … devbox langs
停容器(留数据)ssh myserver-sg devbox down <proj>
删容器+卷(留代码)ssh myserver-sg devbox nuke <proj>
铁律

离开 tmux 用 detach(Ctrl-b d),绝不用 exit —— 会杀掉会话 / 打断 claude。

目录
  1. 一句话总览
  2. 四层模型
  3. 三层持久化
  4. 镜像
  5. 目录 / 卷 / 认证
  6. 资源与安全护栏
  7. 文件清单
  8. 操作:一条命令入口
  9. 操作:devbox 命令表
  10. 操作:claude-go 一键起
  11. 操作:tmux 必修
  12. 典型的一天
  13. 代码怎么进 / 端口怎么出
  14. 加一门新语言
  15. 故障恢复

1一句话总览

从冷笔记本到「容器里正在跑的 claude」,一条命令:

ssh -t myserver-sg dev        # 弹菜单:选语言 + 项目名 → 落进 tmux → 敲 claude-go

派完活按 Ctrl-b d 离开(或直接合盖),claude 在容器里继续跑。回来再 ssh -t myserver-sg dev 选同一项目,接回原会话。

2四层模型 —— 你操作时始终在其中一层

从外到里,每下一层多一层隔离。任何时候拿不准「我在第几层」,敲 hostname && whoami

┌─ Layer 0  你的笔记本 (Windows / PowerShell)
│     │  ssh -t myserver-sg
│     ▼
├─ Layer 1  宿主机   root@阿里云ECS        ← Docker 住这层;生产站点也在这
│     │  docker exec  (devbox 替你做)         这层能 docker ps
│     ▼
├─ Layer 2  容器     dev@devbox-<proj>      ← 隔离沙箱:独立文件系统 / 用户 / 内存封顶
│     │  tmux attach  (devbox 替你做)         这层 docker ps 会 command not found
│     ▼
└─ Layer 3  tmux 会话 "main"                 ← 常驻层:断开不死,claude 跑在这
你是谁进入方式退出方式
1 宿主机rootssh myserver-sgexit → 回笔记本
2 容器devdocker exec -it -u dev devbox-<proj> bashexit → 回宿主机
3 tmuxdevtmux attach -t mainCtrl-b d(detach,别 exit)

3三层持久化 —— 为什么合盖不丢

是什么它挡住的杀手
L1tmux server 跑在容器内SSH 断开只是 detach;claude 收不到 SIGHUP,继续跑
L2容器 PID1 = sleep infinityclaude 崩了/退了,容器不跟着死
L3~/.claude 挂具名卷容器重建,会话历史与登录态照样在

4镜像 —— 方式A:每语言一个预构建镜像

FROM devbox-base,所以 tmux / git / claude-code / claude-go / dev 用户全部共享继承。

镜像语言内含
devbox-base:latest无语言 / 仅 claudenode:22-slim · tmux · git · claude-code 2.1.204 · ripgrep/fd/jq · claude-go
devbox-python:latestPythonbase + Python 3.11.2 · pip · venv · build-essential
devbox-java:latestJavabase + Temurin JDK 21.0.11 (LTS) · Maven 3.9.9
提示

语言在创建容器那一刻定死(devbox up <proj> python);之后 up/attach 都不用再写语言。devbox langs 看有哪些语言可用。

5目录 / 卷 / 认证

东西宿主机容器内说明
代码/srv/dev/<proj>/workspaces/<proj>同一份文件(bind mount),属主 1000:1000
claude 状态具名卷 devbox-claude-<proj>/home/dev/.claude会话历史 / 登录态(L3)
MiniMax 密钥/etc/devbox/minimax.env运行时注入为环境变量chmod 600 · root:root · 不烘焙进镜像

认证走 MiniMax(非 Claude 官方账号):ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic,模型 MiniMax-M3。每次 docker run --env-file 注入,容器里没有任何 Anthropic 凭证。

6资源与安全护栏

护栏设置为什么
内存硬顶--memory=1g --memory-swap=3g容器最多 1g 常驻 + 2g swap;撞墙也伤不到 nginx
OOM 优先级容器 -500 · nginx -900内存不够时,先杀杂项 > 再杀 agent > 最后才 nginx
端口绝不 publish 到 0.0.0.0dev server 一律走 ssh -L 隧道(见 §13)
容器存活--restart unless-stopped机器重启后容器自启(已实测跨 resize 生效)

7文件清单 —— 都是纯文本,可读可改

用途服务器上本地源
生命周期脚本/usr/local/bin/devboxD:\code\private_site\devbox\devbox
交互式前台/usr/local/bin/devD:\code\private_site\devbox\dev
一键起 claude镜像内 /usr/local/bin/claude-go(写在 base Dockerfile 里)
base 镜像/srv/devbox/base/DockerfileD:\code\private_site\devbox\Dockerfile
语言镜像/srv/devbox/langs/Dockerfile.{python,java}D:\code\private_site\devbox\langs\
密钥/etc/devbox/minimax.env(只在服务器,不进版本库)

笔记本 ~/.ssh/config 里,本文所有命令的 myserver-sg = root@8.222.155.72(新加坡这台,装了 devbox)。另有 myserver-bj = 8.141.92.77,是另一台机器、没装 devbox,别搞混。密钥 id_ed25519;VS Code / 命令行 ssh 读同一份。


8操作:一条命令入口

日常就用这一条,弹菜单:

ssh -t myserver-sg dev
════════════  devbox 交互启动  ════════════
现有项目:
    1) myapp                [python, running]
    2) svc                  [java, exited]
    n) 新建一个
    q) 退出
选择(编号/n/q): 1
→ 接入 myapp …
   [落进容器里的 tmux "main"]

没有项目时直接进新建流程(选语言 → 输项目名 → 建好并接入)。-t 不能漏 —— tmux 需要一个真终端。

9操作:devbox 命令表

知道自己要什么时,直接调,比菜单快。都能 ssh myserver-sg devbox … 远程执行(要落进 tmux 的加 -t)。

命令做什么
devbox up <proj> [python|java|none]起容器 + 建 tmux main(已存在则不动)。语言只在首次创建时用
devbox attach <proj>接进 tmux;断开=detach,容器内进程继续跑(配 ssh -t
devbox ls列所有项目:语言 / 状态 / 内存 / tmux 会话
devbox langs列可用语言镜像
devbox shell <proj>开个纯 bash(绕过 tmux,调试用)
devbox down <proj>停容器,保留卷(历史 / 登录态都在)
devbox nuke <proj>删容器 + 删卷;代码目录 /srv/dev/<proj> 不动

10操作:claude-go 一键起 claude

接进 tmux 后,一句话以 skip-permission 起 claude,不用手敲长参数:

claude-go
你在哪跑它怎么做
已在 tmux 里(attach 之后,最常见)当前窗口直接起 claude --dangerously-skip-permissions;claude 退出后回到 shell,会话不散
不在 tmux 里(如 devbox shell 进去)自动建 main + 在里面起 claude + 接入
附带好处

万一手滑把 main 会话 exit 没了 —— 从容器里(非 tmux)敲一句 claude-go,就能重建 main 并起 claude,一步到位。

11操作:tmux 必修(只需两个动作)

想干什么敲什么结果
进去(接上 claude)tmux attach -t main
走人(留着它继续跑)Ctrl-b 松手 ddetach,claude 继续跑 ✓
铁律

离开 tmux 永远用 detach(Ctrl-b d),绝不用 exitexit 会杀掉当前 shell —— 空会话会被带走,有 claude 会被打断。往回翻历史用鼠标滚轮(已开 mouse on)。

12典型的一天

# 早上,开工
ssh -t myserver-sg dev            # 菜单选 myapp(或新建)→ 落进 main
claude-go                      # 起 claude,派活
#   … 给 claude 交代任务 …
Ctrl-b d                       # 合盖走人;claude 在容器里继续跑

# 中午回来,换了个地方
ssh -t myserver-sg dev            # 选 myapp → 回到 main → claude 还在原地,接着看

# 晚上,收工但想让它夜里接着跑
Ctrl-b d                       # 只 detach,别关容器
#   (若配了完成通知,跑完会推手机)

# 某天这个项目不要了
ssh myserver-sg devbox nuke myapp # 删容器+卷;/srv/dev/myapp 代码仍在

13代码怎么进 / 端口怎么出

代码进容器

容器内 /workspaces/<proj> 就是宿主 /srv/dev/<proj>,同一份文件。直接在里面 git clone:

cd /workspaces/myapp && git clone <你的仓库> .

dev server 端口出来(不 publish,走 ssh 隧道)

比如容器里跑了个服务在 :5173,想在笔记本浏览器看:先把宿主的端口转出来,再从宿主转进容器。最简单是让服务监听容器的 0.0.0.0,然后:

# 笔记本上另开一个终端
ssh -L 5173:localhost:5173 myserver-sg
# 然后在宿主再 -L 到容器,或直接用 docker 的端口——但本方案约定:
# 服务绑容器 0.0.0.0:5173,宿主用 docker exec 转发/或临时 -p 仅供本机,
# 对外一律只经 ssh 隧道,绝不 0.0.0.0 直接暴露。
注意

容器永不 -p 到公网。要看 dev server,用 ssh -L 把流量隧道回笔记本。需要时告诉我,给你把某个项目的隧道命令固化下来。

14加一门新语言(比如 Go / Rust)

三步,跟你说一声我就做:

  1. langs/Dockerfile.python 的模式写一个 Dockerfile.goFROM devbox-base + 装 Go)
  2. 服务器上 docker build -t devbox-go:latest -f Dockerfile.go .(一次)
  3. devbox 脚本的 image_for_lang() 里加一行 go) echo 'devbox-go:latest';;

之后 devbox up proj go 就能用。dev 菜单里也加一个选项即可。

15故障恢复速查

症状怎么办
手滑 exit 把 main 弄没了容器里敲 claude-go(非 tmux 分支会重建 main 并起 claude);或宿主 devbox up <proj> 重建空会话
合盖回来连不上ssh -t myserver-sg dev 选那个项目即可;容器 --restart 会自启
docker ps 看不到容器你多半在容器终端里敲的 —— 容器内没 docker。请在宿主 root
重连后窗口缩成一小格正常:断连留了孤儿 client。devbox attach 已自动踢掉它,重连即好
容器停了想恢复(保数据)devbox up <proj>docker start 它,卷和会话都在
确认站点没被影响宿主 curl -s -o /dev/null -w '%{http_code}' https://jinghao.site/ 应为 200
devbox 手册 · 生成于 2026-07-09 · 本地文件,未上传服务器 / 外网
未做:完成通知(agent 跑完推手机)—— 待办 #8