Claude Code 服务器部署:Bun 运行时与飞书 AI Agent 生产实践

📅 2026/7/11 3:27:33
Claude Code 服务器部署:Bun 运行时与飞书 AI Agent 生产实践
1. 先厘清一个根本误区Claude Code 不是能“部署到服务器”的传统软件很多人看到“Claude Code 服务器部署”这个搜索词第一反应是下载一个安装包扔进云服务器执行./install.sh然后systemctl start claude-code—— 完事。我试过也踩过坑结果发现这从根上就错了。Claude Code 本质上不是一个可独立分发、自带运行时的二进制程序。它没有官方 Linux ARM64 或 x86_64 的预编译 release也没有 Docker Hub 官方镜像。你在网上搜到的所谓“Claude Code 安装包”99% 是社区魔改版、旧版 fork或是把前端 UI 和后端代理硬凑在一起的半成品。直接在服务器上curl -L https://xxx/codex-linux.tar.gz | tar xz然后./claude-code大概率会遇到error: failed to execute bun: spawnSync bun ENOENT这类报错——不是你的服务器坏了而是整个执行链路缺了最关键的一环Bun 运行时本身就没装上。这背后是一个被严重低估的事实Claude Code 的核心依赖不是 Node.js而是 Bun。而 Bun 的安装在服务器环境里远比在 macOS 或 Windows 上麻烦。它不像apt install nodejs那样一行命令搞定。Bun 官方不提供.deb或.rpm包也不进主流发行版的仓库。你得手动下载、解压、加 PATH还得确认 glibc 版本兼容性。我在一台腾讯云 Ubuntu 22.04 服务器上就因为系统自带的 glibc 2.35 和 Bun 1.1 要求的 2.38 不匹配卡了整整一个下午。最后发现必须先升级系统内核和 libc或者干脆换用较新的 Ubuntu 24.04 镜像——这种底层细节官方文档里根本不会提但却是你能否跑起来的第一道生死线。所以“部署 Claude Code 到服务器”这个动作准确来说应该是在目标服务器上构建一个稳定、可复现、能长期运行的 Claude Code 执行环境并将其桥接到一个可被外部如飞书安全调用的 API 网关或消息通道中。它不是部署一个应用而是搭建一条“AI 编程能力输送管道”。管道的入口是飞书群聊里的/new chat出口是服务器上那个默默运行、调用 Claude API 的 Bun 进程。中间所有环节——Bun 的安装、工作目录的权限、API Key 的安全存储、进程守护、日志轮转、超时熔断——都得你亲手拧紧螺丝。这不是一键部署而是一场基础设施级的工程实践。提示如果你只是想在自己电脑上用 Claude Code直接去官网下载桌面版即可完全不需要碰服务器。本文讨论的是那种“团队共用一个 Claude Code 实例所有人通过飞书对话代码生成结果自动存入公司 Git 仓库”的生产级场景。目标不是“能跑”而是“跑得稳、管得住、查得清、扩得开”。2. 核心依赖链拆解Bun、Agent SDK 与 Lark Bridge 的三角关系要让 Claude Code 在服务器上真正“活”起来不能只盯着claude-code这个名字。它背后是一个精密咬合的三层依赖结构每一层出问题整个链条就断掉。我把它画成一张清晰的依赖图不是为了炫技而是为了让你在出问题时能立刻定位到是哪一环松了。2.1 第一层Bun —— 不是 Node.js 的替代品而是为 AI Agent 量身定制的引擎Bun 的定位常被误解为“更快的 Node.js”。这是大错特错。Node.js 是为通用 Web 服务设计的而 Bun 是为高频 I/O、短生命周期、高并发的 AI 工作流优化的。它的启动速度比 Node.js 快 3-5 倍内存占用低 40%这对 Claude Code 这种需要频繁创建/销毁会话、实时响应飞书卡片按钮点击的场景是决定性的。在服务器上安装 Bun绝不能用npm install -g bun这会失败也不能用curl下载后手动解压就完事。正确的姿势是# 1. 下载官方预编译二进制以 Ubuntu 24.04 x86_64 为例 curl -fsSL https://bun.sh/install | bash # 2. 这步极其关键它默认只写入当前用户的 ~/.bun/bin但系统级服务需要全局PATH # 所以必须手动软链接到 /usr/local/bin sudo ln -sf $HOME/.bun/bin/bun /usr/local/bin/bun # 3. 验证必须在 root 和普通用户下都生效 sudo -i -u your_app_user bash -c bun --version # 输出应为bun v1.1.25 (或更高) # 4. 检查 glibc 兼容性Ubuntu 22.04 用户必做 ldd $(which bun) | grep libc # 如果显示 not found 或版本低于 2.38说明必须升级系统或换镜像我踩过的最大坑就是跳过了第 2 步。bun命令在终端里能运行但当systemd服务以your_app_user身份启动时PATH 里根本没有/home/your_app_user/.bun/bin。结果服务日志里全是spawnSync bun ENOENT。这个错误信息极具迷惑性它让你以为是bun没装其实是bun在 PATH 里找不到。解决方法就是那条sudo ln -sf让bun成为系统级命令。2.2 第二层Claude Agent SDK —— 你和 Claude API 之间的“翻译官”与“守门员”很多人以为只要有了 Bun就能直接bun run claude-code。错。Claude Code 的核心逻辑是通过官方的anthropic-ai/agent-sdk来调用 Claude 的 API。这个 SDK 不是简单的 HTTP 封装它内置了三重关键能力会话状态管理自动维护conversation_id、message_id确保多用户并发时上下文不串。工具调用Tool Use编排当你在飞书里点“生成 PR 描述”按钮时SDK 负责把你的请求、当前 Git 仓库状态、PR diff 内容按 Anthropic 的严格 JSON Schema 组装好再发给 API。流式响应Streaming处理把 Claude 返回的delta字节流实时拼接、解析、并推送到飞书 WebSocket 连接实现“打字机”效果。这个 SDK 的版本必须和你使用的 Claude Code 前端 UI 严格匹配。我曾用anthropic-ai/agent-sdk0.7.0去对接一个基于0.5.0SDK 开发的 UI结果所有工具调用都返回400 Bad Request。查了 3 小时日志才发现是 SDK 新版强制要求tool_choice字段而旧版 UI 没传。最终解决方案不是降级 SDK而是给 UI 补了一个中间件自动注入缺失字段。这说明SDK 不是黑盒你必须理解它的协议契约。2.3 第三层Lark Coding Agent Bridge —— 把 AI 能力“翻译”成飞书语言的“外交官”这才是整个架构里最精妙、也最容易被忽视的一环。Lark Bridge 不是一个简单的反向代理。它是一个双向协议转换器输入侧它监听飞书发来的event_callback事件比如群聊里有人发/new chat。它把飞书的open_id、chat_id、msg_id、text转换成 Claude Agent SDK 能理解的user_id、session_id、prompt。输出侧它接收 SDK 返回的富文本内容Markdown、表格、JSON 卡片数据再调用飞书 OpenAPI把它们渲染成真正的飞书卡片、文档、或带按钮的交互消息。Bridge 的核心价值不在于“连上了”而在于“连得聪明”。比如当飞书用户在手机上语音输入一段模糊需求“帮我看看这个 Python 脚本为啥跑得慢”Bridge 会自动识别这是语音转文字触发voice_to_text工具把转出的文字加上#context: mobile_voice_input的前缀告诉 Claude 这是移动端场景启动一个带--timeout 120参数的专用会话防止语音识别延迟导致超时把最终结果用lark::card::rich_text格式发送确保手机端能正常渲染。这个过程全部由 Bridge 的配置文件bridge.config.json控制。里面有一段关键配置{ agent: { claude: { timeout: 120, max_retries: 3, tool_whitelist: [code_interpreter, git_status, voice_to_text] } }, lark: { message_format: rich_text, mobile_optimized: true, auto_create_doc: true } }如果你没配mobile_optimized: true那么在飞书 App 里收到的就永远是一大段纯文本而不是可折叠的代码块和带颜色的语法高亮。这就是为什么很多团队反馈“接入了但体验很差”——不是 Claude 不行是 Bridge 的“外交辞令”没说对。3. 从零构建生产环境服务器初始化、权限隔离与进程守护现在我们把前面两节的理论落地为一份可直接在阿里云 ECS 或 AWS EC2 上执行的、无废话的初始化脚本。这不是开发环境的玩具而是面向 20 人以上技术团队的生产环境方案。每一步我都标注了“为什么必须这样”以及“不这样做会怎样”。3.1 创建专用系统用户与安全沙箱绝对禁止用root或ubuntu用户来运行 Claude Code。这是安全红线。# 1. 创建无登录权限、无 shell 的专用用户 sudo useradd -r -s /bin/false -d /opt/claude-code claude # 2. 创建应用主目录并设置严格权限 sudo mkdir -p /opt/claude-code/{app,logs,workspaces,config} sudo chown -R claude:claude /opt/claude-code sudo chmod 750 /opt/claude-code sudo chmod 700 /opt/claude-code/{config,workspaces} # 3. 关键一步为 Bun 创建符号链接解决 PATH 问题 sudo ln -sf /home/claude/.bun/bin/bun /usr/local/bin/bun # 注意这里 /home/claude 是用户家目录不是 /opt/claude-code为什么必须用-r系统用户因为系统用户 UID 在 1-999 范围会被 SELinux/AppArmor 自动赋予更严格的沙箱策略。-s /bin/false确保它无法 SSH 登录杜绝了暴力破解风险。chmod 700对config目录是为了保护你的ANTHROPIC_API_KEY—— 这个密钥一旦泄露攻击者可以直接调用你的 Claude 配额产生真实费用。3.2 安装与验证 Bun一次到位拒绝“差不多”在claude用户环境下执行标准安装# 切换到 claude 用户 sudo -i -u claude # 1. 安装 Bun官方推荐方式 curl -fsSL https://bun.sh/install | bash # 2. 验证安装必须在用户环境下验证 bun --version # 应输出版本号 bun run https://bun.sh/hello-world # 应输出 Hello, World! # 3. 创建一个最小测试脚本验证 Bun 能否调用网络 echo console.log(await fetch(https://api.anthropic.com).then(r r.status)); test-fetch.js bun run test-fetch.js # 应输出 401未授权证明网络通如果报错 ENOENT则 PATH 仍有问题注意test-fetch.js的目的是验证 Bun 的fetchAPI 是否可用。Claude Agent SDK 的核心就是fetch。如果这一步失败后面所有步骤都是空中楼阁。我见过太多人跳过这步直接跑bun run app.js结果日志里全是fetch is not defined却还在怀疑是 SDK 问题。3.3 部署 Lark Bridge 并配置飞书应用不要git clone主分支。生产环境必须锁定 commit hash确保可回滚。# 仍在 claude 用户下 cd /opt/claude-code/app # 1. 克隆并检出已验证稳定的版本以 2024-10-15 的稳定版为例 git clone https://github.com/zarazhangrui/lark-coding-agent-bridge.git . git checkout 8a3f2c1d # 这是经过我们团队 3 周压力测试的 commit # 2. 安装依赖Bun 的优势在此刻体现快 bun install # 3. 复制并编辑配置文件 cp config.example.json config.json nano config.jsonconfig.json的关键字段必须如下配置{ lark: { app_id: cli_xxx, // 从飞书开放平台获取 app_secret: xxx, // 严格保密 verification_token: xxx, // 飞书事件订阅所需 encrypt_key: xxx // 如启用加密必须填 }, anthropic: { api_key: sk-ant-api03-xxx, // 你的 Anthropic API Key base_url: https://api.anthropic.com/v1 // 生产环境必须显式指定 }, server: { port: 3001, // 不要用 3000避免与 Node.js 冲突 host: 127.0.0.1 // 只监听本地由 Nginx 反向代理 } }为什么host必须是127.0.0.1因为直接暴露0.0.0.0:3001到公网等于把你的app_secret和api_key放在门口。所有流量必须经由 Nginx 做 TLS 终止、IP 白名单、速率限制。这是生产环境的铁律。3.4 systemd 服务定义让进程“死而复生”创建/etc/systemd/system/claude-code.service[Unit] DescriptionClaude Code Agent Service Afternetwork.target [Service] Typesimple Userclaude WorkingDirectory/opt/claude-code/app ExecStart/usr/local/bin/bun run ./src/index.ts Restartalways RestartSec10 # 关键限制资源防止单一会话吃光内存 MemoryLimit2G CPUQuota200% # 关键设置环境变量让 Bun 知道自己的家在哪 EnvironmentHOME/home/claude EnvironmentPATH/usr/local/bin:/usr/bin:/bin [Install] WantedBymulti-user.target然后启用服务sudo systemctl daemon-reload sudo systemctl enable claude-code.service sudo systemctl start claude-code.service # 查看实时日志CtrlC 退出 sudo journalctl -u claude-code.service -fRestartSec10的意义当服务因 OOM内存溢出被系统杀死后systemd 会在 10 秒后自动拉起它而不是让它永久宕机。MemoryLimit2G是经过我们实测的平衡点单个 Claude 会话峰值内存约 1.2G留 0.8G 余量给系统和其他进程。超过此值systemd 会主动kill -9比让整个服务器卡死要好得多。4. 飞书集成实战从应用创建到群聊激活的完整链路Bridge 跑起来了只是完成了 30%。剩下 70%是让飞书真正“认识”并信任这个 Bot。这一步90% 的失败都发生在这里。我将整个流程拆解为四个不可跳过的阶段并指出每个阶段最常踩的坑。4.1 飞书开放平台创建应用与获取凭证登录 飞书开放平台 进入「开发者后台」创建应用选择「企业自建应用」名称填Claude Code Team Bot。配置应用权限这是最关键的一步必须勾选消息 - 发送消息必需消息 - 获取消息详情必需用于读取/new chat命令群组 - 获取群组信息必需用于判断是否在群聊中用户 - 获取用户基本信息必需用于识别发起者文档 - 创建文档如需auto_create_doc功能配置事件订阅Request URL填https://your-domain.com/webhook这是 Nginx 反向代理的地址不是服务器 IPVerification Token和Encrypt Key复制到config.json中对应位置。订阅事件im.message.receive_v1接收消息、im.message.reaction_v1表情反应用于点赞/踩。坑点预警很多团队卡在“事件订阅验证失败”。原因通常是Nginx 没配好/webhook路径没正确转发到localhost:3001飞书开放平台的App ID和App Secret没填到config.json里服务器防火墙ufw或firewalld没放行443端口。请务必用curl -v https://your-domain.com/webhook在服务器本地测试确保返回200 OK。4.2 Nginx 反向代理安全网关的终极配置在/etc/nginx/sites-available/claude-code中写入以下配置upstream claude_backend { server 127.0.0.1:3001; } server { listen 443 ssl http2; server_name your-domain.com; # SSL 证书使用 Lets Encrypt ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # 强制 HTTPS if ($scheme ! https) { return 301 https://$host$request_uri; } # 只允许飞书的 IP 段访问 webhook关键安全措施 # 飞书官方 IP 段https://open.feishu.cn/document/server-docs/ip-ranges allow 103.107.224.0/22; allow 103.107.228.0/22; allow 103.107.232.0/22; deny all; # 速率限制防爆破 limit_req zoneclaude_api burst10 nodelay; location /webhook { proxy_pass http://claude_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 其他路径可选提供一个简单的健康检查页 location /health { return 200 OK; add_header Content-Type text/plain; } }然后启用sudo ln -sf /etc/nginx/sites-available/claude-code /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginxallowdeny all是灵魂。它意味着只有飞书官方服务器才能调用你的 webhook。任何其他 IP包括你自己的办公室网络尝试curl https://your-domain.com/webhook都会得到403 Forbidden。这从网络层就切断了未授权访问的可能。别嫌麻烦这是钱的问题——API Key 泄露一天就能刷掉你几百美金。4.3 在飞书客户端完成最终激活现在一切后端都准备好了。打开飞书 App 或网页版第一步添加 Bot 到群聊在任意群聊中点击右上角-添加机器人- 搜索Claude Code Team Bot- 点击添加。此时Bot 会自动发送欢迎消息“你好我是 Claude Code输入/help查看指令。”第二步测试核心指令在群聊中输入/new chat 重构用户登录模块如果一切正常Bot 会立即回复“✅ 已创建新会话。正在加载工作空间...”几秒后会发送一个带运行、停止按钮的卡片。第三步验证富文本与文档输入/config message_format rich_text然后随便问一个问题比如“用 Python 写一个快速排序”。你应该看到的不再是纯文本代码而是带行号、语法高亮、可复制的代码块。如果/new chat没反应请立即检查journalctl -u claude-code.service日志。最常见的日志错误是Error: Invalid verification token。这意味着你在飞书开放平台配置的Verification Token和config.json里的不一致。请逐字核对注意大小写和空格。4.4 多 Profile 管理为 Claude 和 Codex 分配独立“身份证”一个服务器完全可以同时运行 Claude Code 和 Codex 两个 Agent。但它们必须有完全隔离的“身份”否则会互相污染会话。在claude用户下创建两个独立的配置目录mkdir -p /opt/claude-code/config/{claude,codex} cp /opt/claude-code/config.json /opt/claude-code/config/claude/config.json cp /opt/claude-code/config.json /opt/claude-code/config/codex/config.json # 编辑 codex 的配置替换为 Codex 的 API Key 和 App ID nano /opt/claude-code/config/codex/config.json然后为 Codex 创建一个独立的 systemd 服务/etc/systemd/system/claude-codex.service[Unit] DescriptionClaude Codex Agent Service Afternetwork.target [Service] Typesimple Userclaude WorkingDirectory/opt/claude-code/app # 关键指定不同的 profile 和 agent ExecStart/usr/local/bin/bun run ./src/index.ts --profile codex --agent codex Restartalways RestartSec10 MemoryLimit2G EnvironmentHOME/home/claude EnvironmentPATH/usr/local/bin:/usr/bin:/bin [Install] WantedBymulti-user.target启用并启动sudo systemctl daemon-reload sudo systemctl enable claude-codex.service sudo systemctl start claude-codex.service这样claude-code.service用claudeprofileclaude-codex.service用codexprofile。它们的 API Key、工作目录、日志文件、甚至bun进程 PID全部物理隔离。你可以用sudo journalctl -u claude-codex.service -f单独查看 Codex 的日志互不干扰。这才是真正的“多租户”支持。5. 故障排查全景图从ENOENT到429 Too Many Requests的逐层诊断即使你严格按照上面的步骤操作生产环境依然会出问题。下面这张表是我过去三个月在客户现场记录的真实故障案例按发生频率从高到低排序并附上唯一有效的排查命令和修复方案。这不是教科书而是血泪经验。故障现象根本原因诊断命令修复方案我的实操心得spawnSync bun ENOENTbun不在systemd服务的PATH中sudo systemctl show --propertyEnvironment claude-code.service执行sudo ln -sf /home/claude/.bun/bin/bun /usr/local/bin/bun并重启服务这个错误出现频率最高占所有启动失败的 65%。永远不要相信which bun在终端里的输出systemd有自己的PATH。Error: Invalid verification token飞书开放平台的Verification Token与config.json不一致sudo journalctl -u claude-code.service | grep verification重新复制飞书后台的Verification Token全选、复制、粘贴不要手敲。然后sudo systemctl restart claude-code.service手动输入时很容易把字母lL和数字1搞混。建议用cat /opt/claude-code/config/config.json | grep verification直接查看。Error: connect ECONNREFUSED 127.0.0.1:3001claude-code.service进程根本没起来或监听了错误端口sudo ss -tuln | grep :3001如果无输出说明服务没运行如果有输出但State是LISTEN则检查config.json的server.port是否为3001ss -tuln是比netstat更快、更准的端口检查命令。grep :3001能瞬间告诉你端口是否就绪。{code:11232,msg:frequency limited}飞书 API 调用频率超限通常是群聊里多人同时发/new chatsudo journalctl -u claude-code.service | grep 11232 | tail -10在config.json中增加lark: {rate_limit: {burst: 5, delay: 1000}}然后重启这个错误不是你的错是飞书的风控。burst: 5表示每秒最多处理 5 个请求delay: 1000表示每个请求间隔至少 1 秒。Error: Command failed: git status服务器上没装git或claude用户没有git命令的执行权限sudo -i -u claude bash -c git --versionsudo apt update sudo apt install -y git然后sudo chmod x /usr/bin/git很多云服务器镜像默认不装git。claude用户必须能执行git否则所有涉及代码仓库的工具都会失败。Error: Permission denied dir_s_mkdir - /opt/claude-code/workspacesclaude用户对workspaces目录没有写权限ls -ld /opt/claude-code/workspacessudo chown claude:claude /opt/claude-code/workspaces这个错误通常发生在你手动mkdir后忘了chown。ls -ld能一眼看出属主是否正确。最后一个也是最隐蔽的坑Error: Cannot find module typescript。这通常发生在你更新了 Bun 或 SDK 后。修复方案不是bun install typescript而是删除node_modules和bun.lockb然后bun install重装。因为bun.lockb里锁定了旧版本的依赖树手动install会破坏一致性。我建议把这条命令写成一个脚本放在/opt/claude-code/reinstall.sh里一键执行。6. 运维与扩展日志分析、用量监控与平滑升级策略服务上线只是开始。一个成熟的 AI Agent 服务必须具备可观测性、可度量性和可演进性。下面这些是我给客户部署后持续运行半年以上的运维实践。6.1 结构化日志让每一行输出都成为可查询的数据默认的journalctl日志是纯文本难以分析。我们用pino作为日志库将日志格式化为 JSON在src/index.ts的顶部加入import pino from pino; const logger pino({ transport: { target: pino-pretty, // 开发时用 options: { colorize: true } }, // 生产环境输出为 JSON便于 ELK 或 Loki 采集 level: process.env.NODE_ENV production ? info : debug, });然后所有关键操作都打日志logger.info({ event: session_created, session_id: sessionId, user_id: event.user_id, chat_id: event.chat_id, prompt: truncate(prompt, 100), // 敏感信息脱敏 }, New session created);这样journalctl -u claude-code.service的输出就变成了{level:30,time:1730524800123,pid:12345,hostname:my-server,event:session_created,session_id:sess_xxx,user_id:ou_xxx,chat_id:oc_xxx,prompt:重构用户登录模块,msg:New session created}为什么必须 JSON 化因为你可以用jq做精准过滤。比如统计今天有多少次会话创建sudo journalctl -u claude-code.service \| jq select(.event session_created) \| wc -l。或者找出所有超时的会话sudo journalctl -u claude-code.service \| jq select(.event session_timeout)。纯文本日志你只能靠眼睛扫效率极低。6.2 用量监控看清谁在用、怎么用、用了多少Claude 的 API 调用是按 token 计费的。你必须知道每天的费用花在哪里。我们在config.json中启用了详细的用量上报{ anthropic: { log_usage: true, usage_log_path: /opt/claude-code/logs/usage.log } }然后写一个简单的 Bash 脚本/opt/claude-code/bin/daily-report.sh#!/bin/bash # 统计昨日用量 YESTERDAY$(date -d yesterday %Y-%m-%d) LOG_FILE/opt/claude-code/logs/usage.log echo Claude Code Daily Usage Report for $YESTERDAY echo Total requests: $(grep $YESTERDAY $LOG_FILE \| wc -l) echo Input tokens: $(grep $YESTERDAY $LOG_FILE \| awk -F, {sum $2} END {print sum0}) echo Output tokens: $(grep $YESTERDAY $LOG_FILE \| awk -F, {sum $3} END {print sum0}) echo Avg. response time: $(grep $YESTERDAY $LOG_FILE \| awk -F, {sum $4; count} END {print int(sum/count)})ms再用crontab每天早上 8 点自动执行并邮件发送# 编辑 crontab sudo crontab -e -u claude # 添加这一行 0 8 * * * /opt/claude-code/bin/daily-report.sh \| mail -s Claude Code Daily Report adminyour-company.com这个报告的价值远超成本控制。我们曾通过分析发现80% 的input_tokens都来自同一个产品经理的“需求描述”他习惯把整个 PRD 文档粘贴进去。于是我们给他培训了“如何用一句话概括需求”一周后他的平均input_tokens从 12000 降到了 2800。这就是数据驱动的效能提升。6.3 平滑升级零停机发布新版本的黄金法则每次git pull新版本都不能简单粗暴地systemctl restart。这会导致所有进行中的会话被强行中断用户看到“连接已断开”。我们的升级流程是四步原子操作拉取新代码sudo -i -u claude bash -c cd /opt/claude-code/app git pull origin main安装新依赖sudo -i -u claude bash -c cd /opt/claude-code/app bun install热重载Graceful Reloadsudo systemctl kill -s SIGUSR2 claude-code.service验证并清理sudo journalctl -u claude-code.service \| tail -20确认新进程 PID 已变且无 ERROR。SIGUSR2是 Bun 进程的热重载信号。它会启动一个新进程等新进程完全就绪后再优雅地关闭旧进程所有正在进行的 WebSocket 连接都会被平