Skip to content
返回

Claude Desktop 沙箱踩坑记录

前面陆陆续续写了好几篇跟 Claude Desktop 沙箱有关的文章——npm run dev 跑不起来github.com 被挡gh 报 TLS 错——一篇一个坑,翻起来零散。这篇把它们汇到一处,按「该改哪个配置」重新整理一遍,当成一份速查清单。

先理清三个概念

后面要反复提到「设置文件」,先把它们和承载它们的环境讲清楚,免得绕晕。

Claude Desktop 内部跑的是 Claude Code。 Claude Desktop 是官方桌面客户端,但它干活的内核就是 Claude Code——和你在终端里敲的那个 CLI 是同一套东西,只是换了层 GUI 外壳。所以 Claude Code 的那套配置(包括沙箱配置)在 Claude Desktop 里照样生效,下面说的「设置文件」指的都是 Claude Code 的设置文件。

它有两级设置文件,作用范围不同:

一句话约定:除非某条特别声明,下面提到的沙箱设置在用户级和项目级两个文件里都能生效,配哪个看你想要的作用范围。例外情况我会在对应的小节里会单独点出来。

坑一:别让它「绕过」沙箱,让它停下来告诉你

这是最该先立的规矩,跟具体配置无关,但不立好后面全是坑。

Claude 撞上沙箱限制时,默认行为是自己想办法绕过——比如写文件被拒就换个目录写、命令被挡就换个等效命令。听上去挺机灵,实则常常坏事:它绕过去之后任务看着「成功」了,实际执行得不彻底、或者悄悄缺了一块,而你根本不知道它中途拐了个弯。

我的做法是在 CLAUDE.md 里立一条硬规矩:不准擅自绕过沙箱限制。一旦因为沙箱失败,必须停下来,明确告诉我到底是什么被拦了——是哪个文件的路径、哪个域名、还是哪条具体命令,连同报错一起报上来——然后由我来决定是去加白名单 / 改配置,还是这次确实可以让它绕过。

把决定权收回到自己手里,比事后发现任务做漏了再返工省事得多。我用的规则大致是这样:

当某个操作因为沙箱限制而失败时(文件写入被拒、域名不可达、
命令被拦等),不要直接放弃,也不要擅自换路径绕开,而要:

1. 先讲清楚到底是什么被拦截了:明确告诉我被拦的文件绝对路径、
   域名地址或具体命令,并附上失败的报错。
2. 然后停下来问我,给我两个选项:
   a. 我已经把它加入白名单了 —— 选 a 时你重新尝试刚才被拦的操作。
   b. 你来绕过这个限制 —— 选 b 时你换一种方式达到同样目的。
3. 在我做出选择之前,不要擅自重试,也不要擅自换方式,等我回复。

立好这条之后,下面四个坑才轮得到「改哪个配置」这一步——因为它会老老实实把被拦的东西报给你,而不是闷头绕过去。

坑二:npm run dev 监听端口失败

前端开发离不开 dev server,但沙箱默认禁止进程 bind / listen 本地端口npm run dev 一起来就被挡(典型报错 listen EPERM)。之前那篇详细记过,这里给当前推荐的解法。

开启 Preview MCP。 它一般是默认开着的;如果没开,去 Claude Desktop Settings → Claude Code 里打开。开启后 Claude Desktop 会注入一组 Preview 工具,AI 用它来跑 npm run dev 并直接打开页面——类似 Playwright / 浏览器 MCP 那种能访问页面、截图、读 console 的工具。dev server 不在 bash 沙箱里起,自然就绕开了「禁止监听端口」这道墙。

一个容易忽略的后续:即便 Preview 把 dev server 跑起来了,你在沙箱里 curl http://localhost:3000 照样会报错。原因是沙箱内的回环和 dev server 所在的网络环境不是同一个。要让沙箱内能访问到本地端口,得把 sandbox.network.allowLocalBinding 设成 true

{
  "sandbox": {
    "network": {
      "allowLocalBinding": true
    }
  }
}

坑三:域名白名单——allowDomains 在设置文件里无效

这是第一个例外。 想给沙箱放行某个出站域名,你可能会去设置文件里写 sandbox.network.allowDomains——别白费劲,它在用户级和项目级文件里都不生效

真正管事的开关在 Claude Desktop 的图形界面里,路径是:

Inference configuration → Workspace restrictions → Allowed egress hosts

沙箱默认只放行推理(inference)那一个端点,其余出站一律 403——所以连 npm 装包、git push、抓个文档都会挂。要放行就在这里按域名加。几个常用的:

用途要加的域名
npm 装包registry.npmjs.orgregistry.npmmirror.com
GitHub 相关github.com*.github.com
Shadcn CLI 读文档ui.shadcn.com

这里有个匹配规则的小坑:通配符不匹配顶级域本身*.github.com 能匹配 api.github.com,但匹配不到 github.com 这个 apex,而 git push 走的恰恰是 apex——所以 github.com*.github.com两条都加。这个坑单独写过一篇,含来龙去脉。

坑四:excludedCommands 把命令整个放出沙箱

有些命令不是缺个域名或端口,而是在沙箱里压根跑不通——这时候按域名、按端口精修都没用,直接把整条命令丢到沙箱外去跑最省事。这就是 sandbox.excludedCommands

{
  "sandbox": {
    "excludedCommands": ["gh *", "docker *", "npm *"]
  }
}

匹配规则是命令前缀,gh * 覆盖 gh pr creategh api 等所有子命令。三个最常用的:

excludedCommands 有个很顺手的优点:即时生效、不用重启会话,即便开了严格沙箱模式也照样管用。

坑五:文件写权限——相对路径只认项目级文件

这是第二个例外。 sandbox.filesystem.allowWrite 用来放行沙箱内的文件写入,但它对路径的写法挑环境:

// ./.claude/settings.local.json —— 相对路径要写在项目级
{
  "sandbox": {
    "filesystem": {
      "allowWrite": [".git/config"]
    }
  }
}

顺带一提:git push 报的 could not write config file .git/config: Operation not permitted 就是这个坑的典型表现——分支其实已经推上去了,只是 upstream tracking 没写成。要么按上面放行 .git/config,要么干脆用坑四的 excludedCommandsgit * 把 git 整个放出沙箱,文件写和网络两层一起绕开。

速查表

最后压缩成一张表,按症状找配置:

症状改哪里怎么改
它闷头绕过沙箱、任务做漏CLAUDE.md立规矩:不准绕,停下来报被拦的文件 / 域名 / 命令
npm run dev 起不来设置 + 设置文件开 Preview MCP;沙箱内要访问本地端口再加 network.allowLocalBinding: true
域名 403、装包 / push 连不上Claude Desktop UIAllowed egress hosts 里按域名加(设置文件里的 allowDomains 无效)
某命令在沙箱里跑不通 / 装包要域名要写缓存(ghdockernpm…)设置文件excludedCommands"命令 *"npm * 还能顺带解决 tsx 等子进程 listen socket)
写文件被拒(如 .git/config项目级设置文件filesystem.allowWrite 加路径(相对路径用户级不生效)

分享这篇文章:

下一篇
Claude Desktop 里 gh 报 TLS 错的原因与解法