OpenClaw Gateway 代理问题排查记录:从 ECONNREFUSED 到 WSL systemd 的 TaoToken 配置实践 1. OpenClaw Gateway 在 WSL 里报 ECONNREFUSED 到底卡在哪OpenClaw Gateway 是一个跑在本机、负责把外部事件比如飞书回调、Webhook、定时任务转发给 Agent 运行时的网关服务它本身监听一个本地端口常见是 127.0.0.1:18789同时又要主动往外发 HTTPS 请求去换取 tenant_access_token 之类的凭证。适合谁适合在 WSL2 里做本地 Agent 开发、又想让服务常驻后台的人。问题就出在“主动往外发请求”这一步日志里蹦出AxiosError: connect ECONNREFUSED 127.0.0.1:7890请求目标是https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal。这句话翻译成人话就是程序想通过本机 7890 端口的代理去访问外网但那个端口上根本没有服务在监听于是连接被直接拒绝。ECONNREFUSED 和超时ETIMEDOUT不一样超时是“敲门没人应”拒绝是“门牌号存在但没人住”——说明代理地址是写死的、明确的只是服务没了。很多人第一反应是“Gateway 挂了”其实不是。你跑一下openclaw gateway status大概率看到的是Runtime: running (pid 1528, state active) RPC probe: ok Listening: 127.0.0.1:18789服务活着、systemd 托管正常、websocket 探测通过、端口也在听。也就是说 Gateway 进程本身健康坏的是它继承来的网络代理配置。Node 生态里 Axios 会自动读取HTTP_PROXY、HTTPS_PROXY、http_proxy、https_proxy、ALL_PROXY这几个环境变量只要有一个存在且指向 127.0.0.1:7890请求链路就会变成“程序 → 本地代理 → 外网 API”代理一没整条链路断在第一步。WSL 环境特别容易踩这个坑因为代理变量可能来自三个地方一是你在.bashrc/.zshrc里手动 export 的二是 Windows 侧通过 WSL 的镜像网络或WSLENV透传进来的三是 systemd user service 在启动时把当时 shell 的环境整个继承了过去。前两个只影响交互式终端第三个才是让 Gateway “重启也没用”的元凶——你 unset 了当前 shell但 systemd 启动的进程用的是它自己那份快照。所以排查顺序必须是先确认 Gateway 状态再查当前 shell最后一定要查进程自己的/proc/pid/environ否则你会陷入“明明删了代理还是报错”的循环。2. 把 endpoint 切到 TaoToken 统一通道的前置准备定位到代理问题之后还有一个更省心的做法与其让 Gateway 去直连各种外部 API、还要跟代理变量斗智斗勇不如把出站 endpoint 统一收敛到一个稳定的通道上。我这边用的是 TaoToken官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 它提供统一的 API 入口Base URL 是https://taotoken.net/api模型对话、Coding Plan、控制台、API Keys、接入文档都有对应页面。为什么这一步能顺带解决 ECONNREFUSED因为当你把 Gateway 的出站目标从“一堆分散的外部域名”改成“一个固定的、可直连的 endpoint”后代理变量是否残留就不再是致命问题了——只要这个 endpoint 本身可达请求就不会再走 127.0.0.1:7890。当然前提是你得先把残留的代理变量清干净否则请求还是会先撞到那个不存在的代理上。前置准备分三件事。第一拿到 API Key进控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建一个复制出来形如sk-xxxx的字符串注意只显示一次。第二确认你要用的 Model ID这个在模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 或者接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里能查到不同模型 ID 不一样别照抄别人的。第三想清楚你是临时验证还是长期跑临时验证用模型对话页最省事长期编码或跑 Agent建议直接上 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 额度模型更适合常驻服务。这里有个关键点TaoToken 的三件套永远是 Base URL Key Model ID缺一不可。Base URL 固定https://taotoken.net/apiKey 是你刚建的Model ID 按文档填。后面所有配置文件里出现的base_url、api_key、model都对应这三样。如果你用的是 Claude Code 这类工具接入文档里有专门的 Anthropic 兼容说明页面在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 照着填就行。3. 可复制的 gateway 配置片段与 systemd 单元示例先说 Gateway 侧的配置。OpenClaw 的 gateway 配置一般放在~/.config/openclaw/gateway.json或项目目录下的gateway.config.json具体路径以openclaw gateway status输出里的 config 路径为准。把出站 endpoint 指向 TaoToken 统一通道配置片段如下{ gateway: { listen: 127.0.0.1:18789, outbound: { baseUrl: https://taotoken.net/api, apiKey: sk-你的Key, model: 你的ModelID, timeoutMs: 30000 } }, proxy: { enabled: false } }注意proxy.enabled显式设为 false这是防止 Gateway 内部再自己去读环境变量拼代理。有些版本字段名是useProxy或httpProxy以你本地openclaw gateway config --help为准但思路一致把代理开关关掉让出站走直连。然后是 systemd user 单元。Gateway 被 systemd 托管时环境变量是在单元文件里定义的所以光改 shell 没用。单元文件通常在~/.config/systemd/user/openclaw-gateway.service示例[Unit] DescriptionOpenClaw Gateway Afternetwork-online.target [Service] Typesimple ExecStart/usr/local/bin/openclaw gateway start --foreground Restarton-failure RestartSec5 EnvironmentNODE_ENVproduction EnvironmentOPENCLAW_OUTBOUND_BASE_URLhttps://taotoken.net/api EnvironmentOPENCLAW_OUTBOUND_API_KEYsk-你的Key EnvironmentOPENCLAW_OUTBOUND_MODEL你的ModelID # 关键显式清空代理变量避免继承旧环境 EnvironmentHTTP_PROXY EnvironmentHTTPS_PROXY Environmenthttp_proxy Environmenthttps_proxy EnvironmentALL_PROXY [Install] WantedBydefault.target这里把五个代理变量全部显式置空比“不写”更保险——因为 systemd 默认会继承systemctl --user调用时的环境你之前 export 过的代理可能被带进来。显式置空等于强制覆盖。改完单元文件后必须重载并重启systemctl --user daemon-reload systemctl --user restart openclaw-gateway systemctl --user status openclaw-gateway如果你更想用环境文件而不是写死在单元里可以建~/.config/openclaw/gateway.envOPENCLAW_OUTBOUND_BASE_URLhttps://taotoken.net/api OPENCLAW_OUTBOUND_API_KEYsk-你的Key OPENCLAW_OUTBOUND_MODEL你的ModelID HTTP_PROXY HTTPS_PROXY http_proxy https_proxy ALL_PROXY然后在单元里用EnvironmentFile%h/.config/openclaw/gateway.env引入。这样 Key 不进单元文件改起来也方便。两种方式选一种别混用混用容易排查不清到底哪个生效。4. 验证请求是否真的走通 TaoToken 通道配置改完别急着看日志先用 curl 直接打 TaoToken 的 endpoint确认网络层通不通。这一步能帮你把“网络问题”和“Gateway 配置问题”彻底分开。curl -sS -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的Key \ -H Content-Type: application/json \ -d { model: 你的ModelID, messages: [{role: user, content: ping}], max_tokens: 16 }如果返回里带choices字段说明 Key、Model ID、网络三者都正常。如果返回 401是 Key 问题返回 404 或 model not found是 Model ID 写错连接被拒那还是代理变量没清干净回到第 5 节。接着验证 Gateway 进程自己的环境变量这是最关键的一步。先从 status 里拿到 PIDopenclaw gateway status # 记下 pid比如 1528 cat /proc/1528/environ | tr \0 \n | grep -i proxy这条命令拆开看/proc/pid/environ是 Linux 虚拟文件系统里该进程的环境变量快照变量之间用\0分隔所以用tr \0 \n转成换行再grep -i proxy过滤。如果输出为空恭喜进程里没有代理残留。如果还看到http_proxyhttp://127.0.0.1:7890说明 systemd 那份环境还没清掉回去检查单元文件或 EnvironmentFile。再确认进程启动命令和监听端口cat /proc/1528/cmdline | tr \0 ps -fp 1528 ss -ltnp | grep 18789cmdline看它到底用什么参数启动的ss确认 18789 在听。最后触发一次真实请求观察 Gateway 日志journalctl --user -u openclaw-gateway -f在另一个终端触发一次飞书 token 获取或你配置的任意出站动作日志里应该看到请求发往taotoken.net而不是127.0.0.1:7890并且返回 200。到这一步ECONNREFUSED 就算真正解决了。5. 本篇常见报错逐条排查对照排查过程中会撞到几个典型报错这里按真实日志逐条对照。ECONNREFUSED 127.0.0.1:7890最核心的那个。含义是代理端口没人听。先env | grep -i proxy看当前 shell再cat /proc/pid/environ | tr \0 \n | grep -i proxy看进程。两处都有就两处都清。临时清 shell 用unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY但记住这只影响当前终端systemd 托管的进程必须改单元文件或 EnvironmentFile 后daemon-reloadrestart。401 Unauthorized请求打到 TaoToken 了但 Key 不对。检查三件事Key 有没有复制全sk-开头那串、有没有多余空格、是不是在 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 里被删了。另外确认请求头是Authorization: Bearer sk-xxx别写成x-api-key。local proxy failed / proxy connect ECONNREFUSED和第一个同源只是措辞不同说明请求确实尝试走本地代理。处理方式一样清变量 关配置里的 proxy 开关。reading choices / Cannot read properties of undefined (reading choices)这是拿到响应后解析失败通常不是网络问题而是返回体结构不对——比如 endpoint 写成了/api但实际要/api/v1/chat/completions或者 Model ID 不存在导致返回了错误对象。先用第 4 节的 curl 确认返回结构再对照接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里的路径。OAuth / token 获取失败如果 Gateway 里配了需要 OAuth 的外部服务代理一断OAuth 回调也走不通。这类问题优先确认出站 endpoint 是否已统一到 TaoToken再检查回调地址是否可达。systemd 重启后代理又回来说明你只改了 shell 没改单元。用systemctl --user show openclaw-gateway -p Environment看 systemd 实际生效的环境对照单元文件逐项核对。如果排查半天还是不通最干净的办法是重装服务openclaw gateway uninstall openclaw gateway install openclaw gateway start这会重新生成 systemd 单元和启动配置把旧的继承环境一并清掉。重装后再按第 3 节把 TaoToken 三件套填回去。6. 后续长期跑 Agent 的接入选择问题解决之后如果你只是偶尔验证一下模型用模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 就够了不用碰配置文件。但 OpenClaw Gateway 这种常驻服务本质是长期跑 Agent 和自动化任务出站请求量大、对稳定性敏感这时候更建议走 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 额度和模型策略更适合持续调用。接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里有各语言和各工具的完整示例包括 Claude Code 的 Anthropic 兼容配置照着改 Base URL、Key、Model ID 三件套即可。控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 可以看用量和 Key 管理API Keys 页面负责增删 Key。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后留一个我踩过的坑WSL 里 systemd 的 user 实例默认可能没开如果systemctl --user报 “Failed to connect to bus”先确认/etc/wsl.conf里[boot] systemdtrue并wsl --shutdown重启。这个不解决后面所有 systemd 操作都是空中楼阁。