claude-pod:为 Claude Code CLI 提供 Docker 沙箱
Claude-Pod
开发者 trekhleb 发布 claude-pod,用 Docker 容器运行 Claude Code CLI,只挂载启动时所在的项目文件夹,主目录、SSH 密钥和其他项目都不进容器,因此可以配合 --dangerously-skip-permissions 使用。
Claude Code CLI 的 Docker 沙箱。针对一个项目文件夹运行 Claude——包括使用
--dangerously-skip-permissions时——同时你的主目录、SSH 密钥和其他项目对容器保持不可见。非官方。
TL;DR
claude-pod 在 Docker 容器内运行 Claude Code,并挂载你启动它时所在的项目文件夹。Claude 可以读取和编辑该文件夹;你机器的其余部分——主目录、SSH 密钥、其他项目、宿主 shell——不会被挂载,因此容器看不到它们。
它在两种情况下有用:
- 配合
--dangerously-skip-permissions:你获得自动批准,而无需让 Claude 访问你的整台机器。 - 在正常的逐条提示模式下:容器仍然限制了影响范围,因此过于宽泛的命令、提示注入或恶意依赖都无法触及项目文件夹之外。
它不是完全隔离——以下是边界:
- ✅ 启动文件夹之外不可访问。 你的主目录、
~/.ssh、~/.aws、其他项目以及宿主 shell 都不会被挂载,因此容器看不到它们。 - ⚠️ 启动文件夹内部完全暴露。 其中的任何
.env、.git/config或密钥都可读可写;出站网络是开放的,因此内容可能被读取或外泄;并且你的 Anthropic 登录信息存储在宿主机上的~/.claude-pod/下。 - 🚫 不要从
~或/或其他敏感文件夹启动。 那会把你的整个主目录或文件系统挂载进容器,从而失去意义。
实际效果:最坏情况从“你的整台机器”缩小到“这一个文件夹”,而后者可以从 git 恢复。
# Clone this repo once, anywhere you like (~/tools/claude-pod is just an example) git clone https://github.com/trekhleb/claude-pod.git ~/tools/claude-pod # Build the image (once) — runs from anywhere, no cd needed ~/tools/claude-pod/install.sh # cd into your project, then launch Claude cd ~/projects/your-project ~/tools/claude-pod/claude-pod claude --dangerously-skip-permissions # Long path? You can alias it — see "Aliases" below. # Forgot a command later? Print a copy-pastable cheatsheet of all of them ~/tools/claude-pod/claude-pod --help
唯一的要求是 Docker——你的宿主机上不需要 Node.js、npm 或 claude。完整的威胁模型和四文件设计,请参阅 Security and limits。官方方案请参阅 Anthropic 的 Claude Code sandboxing documentation。
目录
用法
要求
只需要 Docker。 Claude Code 在容器内运行,而不是在你的宿主机上——你不需要在机器上安装 Node.js、npm 或 claude CLI。除一个状态文件夹(~/.claude-pod/)外,宿主机保持原样,该文件夹的存在只是为了在容器重启之间保留你的登录状态。
运行 claude-pod
从任意项目中使用完整或相对路径调用该脚本:
cd ~/projects/anything ~/tools/claude-pod/claude-pod
你会进入一个 bash shell,位于项目在宿主机上的同一路径(例如 /Users/you/projects/anything),其中 claude 位于 PATH。你可以随意运行它:
claude --dangerously-skip-permissions
或者,你可以跳过 shell,直接进入 Claude。你传给 claude-pod 的任何内容都会在容器内运行,而不是 bash。因此,这一条命令会直接把你带入 Claude,并在 Claude 退出时退出容器:
~/tools/claude-pod/claude-pod claude --dangerously-skip-permissions要退出,请输入 exit。
以后忘了某个命令?随时运行 ~/tools/claude-pod/claude-pod --help(或 -h)——它会打印一份可复制粘贴的速查表,包含所有命令(run、install、update、uninstall、options),并带有适合你安装的正确绝对路径。
别名
为方便起见,你可以向 shell 配置文件(~/.zshrc、~/.bashrc 等)添加一个别名:
alias claude-pod=~/tools/claude-pod/claude-pod
这是 shell 优先的形式:claude-pod 会把你放进容器,并在 PATH 上运行 claude,因此你可以运行 npm install、开发服务器或测试,然后自己启动 claude——全部都在沙箱内完成。当你把命令传进去时,同一个别名也会直接进入 Claude:claude-pod claude --dangerously-skip-permissions。
首次启动(登录)
第一次在 pod 内启动 Claude 时,它会打印一个登录 URL。在你的宿主机浏览器中打开它,完成登录,把验证码粘贴回容器,就完成了。会话会持久保存在 ~/.claude-pod/ 中,并且在容器重启后依然存在——每台机器你只需做一次。
暴露端口
默认情况下,claude-pod 不会向宿主机发布任何端口(出站流量仍然不受限制——参见 什么被隔离,什么不被隔离)。通过 PORTS 环境变量映射端口:
# Map a single port (127.0.0.1:3000 -> container:3000) PORTS=3000 claude-pod # Map multiple ports PORTS="3000 5173" claude-pod # Map a specific host port to a different container port PORTS="8080:80" claude-pod # Or, alternatively, without using aliases PORTS="5173:5173" ~/tools/claude-pod/claude-pod
在容器内将你的开发服务器绑定到
0.0.0.0,而不是localhost。 大多数开发服务器默认绑定到localhost,这意味着它们只监听容器自身的回环地址——即使设置了PORTS=...,你的宿主机浏览器也无法访问它们。常见修复方法:
- Vite:
npm run dev -- --host(或vite --host 0.0.0.0)- Next.js:
next dev -H 0.0.0.0- Create React App / webpack-dev-server:
HOST=0.0.0.0 npm start- Django:
manage.py runserver 0.0.0.0:8000- Rails:
rails s -b 0.0.0.0宿主机侧的映射仍然只限于
127.0.0.1(由claude-pod强制),因此在容器内绑定0.0.0.0不会把你的开发服务器暴露到局域网。
粘贴图片和截图
Claude 只能读取位于项目文件夹内部的文件——那是唯一被绑定挂载到容器中的目录。你桌面或下载文件夹中的图片没有被挂载,因此直接从那里粘贴会给 Claude 一个它无法访问的路径。正是这种隔离让你的机器其余部分对容器保持私密(什么被隔离,什么不被隔离);下面这点小麻烦,就是为不暴露那些默认位置所付出的代价。
变通方法:
- 像平常一样截图(它会落在桌面上,或者你的操作系统放置它的任何位置)。
- 把文件复制到你的项目文件夹中——其下任意位置都可以,例如一个
tmp/子文件夹。 - 从项目内的新位置重新复制该文件,这样剪贴板上的路径就指向实际同步到容器中的那个副本。
- 粘贴到 Claude 中。现在该路径在容器内可以解析,图片也能被识别。
更新或固定 Claude Code 版本
默认情况下,install.sh 会获取 npm 上当前 latest 的任何版本,绕过 Docker 对该步骤的缓存。它会解析自身位置,因此你可以从任何文件夹重新运行它:
~/tools/claude-pod/install.sh要固定特定版本,请设置 CLAUDE_CODE_VERSION:
CLAUDE_CODE_VERSION=2.0.0 ~/tools/claude-pod/install.sh固定版本在重新构建时会正常缓存。脚本会在每次构建后打印解析出的版本,因此你始终知道自己得到的是什么。
自定义镜像
该镜像有意保持最小化:node:24-slim + git + curl + less + jq + gh + Claude Code。没有任何特定语言的内容。你的项目需要的任何东西(Python、构建工具、其他工具链)都由你自己添加——编辑 Dockerfile 并重新运行 ~/tools/claude-pod/install.sh。
安全与限制
它实际做什么
整个工具只有四个小文件:
Dockerfile—node:24-slim+git+curl+less+jq+gh+@anthropic-ai/claude-code。claude-pod— 一条docker run命令,挂载你当前目录(外加一个用于登录和历史的小状态目录),不挂载你机器上的其他任何东西。install.sh— 检查 Docker 并构建镜像。不触碰任何系统路径;该工具保持自包含在这个文件夹中。uninstall.sh— 确认后删除镜像和~/.claude-pod/(认证 + 会话历史)。它会列出未触及的内容,以便你自行清理。
什么是隔离的,什么不是
Claude 无法触及:
- 你启动时所处项目文件夹之外的一切。
~/.ssh、~/.aws、~/.zshrc、浏览器数据、其他项目——全都无法访问。 - 宿主机 shell。无法在你的宿主机上执行命令。
仍然暴露:
- 项目文件夹本身。其中的任何内容——
.env、.git/config(可能携带私有远程仓库的凭据)、误提交的私钥、node_modules、同级工作树、临时文件——都可被容器中运行的代码完全读取和写入。不要从这样一个文件夹运行claude-pod:其内容你不放心让 AI(或它刚安装的恶意依赖)看到并修改。 - 网络。默认出站不受限制。恶意载荷可能窃取项目内容或耗尽你的 Anthropic API 配额。如需离线工作,可以用
NET=none完全切断网络(参见 网络隔离与资源限制),但这也会让 Claude 本身离线——没有内置的出站允许列表能在保持 Claude 在线的同时阻止其他一切。 - 你的 Anthropic 登录信息(存储在宿主机的
~/.claude-pod/中,与宿主机上安装的任何 Claude 分开,在沙箱项目间共享)。
Claude 实际可写入的位置——两条路径,均为有意设置的绑定挂载:
- 项目文件夹,以相同路径绑定挂载到容器内(
$PWD:$PWD)。编辑直接落到宿主机磁盘上,无需复制。 - 宿主机上的
~/.claude-pod/,挂载到/home/claude-pod/.claude。存放认证令牌和会话历史。
由于当前目录(
$PWD)被挂载进容器,避免从根目录(/)或/etc等敏感目录运行此工具。在这些情况下,你是在让 AI 访问你的整台机器或其他敏感数据,违背了沙箱的初衷。务必先cd进入你的具体项目文件夹。
Claude 写入的其他所有位置,要么位于容器的临时文件系统中(退出时因 --rm 而丢弃),要么根本没有路径可落——Linux 内核的挂载命名空间使任何其他宿主机目录对容器不可见。项目文件夹内指向 ~/.ssh 或 /etc/passwd 的符号链接同样会显示为失效:这些目标未被挂载,因此容器看不到它们。
硬链接则不同。硬链接是同一文件系统上现有 inode 的第二个名字。如果你项目文件夹内的某个文件与同一文件系统上别处的敏感文件(例如
~/.ssh/id_rsa)存在硬链接,容器可以通过该硬链接访问它——绑定挂载暴露的是 inode,而不仅仅是路径。这要求该硬链接已存在于项目文件夹中,因此只有在你检查来自不受信任来源的代码时才是真正需要担心的问题。对待不熟悉的项目,要像直接运行其代码一样谨慎:不要在你无法信任的文件夹内运行claude-pod。
权衡之处在于:最坏情况变成了“某个项目文件夹出了事”,这可以从 git 恢复,而不是“我的整个主目录都暴露了”。
网络隔离与资源限制
默认情况下,容器具有不受限制的出站网络(Claude 需要 api.anthropic.com,你的构建需要 npm/pip 等),并且进程上限很宽松。当你准备让 Claude 处理来自不受信任来源的代码时,你可以通过环境变量进一步收紧限制——所有这些变量都只是给同一个 docker run 添加标志,其他什么都不变:
# Cut ALL networking for the run. A malicious payload can't exfiltrate the project or phone home. # Note: Claude itself can't reach Anthropic with no network, so this is for offline shell/build # work (inspecting or building untrusted code), not for a live Claude session. NET=none claude-pod # Cap memory and CPU so a runaway or malicious build can't exhaust the host (recoverable via OOM, # but disruptive). No default cap — a fixed limit would kill legitimate large builds. MEMORY=4g CPUS=2 claude-pod # Lower the process/thread cap when running untrusted code (default is 4096, generous for builds). PIDS=512 claude-pod
NET=none 和 PORTS 互斥——没有网络的容器无法发布端口。--pids-limit 始终会被应用(它包含 fork 炸弹,而被丢弃的能力无法阻止这些);如果高度并行的构建触及上限,请提高 PIDS=。
项目文件夹之外的副作用
这个仓库在你启动它的项目之外所导致存在的一切:
- 你主机上的
~/.claude-pod/——认证令牌、设置,以及每个项目的会话/对话历史(记录可能包含 Claude 看到的代码片段和命令输出)。认证和设置跨项目共享(一次登录,永久有效);会话历史位于~/.claude-pod/projects/<encoded-host-path>/下,每个项目一个文件夹,使用与主机版 Claude 相同的编码——所以如果你以后切换到主机安装,你可以把这些文件夹复制过去并保留你的记录。这不是主机版 Claude 安装;它是容器内 Claude 的状态目录,保存在主机上以便在重启后保留。 - Docker 镜像
claude-pod及其层,加上node:24-slim基础镜像,位于 Docker 的镜像存储中。 - 来自
apt-get和npm install步骤的 Docker 构建缓存。 - 构建期间的出站网络:Docker Hub、Debian apt 镜像、npm registry。运行期间:
api.anthropic.com以及你的项目代码所访问的任何内容(网络不受限制)。 - 会话运行期间:一个容器进程,以及你通过
PORTS显式映射并在127.0.0.1上绑定的任何端口。
没有 sudo,不会写入 /usr/local/、/etc/、~/.zshrc、~/Library/、你现有的 ~/.claude/ 或主机上的任何其他地方。
参考
平台
该包装器是可移植的 POSIX bash + Docker。它应该能在任何装有较新 Docker 的主机上运行:
- macOS(Apple Silicon 和 Intel)配合 Docker Desktop、OrbStack 或 Colima——主要开发目标。
- Linux 配合 Docker Engine 或 Docker Desktop——绑定挂载和
--userUID/GID 在这里直接映射,是最原生的体验。 - Windows + WSL2 配合 Docker Desktop 的 WSL2 后端——在 WSL 发行版的 bash shell 内运行
claude-pod。
原生 Windows(cmd.exe / PowerShell)不受支持。该包装器是一个 bash 脚本并使用 POSIX 工具(id 等);请改用 WSL2。
如果某个平台的行为不符合预期,请提交 issue。
卸载
~/tools/claude-pod/uninstall.sh确认后移除 ~/.claude-pod/ 和 claude-pod 镜像。它会明确告诉你它没有触碰什么(node:24-slim、构建缓存、此仓库)以及如何自行清理这些内容。
如果你为了方便添加了 shell 别名(例如 ~/.zshrc / ~/.bashrc 中的 alias claude-pod=...),也请删除那一行——uninstall.sh 不会触碰你的 shell rc 文件。
许可证和商标
此仓库中的代码在 MIT 许可证下发布——完整文本见 LICENSE。
Claude Code 本身是 Anthropic, PBC 拥有的独立产品,不由本项目再分发——install.sh 在构建时从 npm 获取它。本项目与 Anthropic, PBC 无关联、未获其认可或赞助。“Claude”和“Claude Code”是 Anthropic, PBC 的商标,此处为指称性引用。未使用任何 Anthropic 徽标、字标或其他品牌资产。
来源:Hacker News · github.com
