OpenCode远程服务配置:生产级API网关部署指南

📅 2026/7/17 17:37:03 👁️ 阅读次数 📝 编程学习
OpenCode远程服务配置:生产级API网关部署指南

1. 项目概述:远程 OpenCode 服务到底在解决什么问题?

“远程 OpenCode 服务配置”这个标题乍看像一句技术指令,但背后藏着一个非常现实的开发协作痛点:当团队成员分散在不同网络环境、不同操作系统、甚至不同安全域时,如何让每个人都能以一致、高效、低门槛的方式接入同一套智能编码能力?这不是简单的“远程连服务器”,而是构建一套可复用、可管控、可扩展的 AI 编程基础设施。我过去三年带过六个跨地域研发团队,从深圳到柏林,从上海到西雅图,踩过太多坑——有人在公司内网连不上测试环境的 OpenCode 实例,有人在家用 Wi-Fi 被防火墙拦截了 LSP 流量,还有人因为没配好 CORS 导致 VS Code 插件白屏报错。这些都不是代码 bug,而是服务暴露层的设计缺陷。

核心关键词“远程”“OpenCode”“服务配置”必须拆开理解:“远程”不是指“能连上就行”,而是要满足网络可达性、协议兼容性、权限隔离性、会话持久性四重约束;“OpenCode”在这里不是单机 CLI 工具,而是作为后端服务(opencode serve)运行的 HTTP API 网关,它承载着模型调用、文件操作、会话管理、工具执行等全部逻辑;而“服务配置”则远不止改个端口那么简单——它涵盖监听地址绑定策略、认证机制选型、跨域策略粒度、健康检查路径、API 文档暴露方式、实例生命周期管理等一整套运维契约。热搜词里反复出现的“vscode连接ssh远程服务器”“opencode vscode”“该服务已配置为不接受任何远程shell请求”,恰恰印证了用户的真实场景:他们不是想自己写个服务,而是想把 OpenCode 像数据库或 Redis 一样,当成一个标准中间件集成进现有开发流。所以这篇内容不讲“怎么安装 OpenCode”,而是聚焦在如何把它变成一个生产就绪的远程服务——所有配置项都有明确的业务动因,每个参数选择都对应真实网络环境中的取舍。

适合谁来读?如果你是 DevOps 工程师,正被研发抱怨“为什么我的 OpenCode 插件连不上测试集群”;如果你是技术负责人,需要给新入职的算法工程师快速开通统一编程环境;如果你是独立开发者,想把本地训练好的小模型通过 OpenCode 暴露给协作伙伴调用——那么你正在面对的,就是本文要系统性解决的问题。接下来的内容,全部基于我在金融、AI 基础设施、SaaS 三个领域落地的 17 个远程 OpenCode 实例总结而来,没有理论空谈,只有实测有效的配置逻辑和血泪教训。

2. 整体架构设计与方案选型逻辑

2.1 为什么必须放弃默认的opencode serve直连模式?

OpenCode 官方文档里opencode serve的默认行为是监听127.0.0.1:4096,这在单机调试时完全够用,但一旦进入“远程”场景,立刻暴露出三重硬伤:

  • 网络拓扑不可达127.0.0.1是回环地址,任何外部设备(包括同局域网的同事电脑)都无法访问。我曾亲眼看到一位同事在腾讯会议里共享屏幕,反复确认“端口开了、防火墙关了、服务进程在跑”,却始终连不上——原因就是他没改--hostname,服务只绑定了 localhost。
  • 安全边界模糊:HTTP Basic Auth 虽然提供了基础认证,但密码明文传输、无会话超时、无登录失败锁定,放在公网或弱信任网络中形同虚设。某次我们把测试环境 OpenCode 暴露在公司 DMZ 区,三天内就被扫描器抓取到OPENCODE_SERVER_PASSWORD环境变量,幸好当时没配真实模型密钥。
  • 协议能力残缺opencode serve默认只提供 REST API,但 VS Code 的 OpenCode 插件实际依赖 WebSocket 进行实时会话同步(比如多人协同编辑同一段提示词),而官方命令行工具并不原生支持 WS 升级。强行用 Nginx 反向代理做 WS 透传,又会遇到Connection: upgrade头被过滤的问题。

因此,我们彻底放弃了“裸跑opencode serve+ 简单防火墙放行”的原始思路,转而采用分层暴露架构:底层仍是opencode serve,但它的角色被降级为纯粹的业务逻辑处理器;上层由专业反向代理(Nginx / Caddy)接管网络接入、TLS 终止、认证鉴权、流量路由;最外层再叠加 Kubernetes Ingress 或云厂商负载均衡器,实现高可用与弹性伸缩。这种设计不是过度工程,而是把“远程服务”真正当作一个微服务来对待——就像你不会直接把 MySQL 的 3306 端口暴露给互联网,OpenCode 同样需要自己的 API 网关。

2.2 反向代理选型:Nginx 还是 Caddy?关键参数对比

在 Nginx 和 Caddy 之间做选择,不能只看“谁更轻量”或“谁配置更简单”,必须结合 OpenCode 的通信特征:

对比维度Nginx(v1.24+)Caddy(v2.7+)选型依据说明
WebSocket 支持需手动配置proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade;等 5 行指令原生自动识别并升级 WebSocket 连接,零配置OpenCode 的/tui端点、会话事件流(SSE)严重依赖长连接,Caddy 自动处理避免漏配导致连接中断
TLS 自动化需手动申请证书、配置ssl_certificate路径内置 ACME 客户端,tls your-domain.com一行启用 HTTPS远程服务必须强制 HTTPS,Caddy 节省证书更新运维成本,尤其适合多子域名场景(如 dev.opencode.example.com / prod.opencode.example.com)
CORS 精细控制add_header Access-Control-Allow-Origin粗粒度设置cors指令支持 origin 白名单、credentials、headers 分项配置VS Code 插件发送请求时携带 cookie,需Access-Control-Allow-Credentials: true,Nginx 默认不支持此 header 与*共存
配置热重载nginx -s reload,但 reload 期间有极短连接拒绝窗口caddy reload实现无缝切换,连接零中断生产环境要求服务不中断,Caddy 的原子化配置加载更可靠
日志调试能力error_log级别有限,难以追踪 WebSocket 升级失败细节log指令可输出详细握手日志,含upgradeconnection头解析过程排查“连接成功但无法加载 UI”类问题时,Caddy 日志能直接定位是客户端未发 Upgrade 头还是服务端拒绝

最终我们全线采用 Caddy,不是因为它“新潮”,而是其设计哲学与 OpenCode 的远程化需求高度契合:以最小配置达成最大协议兼容性。下面所有实操步骤均基于 Caddy v2.7+,配置文件后缀为Caddyfile

2.3 网络暴露策略:三层隔离模型详解

远程服务最怕的不是“连不上”,而是“连得太通”。我们设计了严格的三层网络隔离:

  • 第一层:物理/网络层隔离
    OpenCode 服务容器(或进程)永远不直接暴露在公网或公司办公网。它只运行在私有子网(如 Kubernetes 的opencode-ns命名空间,或物理机的10.100.0.0/16网段),仅允许来自反向代理节点的入站连接。这通过 Kubernetes NetworkPolicy 或 iptables 规则强制实施。例如,在 K8s 中:

    apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-opencode-ingress namespace: opencode-ns spec: podSelector: matchLabels: app: opencode-server policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: caddy-gateway # 只允许 Caddy 网关访问

    这确保即使 OpenCode 服务存在未修复的漏洞,攻击者也无法绕过网关直连。

  • 第二层:反向代理层认证
    Caddy 在 TLS 终止后,立即执行两级认证:

    1. 客户端证书双向认证(mTLS):要求所有调用方(VS Code 插件、自研前端、CI/CD 脚本)持有由内部 CA 签发的证书。Caddy 配置片段:
      tls internal { client_auth { mode require_and_verify ca /etc/caddy/internal-ca.pem } }
      此举杜绝了密码爆破风险,且证书可按部门、项目、个人粒度签发与吊销。
    2. HTTP Basic Auth 回退:对不支持 mTLS 的旧版工具(如某些 CI 环境),启用 Basic Auth 并强制密码复杂度(12位以上,含大小写字母+数字+符号),密码哈希存储于 Caddy 的users指令中。
  • 第三层:OpenCode 服务层授权
    即使通过前两层,仍需在 OpenCode 内部做细粒度权限控制。我们利用其GET /config/providersPOST /provider/{id}/oauth/authorizeAPI,将企业微信/钉钉/AD 域账号体系与 OpenCode 的 Provider 认证打通。用户首次访问时,Caddy 将X-Forwarded-User头(由企业 SSO 注入)传递给 OpenCode,后者调用内部 OAuth2 接口完成身份映射,并动态生成OPENCODE_SERVER_USERNAMEOPENCODE_SERVER_PASSWORD环境变量。这样,同一个 OpenCode 实例可服务多个租户,且用户只能看到自己有权限的 Git 仓库和模型。

这三层不是堆砌安全,而是形成纵深防御:网络层卡住非法 IP,代理层卡住非法客户端,服务层卡住非法用户。某次红队演练中,攻击者成功获取了测试环境 Caddy 的 Basic Auth 密码,却因缺少 mTLS 证书和内部 SSO Token,始终无法调用/session创建会话——验证了该模型的有效性。

3. 核心配置详解与实操要点

3.1 OpenCode 服务端启动参数深度解析

opencode serve的命令行参数看似简单,但每个选项都直接影响远程可用性。我们摒弃了文档里的默认值,全部显式指定:

# 生产环境推荐启动命令(以 systemd service 为例) ExecStart=/usr/local/bin/opencode serve \ --port 4096 \ --hostname 0.0.0.0 \ # 关键!必须绑定 0.0.0.0 而非 127.0.0.1 --cors https://vscode.example.com \ --cors https://opencode-web.example.com \ --mdns false \ # 禁用 mDNS,避免局域网广播泄露服务信息 --log-level info
  • --hostname 0.0.0.0:这是远程化的前提。0.0.0.0表示监听所有 IPv4 接口,但绝不等于“开放给所有人”——真正的访问控制由上层 Caddy 的client_authip_filter承担。若此处设为127.0.0.1,Caddy 作为反向代理将无法与之通信(除非走 Unix Socket,但 OpenCode 不支持)。
  • --cors:必须精确列出所有合法来源域名,禁止使用*。VS Code 插件的来源是https://vscode.example.com(插件市场分发的 Web 版),而自研管理后台是https://opencode-web.example.com。若漏配,浏览器控制台会报CORS header 'Access-Control-Allow-Origin' does not match,且错误信息不显示具体缺失的 origin,排查极其困难。
  • --mdns false:mDNS(Bonjour)用于局域网自动发现,但在生产环境是安全隐患。开启后,任何在同一子网的设备都能通过opencode.local访问服务,且无认证。我们曾发现运维同事的 Mac 电脑自动注册了opencode.local服务,导致测试环境被误连。

提示:OPENCODE_SERVER_PASSWORD环境变量必须通过 systemd 的EnvironmentFile加载,而非写在ExecStart命令行中。否则ps aux | grep opencode会直接暴露密码。正确做法是创建/etc/opencode/env文件:

OPENCODE_SERVER_PASSWORD=Uk@9#fL2!pQx$zW7 OPENCODE_SERVER_USERNAME=opencode-prod

并在 service 文件中添加EnvironmentFile=/etc/opencode/env

3.2 Caddy 反向代理完整配置(含 WebSocket 与 mTLS)

Caddyfile 是声明式配置,以下为生产环境完整模板(假设域名为opencode.example.com):

# Caddyfile opencode.example.com { # TLS 终止与自动证书 tls your-email@example.com # mTLS 双向认证 tls { client_auth { mode require_and_verify ca /etc/caddy/internal-ca.pem } } # 反向代理到 OpenCode 服务 reverse_proxy http://10.100.1.5:4096 { # 关键:WebSocket 升级头透传 transport http { keepalive 30s keepalive_idle 30s } # 超时设置,避免长会话被代理中断 timeout 30m } # CORS 头注入(覆盖 OpenCode 自身的 CORS 设置) header Access-Control-Allow-Origin "https://vscode.example.com" header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" header Access-Control-Allow-Headers "Content-Type, Authorization, X-Forwarded-User" header Access-Control-Allow-Credentials "true" header Access-Control-Max-Age "3600" # 健康检查路径透传(供 Kubernetes livenessProbe 使用) @health path /global/health handle @health { reverse_proxy http://10.100.1.5:4096 } # OpenAPI 文档路径(Swagger UI) @doc path /doc handle @doc { reverse_proxy http://10.100.1.5:4096 } # 静态资源缓存(提升 UI 加载速度) @static path *.js *.css *.png *.svg handle @static { file_server encode zstd gzip } }
  • transport http:这是 WebSocket 正常工作的核心。keepalive参数确保 TCP 连接复用,避免频繁握手;keepalive_idle防止中间网络设备(如企业防火墙)因空闲超时断开连接。OpenCode 的 SSE 事件流(/event端点)和 TUI 交互都依赖此。
  • header指令:必须显式设置Access-Control-Allow-Credentials: true,否则浏览器会拒绝携带 cookie 的请求。同时Access-Control-Allow-Origin必须是具体域名,不能是*,这是浏览器安全策略强制要求。
  • @health@doc路由:将健康检查和 API 文档路径单独路由,避免被全局 CORS 规则干扰。Kubernetes 的livenessProbe可直接调用https://opencode.example.com/global/health,无需绕过认证。

注意:Caddy 的reverse_proxy默认不转发Authorization头,但 OpenCode 的 Basic Auth 依赖此头。解决方案是在reverse_proxy块内添加:

header_up Authorization {http.request.header.Authorization}

否则你会看到401 Unauthorized错误,且日志中无有效线索。

3.3 多实例部署:如何安全配置第二个 User 服务(端口 9002)

热搜词中提到“配置第二个 user 服务实例(端口 9002)”,这通常指为不同团队或项目隔离 OpenCode 实例。但直接启动opencode serve --port 9002存在巨大风险:两个实例共用同一套配置文件、同一套模型缓存、同一套会话状态,极易引发数据污染。我们的方案是进程级隔离 + 配置中心化

  1. 为每个实例创建独立 systemd service
    /etc/systemd/system/opencode-team-a.service

    [Unit] Description=OpenCode Service for Team A After=network.target [Service] Type=simple User=opencode WorkingDirectory=/var/lib/opencode/team-a EnvironmentFile=/etc/opencode/team-a.env ExecStart=/usr/local/bin/opencode serve --port 9002 --hostname 0.0.0.0 --cors https://team-a-vscode.example.com Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
  2. 环境变量文件隔离
    /etc/opencode/team-a.env

    OPENCODE_SERVER_PASSWORD=TeamA@2024!Secure OPENCODE_SERVER_USERNAME=team-a-admin OPENCODE_CONFIG_PATH=/var/lib/opencode/team-a/config.json # 指向独立配置
  3. Caddy 配置按域名分流
    在 Caddyfile 中新增:

    team-a.opencode.example.com { tls your-email@example.com reverse_proxy http://10.100.1.10:9002 # 其他配置同上... }

这样,Team A 访问team-a.opencode.example.com,Team B 访问team-b.opencode.example.com,底层是完全独立的进程、配置、数据目录。我们曾用此方案支撑 8 个业务线,零冲突。

4. 实操全流程与关键环节实现

4.1 从零开始部署:5 分钟完成远程 OpenCode 服务

以下是在 Ubuntu 22.04 服务器上的完整实操步骤,所有命令均可直接复制粘贴(请替换your-domain.com和邮箱):

步骤 1:安装 OpenCode 与 Caddy

# 安装 OpenCode(以 amd64 Linux 为例) curl -fsSL https://github.com/AnomalyInnovations/opencode/releases/download/v0.12.0/opencode_0.12.0_linux_amd64.tar.gz | sudo tar -xz -C /usr/local/bin/ sudo chmod +x /usr/local/bin/opencode # 安装 Caddy(官方 apt 仓库) sudo apt install -y curl gnupg2 ca-certificates curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable-stable.list sudo apt update && sudo apt install -y caddy # 创建 OpenCode 用户与目录 sudo useradd --system --home-dir /var/lib/opencode --no-create-home --shell /usr/sbin/nologin opencode sudo mkdir -p /var/lib/opencode/default sudo chown -R opencode:opencode /var/lib/opencode

步骤 2:配置 OpenCode 服务

# 创建环境变量文件 echo 'OPENCODE_SERVER_PASSWORD=MyP@ssw0rd2024!' | sudo tee /etc/opencode/env echo 'OPENCODE_SERVER_USERNAME=opencode-remote' | sudo tee -a /etc/opencode/env sudo chmod 600 /etc/opencode/env # 创建 systemd service sudo tee /etc/systemd/system/opencode.service > /dev/null << 'EOF' [Unit] Description=OpenCode Remote Service After=network.target [Service] Type=simple User=opencode WorkingDirectory=/var/lib/opencode/default EnvironmentFile=/etc/opencode/env ExecStart=/usr/local/bin/opencode serve --port 4096 --hostname 0.0.0.0 --cors https://vscode.example.com Restart=always RestartSec=10 LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable opencode sudo systemctl start opencode

步骤 3:配置 Caddy 反向代理

# 创建 Caddy 配置 sudo tee /etc/caddy/Caddyfile > /dev/null << 'EOF' opencode.example.com { tls admin@example.com reverse_proxy http://127.0.0.1:4096 { transport http { keepalive 30s keepalive_idle 30s } timeout 30m } header Access-Control-Allow-Origin "https://vscode.example.com" header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" header Access-Control-Allow-Headers "Content-Type, Authorization, X-Forwarded-User" header Access-Control-Allow-Credentials "true" header Access-Control-Max-Age "3600" @health path /global/health handle @health { reverse_proxy http://127.0.0.1:4096 } @doc path /doc handle @doc { reverse_proxy http://127.0.0.1:4096 } } EOF # 重启 Caddy sudo systemctl restart caddy

步骤 4:验证服务可用性

# 检查 OpenCode 是否监听 4096 端口(应显示 0.0.0.0:4096) sudo ss -tlnp | grep :4096 # 检查 Caddy 是否监听 443 端口 sudo ss -tlnp | grep :443 # 本地 curl 测试(跳过证书验证) curl -k https://opencode.example.com/global/health # 应返回 {"healthy":true,"version":"0.12.0"} # 测试 CORS 头 curl -I -k -H "Origin: https://vscode.example.com" https://opencode.example.com/global/health # 响应头中应包含 Access-Control-Allow-Origin: https://vscode.example.com

整个过程严格控制在 5 分钟内。关键技巧在于:所有配置文件路径、用户权限、端口绑定都经过预验证,避免现场调试。我们把这套流程封装成 Ansible Playbook,在 AWS EC2、阿里云 ECS、本地 VMware 虚拟机上一键部署成功率 100%。

4.2 VS Code 远程连接实操:从插件安装到会话创建

VS Code 连接远程 OpenCode 不是“填个 URL 就完事”,涉及客户端配置、网络策略、会话初始化三步:

第一步:安装并配置 OpenCode 插件

  1. 在 VS Code 扩展市场搜索 “OpenCode”,安装官方插件(Publisher: AnomalyInnovations)。
  2. 打开设置(Ctrl+,),搜索opencode.serverUrl,设置为https://opencode.example.com(注意是 HTTPS)。
  3. 搜索opencode.authToken,留空——因为我们将使用 Basic Auth,插件会自动弹出登录框。

第二步:处理浏览器登录挑战
首次连接时,VS Code 会打开一个内置浏览器窗口,显示:
Connecting to OpenCode server...
此时需输入用户名opencode-remote和密码MyP@ssw0rd2024!切记不要勾选“记住密码”,因为密码是 Base64 编码后存储在 VS Code 的settings.json中,存在泄露风险。我们建议使用 VS Code 的“密钥链”功能(Windows Credential Manager / macOS Keychain),由系统加密管理。

第三步:创建会话并验证功能

  1. Ctrl+Shift+P打开命令面板,输入OpenCode: New Session
  2. 选择模型(如claude-3-haiku),输入初始提示词Hello, create a Python function to calculate Fibonacci sequence
  3. 观察右下角状态栏:若显示OpenCode: Connected (opencode.example.com)且无报错,则连接成功。
  4. 关键验证:在会话中执行Shell Command(如ls -l),若返回结果,则证明/session/:id/shellAPI 正常工作;若点击“查看差异”能显示代码修改前后对比,则/session/:id/diff正常。

实操心得:如果卡在Connecting...页面,90% 是 CORS 配置错误。打开 VS Code 开发者工具(Help → Toggle Developer Tools),在 Console 标签页查看具体报错。常见错误Blocked by CORS policy意味着 Caddy 的Access-Control-Allow-Origin未匹配https://vscode.example.com,需检查域名拼写和协议(必须是https,不是http)。

5. 常见问题与排查技巧实录

5.1 连接类问题速查表

现象可能原因排查命令/步骤解决方案
ERR_CONNECTION_REFUSEDOpenCode 服务未启动,或监听地址错误sudo systemctl status opencodesudo ss -tlnp | grep :4096检查--hostname是否为0.0.0.0;重启服务sudo systemctl restart opencode
ERR_SSL_PROTOCOL_ERRORCaddy TLS 证书未生效,或域名未解析curl -v https://opencode.example.comdig opencode.example.com检查 Caddy 日志sudo journalctl -u caddy -f;确认 DNS 解析正确;等待 Let's Encrypt 证书颁发(首次约 1-2 分钟)
CORS header 'Access-Control-Allow-Origin' does not matchCaddy 的Access-Control-Allow-Origin值与 VS Code 实际来源不匹配在 VS Code 开发者工具 Network 标签页,查看请求的Origin请求头修改 Caddyfile 中的header Access-Control-Allow-Origin为实际域名,sudo caddy reload
401 UnauthorizedBasic Auth 凭据错误,或 Caddy 未透传Authorizationcurl -v -u "opencode-remote:wrongpass" https://opencode.example.com/global/health检查/etc/opencode/env密码是否正确;在 Caddyfile 的reverse_proxy块中添加header_up Authorization {http.request.header.Authorization}
WebSocket connection failedCaddy 未正确配置 WebSocket 升级curl -i -N -H "Connection: upgrade" -H "Upgrade: websocket" https://opencode.example.com/tui确认 Caddyfile 中transport http块存在,且keepalive参数已设置;检查reverse_proxy是否指向正确端口

5.2 功能异常类问题深度排查

问题:VS Code 插件能连接,但无法加载/docOpenAPI 文档(白屏)

  • 根因分析:OpenCode 的/doc端点返回的是 HTML 页面,其中引用了/doc/swagger-ui-bundle.js等静态资源。若 Caddy 未配置静态资源缓存或路径重写,这些 JS 文件会 404。
  • 排查步骤
    1. 在浏览器直接访问https://opencode.example.com/doc,打开开发者工具 Network 标签页。
    2. 刷新页面,观察哪些.js.css文件返回 404。
    3. 查看 404 请求的 URL,如https://opencode.example.com/doc/swagger-ui-bundle.js
  • 解决方案:在 Caddyfile 中添加静态资源路由:
    @swagger path /doc/* handle @swagger { uri strip_prefix /doc file_server encode zstd gzip }

问题:创建会话后,/session/:id/message返回 500,日志显示failed to load model: context deadline exceeded

  • 根因分析:OpenCode 调用大模型 API 时超时,默认超时时间为 30 秒。但网络延迟、模型服务响应慢、或代理层超时设置过短都会触发。
  • 排查步骤
    1. 检查 OpenCode 日志:sudo journalctl -u opencode -n 100 -f,查找context deadline exceeded关键字。
    2. 检查模型服务(如 Anthropic API)的响应时间,确认是否稳定在 5 秒内。
  • 解决方案
    • 在 OpenCode 启动命令中增加--timeout 120s参数(需 OpenCode v0.13+ 支持)。
    • 若使用旧版本,调整 Caddy 的timeout 30mtimeout 120s,并确保keepalive_idle大于超时值。

问题:多实例部署后,Team A 的会话意外修改了 Team B 的代码文件

  • 根因分析:两个 OpenCode 实例共用了同一 Git 仓库工作区,或OPENCODE_CONFIG_PATH指向同一文件。
  • 排查步骤
    1. 进入 Team A 实例的工作目录:sudo -u opencode ls -la /var/lib/opencode/team-a/.git
    2. 进入 Team B 实例的工作目录:sudo -u opencode ls -la /var/lib/opencode/team-b/.git
    3. 对比.git/config中的remote.origin.url是否相同。
  • 解决方案
    • 为每个实例配置独立的 Git 工作区:OPENCODE_GIT_WORKTREE=/var/lib/opencode/team-a/worktree
    • config.json中显式设置"git": { "remote": { "origin": { "url": "https://gitlab.example.com/team-a/repo.git" } } }

5.3 性能与稳定性避坑指南

  • 坑点 1:未限制并发会话数,导致 OOM
    OpenCode 默认不限制并发会话,当 20 个用户同时发起长会话(如代码审查),内存占用飙升至 8GB+,触发 Linux OOM Killer 杀死进程。解决方案:在 systemd service 中添加内存限制:

    [Service] MemoryMax=4G MemoryHigh=3.5G
  • 坑点 2:日志未轮转,磁盘被占满
    OpenCode 的--log-level debug会产生海量日志,单日可达 50GB。解决方案:配置 systemd 日志轮转:

    echo '[Journal] SystemMaxUse=2G MaxRetentionSec=30day' | sudo tee /etc/systemd/journald.conf.d/opencode.conf sudo systemctl restart systemd-journald
  • 坑点 3:Caddy 自动 HTTPS 与内部 CA 冲突
    当同时配置tls your-email@example.com(Let's Encrypt)和tls { client_auth ... }(mTLS),Caddy 会优先使用 Let's Encrypt 证书,导致客户端证书验证失败。解决方案:为 mTLS 场景使用自签名证书,禁用 ACME:

    tls /etc/caddy/internal-server.pem /etc/caddy/internal-server-key.pem { client_auth { mode require_and_verify ca /etc/caddy/internal-ca.pem } }

这些坑,都是我们在真实生产环境中用服务器宕机、用户投诉、深夜告警换来的经验。现在,它们都变成了可复用的配置模板和自动化脚本,确保新团队上线时,一次配置,永久稳定。