WSL Ubuntu 20.04 中 VS Code Codex 插件登录失败问题排查与解决笔记

1. 问题背景

我的环境如下:

1
2
3
4
5
6
Windows + WSL2
WSL 系统:Ubuntu 20.04
编辑器:VS Code
插件:OpenAI Codex / ChatGPT Codex 插件
代理软件:Clash
Clash 代理端口:7897

我的目标是:

1
在 WSL 环境中的 VS Code 里使用 Codex 插件。

Windows 原生 VS Code 中 Codex 插件可以正常使用,但是在 WSL 中使用 VS Code 打开项目后,Codex 登录失败。


2. 报错现象

在 VS Code WSL 环境中登录 Codex 时,出现如下错误:

1
2
3
4
5
6
7
8
9
10
Sign-in could not be completed

Token exchange failed: error sending request for url (https://auth.openai.com/oauth/token)

Error code
token_exchange_failed

Details
Token exchange failed: error sending request for url (https://auth.openai.com/oauth/token)
Return to Codex to retry, switch accounts, or contact your workspace admin if access is restricted.

同时,VS Code Output 中还有类似错误:

1
2
Error fetching error="TypeError: fetch failed" url=https://chatgpt.com/ces/v1/rgstr
Error fetching error="TypeError: fetch failed" url=https://ab.chatgpt.com/v1/sdk_exception

一开始在 WSL 中测试:

1
curl -I https://chatgpt.com

也是失败的。


3. 初步判断

Windows 下 VS Code Codex 可以使用,说明:

1
2
3
账号本身没有问题
Codex 插件本身没有问题
Clash 在 Windows 端是可用的

但是 WSL 下失败,说明问题主要在:

1
WSL 环境没有正确走 Windows Clash 代理。

需要特别注意:

1
2
Windows 中的 127.0.0.1:7897 指的是 Windows 自己的 Clash。
WSL 中的 127.0.0.1:7897 指的是 WSL 自己,不一定是 Windows 的 Clash。

因此,在 WSL 中通常不能直接使用:

1
http://127.0.0.1:7897

而应该使用 Windows 主机在 WSL 中的网关地址,例如:

1
http://172.23.0.1:7897

这个 IP 可以通过下面命令动态获取:

1
ip route show | grep -i default | awk '{ print $3 }'

4. 第一步:确认 WSL 能访问 Windows Clash

在 WSL 中执行:

1
2
WIN_HOST=$(ip route show | grep -i default | awk '{ print $3}')
echo $WIN_HOST

输出为:

1
172.23.0.1

然后测试 WSL 是否能通过 Windows Clash 访问 ChatGPT:

1
curl -x http://$WIN_HOST:7897 -I https://chatgpt.com

返回结果中出现:

1
HTTP/1.1 200 Connection established

说明 WSL 已经成功连接到 Windows Clash 代理端口。

后面即使出现:

1
2
HTTP/2 403
cf-mitigated: challenge

也不一定是错误。这通常是 Cloudflare 对 curl 请求的挑战。重点是已经出现:

1
HTTP/1.1 200 Connection established

这说明代理链路已经打通。


5. 给 WSL 终端设置代理

/home/dky/.bashrc 中添加:

1
2
3
4
5
6
7
8
9
10
# Windows Clash proxy for WSL
export WIN_HOST=$(ip route show | grep -i default | awk '{ print $3}')
export http_proxy="http://${WIN_HOST}:7897"
export https_proxy="http://${WIN_HOST}:7897"
export HTTP_PROXY="http://${WIN_HOST}:7897"
export HTTPS_PROXY="http://${WIN_HOST}:7897"
export all_proxy="http://${WIN_HOST}:7897"
export ALL_PROXY="http://${WIN_HOST}:7897"
export no_proxy="localhost,127.0.0.1,::1"
export NO_PROXY="localhost,127.0.0.1,::1"

然后执行:

1
source ~/.bashrc

测试:

1
2
3
echo $http_proxy
echo $https_proxy
curl -I https://auth.openai.com

如果返回中出现:

1
HTTP/1.1 200 Connection established

说明 WSL 终端环境已经能正确走代理。


6. 仅设置 .bashrc 还不够

虽然 WSL 终端里的 curl 已经正常,但是 Codex 插件依然可能登录失败。

原因是:

1
2
3
Codex 插件不是普通 shell 命令。
它运行在 VS Code Server / Extension Host / codex app-server 进程里。
这些进程不一定读取 ~/.bashrc。

因此,还需要给 VS Code Remote WSL Server 设置启动环境变量。


7. 给 VS Code WSL Server 设置代理

创建或修改文件:

1
/home/dky/.vscode-server/server-env-setup

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh

WIN_HOST=$(ip route show | grep -i default | awk '{ print $3 }')

export http_proxy="http://${WIN_HOST}:7897"
export https_proxy="http://${WIN_HOST}:7897"
export HTTP_PROXY="http://${WIN_HOST}:7897"
export HTTPS_PROXY="http://${WIN_HOST}:7897"
export all_proxy="http://${WIN_HOST}:7897"
export ALL_PROXY="http://${WIN_HOST}:7897"
export no_proxy="localhost,127.0.0.1,::1"
export NO_PROXY="localhost,127.0.0.1,::1"

# Let Node.js fetch use HTTP_PROXY / HTTPS_PROXY when supported
export NODE_USE_ENV_PROXY=1

赋予执行权限:

1
chmod +x ~/.vscode-server/server-env-setup

这个文件的作用是:

1
让 VS Code Server、Extension Host、Codex app-server 等 WSL 内部插件进程也获得正确的代理环境变量。

8. 设置 Remote WSL 的 VS Code 代理

修改文件:

1
/home/dky/.vscode-server/data/Machine/settings.json

添加:

1
2
3
4
{
"http.proxy": "http://172.23.0.1:7897",
"http.proxySupport": "override"
}

这里的 172.23.0.1 是当时通过下面命令获取到的 Windows Host IP:

1
ip route show | grep -i default | awk '{ print $3 }'

需要注意:

1
这个 IP 有可能在重启 WSL 或电脑后发生变化。

如果以后再次失败,需要重新执行:

1
ip route show | grep -i default | awk '{ print $3 }'

如果输出不是 172.23.0.1,就要更新 Machine/settings.json 中的代理地址。


9. 重启 VS Code Server

修改环境变量后,需要彻底重启 VS Code WSL Server。

关闭所有 VS Code 窗口,然后在 WSL 中执行:

1
2
pkill -f vscode-server
pkill -f ".vscode-server"

或者在 Windows PowerShell 中执行:

1
wsl --shutdown

然后重新打开 WSL,进入项目目录:

1
2
cd ~/workspaces_rk/kernel
code .

10. 关键问题:Windows User Settings 污染了 WSL Codex 进程

我之前为了让 Windows 原生 VS Code 使用 Codex,在 Windows PowerShell 中执行过:

1
2
3
4
5
6
7
8
9
setx HTTP_PROXY "http://127.0.0.1:7897"
setx HTTPS_PROXY "http://127.0.0.1:7897"
setx ALL_PROXY "http://127.0.0.1:7897"
setx NO_PROXY "localhost,127.0.0.1"

setx http_proxy "http://127.0.0.1:7897"
setx https_proxy "http://127.0.0.1:7897"
setx all_proxy "http://127.0.0.1:7897"
setx no_proxy "localhost,127.0.0.1"

同时还在 Windows VS Code User Settings 中添加过:

1
2
"http.proxy": "http://127.0.0.1:7897",
"http.proxySupport": "on"

配置文件位置是:

1
C:/Users/dky/AppData/Roaming/Code/User/settings.json

这个配置在 Windows 本地是合理的,因为 Windows 中的:

1
127.0.0.1:7897

就是 Windows 本机的 Clash。

但是问题在于:

1
当 VS Code 连接 WSL Remote 后,这个 Windows User Settings 中的 http.proxy 配置可能会影响 WSL 中的 Codex app-server。

导致 Codex app-server 进程中出现错误代理:

1
2
HTTP_PROXY=http://127.0.0.1:7897
HTTPS_PROXY=http://127.0.0.1:7897

而在 WSL 里,127.0.0.1:7897 指的是 WSL 自己,不是 Windows Clash,所以 Codex 登录换 token 失败。


11. 发现问题的关键命令

使用下面命令检查 Codex app-server 进程实际拿到的代理变量:

1
ps eww -ef | grep "codex app-server" | sed 's/ /\n/g' | grep -i proxy

之前失败时,发现有冲突:

1
2
3
4
5
HTTP_PROXY=http://127.0.0.1:7897
HTTPS_PROXY=http://127.0.0.1:7897

http_proxy=http://172.23.0.1:7897
https_proxy=http://172.23.0.1:7897

也就是说:

1
2
大写代理变量是错的:127.0.0.1:7897
小写代理变量是对的:172.23.0.1:7897

很多程序会优先读取大写的 HTTP_PROXY / HTTPS_PROXY,所以 Codex 很可能使用了错误的代理地址。


12. 最终解决方法

删除 Windows User Settings 中的这两行:

1
2
"http.proxy": "http://127.0.0.1:7897",
"http.proxySupport": "on"

也就是修改文件:

1
C:/Users/dky/AppData/Roaming/Code/User/settings.json

删除后只保留其他正常配置,例如:

1
2
3
{
"workbench.colorTheme": "Visual Studio Light"
}

然后重启 VS Code / WSL Server。

最终 Codex 成功登录。


13. 正常登录后的验证结果

重新检查 Codex app-server 进程:

1
ps eww -ef | grep "codex app-server" | sed 's/ /\n/g' | grep -i proxy

正常结果为:

1
2
3
4
5
6
7
8
9
HTTPS_PROXY=http://172.23.0.1:7897
http_proxy=http://172.23.0.1:7897
https_proxy=http://172.23.0.1:7897
HTTP_PROXY=http://172.23.0.1:7897
ALL_PROXY=http://172.23.0.1:7897
all_proxy=http://172.23.0.1:7897
NODE_USE_ENV_PROXY=1
NO_PROXY=localhost,127.0.0.1,::1
no_proxy=localhost,127.0.0.1,::1

此时所有代理变量都指向:

1
172.23.0.1:7897

不再出现:

1
127.0.0.1:7897

Codex 登录恢复正常。


14. 最终推荐配置

14.1 Windows User Settings

文件位置:

1
C:/Users/dky/AppData/Roaming/Code/User/settings.json

不要写:

1
2
"http.proxy": "http://127.0.0.1:7897",
"http.proxySupport": "on"

推荐保持简洁,例如:

1
2
3
{
"workbench.colorTheme": "Visual Studio Light"
}

14.2 WSL .bashrc

文件位置:

1
/home/dky/.bashrc

保留:

1
2
3
4
5
6
7
8
9
10
# Windows Clash proxy for WSL
export WIN_HOST=$(ip route show | grep -i default | awk '{ print $3}')
export http_proxy="http://${WIN_HOST}:7897"
export https_proxy="http://${WIN_HOST}:7897"
export HTTP_PROXY="http://${WIN_HOST}:7897"
export HTTPS_PROXY="http://${WIN_HOST}:7897"
export all_proxy="http://${WIN_HOST}:7897"
export ALL_PROXY="http://${WIN_HOST}:7897"
export no_proxy="localhost,127.0.0.1,::1"
export NO_PROXY="localhost,127.0.0.1,::1"

作用:

1
让 WSL 终端中的 curl、git、npm、pip 等命令走 Windows Clash 代理。

14.3 VS Code WSL Server 环境变量

文件位置:

1
/home/dky/.vscode-server/server-env-setup

保留:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh

WIN_HOST=$(ip route show | grep -i default | awk '{ print $3 }')

export http_proxy="http://${WIN_HOST}:7897"
export https_proxy="http://${WIN_HOST}:7897"
export HTTP_PROXY="http://${WIN_HOST}:7897"
export HTTPS_PROXY="http://${WIN_HOST}:7897"
export all_proxy="http://${WIN_HOST}:7897"
export ALL_PROXY="http://${WIN_HOST}:7897"
export no_proxy="localhost,127.0.0.1,::1"
export NO_PROXY="localhost,127.0.0.1,::1"

export NODE_USE_ENV_PROXY=1

作用:

1
让 VS Code Server、Extension Host、Codex app-server 等 WSL 内部插件进程也使用正确代理。

14.4 Remote WSL Machine Settings

文件位置:

1
/home/dky/.vscode-server/data/Machine/settings.json

可以保留:

1
2
3
4
{
"http.proxy": "http://172.23.0.1:7897",
"http.proxySupport": "override"
}

但是要注意:

1
2
172.23.0.1 是当前 WSL 中 Windows Host 的 IP。
这个 IP 可能变化。

如果以后失败,重新查看:

1
ip route show | grep -i default | awk '{ print $3 }'

然后更新配置。


15. Windows 的 setx 环境变量要不要删?

之前通过 PowerShell 设置的:

1
2
3
4
5
6
7
8
9
setx HTTP_PROXY "http://127.0.0.1:7897"
setx HTTPS_PROXY "http://127.0.0.1:7897"
setx ALL_PROXY "http://127.0.0.1:7897"
setx NO_PROXY "localhost,127.0.0.1"

setx http_proxy "http://127.0.0.1:7897"
setx https_proxy "http://127.0.0.1:7897"
setx all_proxy "http://127.0.0.1:7897"
setx no_proxy "localhost,127.0.0.1"

是否需要删除,要看使用场景。

如果还需要 Windows 原生 PowerShell、Windows 原生 VS Code、Windows 原生 Codex 走 Clash,可以保留。

如果主要使用 WSL Codex,并且担心再次污染环境,也可以删除 Windows 用户环境变量。

删除方式:

1
2
3
4
5
6
7
8
9
[Environment]::SetEnvironmentVariable("HTTP_PROXY", $null, "User")
[Environment]::SetEnvironmentVariable("HTTPS_PROXY", $null, "User")
[Environment]::SetEnvironmentVariable("ALL_PROXY", $null, "User")
[Environment]::SetEnvironmentVariable("NO_PROXY", $null, "User")

[Environment]::SetEnvironmentVariable("http_proxy", $null, "User")
[Environment]::SetEnvironmentVariable("https_proxy", $null, "User")
[Environment]::SetEnvironmentVariable("all_proxy", $null, "User")
[Environment]::SetEnvironmentVariable("no_proxy", $null, "User")

当前问题已经解决,所以不一定必须删除 Windows setx 环境变量。

最关键的是:

1
不要在 Windows User Settings 中写 http.proxy = http://127.0.0.1:7897。

16. 核心经验总结

16.1 Windows 和 WSL 的 localhost 不是一回事

1
2
3
4
5
6
Windows 中:
127.0.0.1:7897 = Windows 本机 Clash

WSL 中:
127.0.0.1:7897 = WSL 自己
172.23.0.1:7897 = Windows 主机 Clash

所以 WSL 中访问 Windows Clash,应该使用:

1
WIN_HOST=$(ip route show | grep -i default | awk '{ print $3}')

然后使用:

1
http://${WIN_HOST}:7897

16.2 WSL 终端能联网,不代表 VS Code 插件能联网

WSL 终端中的:

1
curl -I https://auth.openai.com

能通,只能说明 shell 环境能走代理。

Codex 插件还需要检查:

1
ps eww -ef | grep "codex app-server" | sed 's/ /\n/g' | grep -i proxy

重点看:

1
2
3
4
5
6
7
HTTP_PROXY
HTTPS_PROXY
http_proxy
https_proxy
ALL_PROXY
all_proxy
NODE_USE_ENV_PROXY

是否都正确。


16.3 大写代理变量尤其重要

很多程序优先读取:

1
2
3
HTTP_PROXY
HTTPS_PROXY
ALL_PROXY

如果大写变量是错误的,即使小写变量正确,也可能失败。

因此正常状态应该是:

1
2
3
4
HTTP_PROXY=http://172.23.0.1:7897
HTTPS_PROXY=http://172.23.0.1:7897
http_proxy=http://172.23.0.1:7897
https_proxy=http://172.23.0.1:7897

不能出现:

1
2
HTTP_PROXY=http://127.0.0.1:7897
HTTPS_PROXY=http://127.0.0.1:7897

17. 快速排查命令

以后如果 Codex WSL 登录又失败,可以按下面顺序检查。

17.1 检查 Windows Host IP

1
ip route show | grep -i default | awk '{ print $3 }'

17.2 检查 WSL 终端代理变量

1
2
3
4
echo $http_proxy
echo $https_proxy
echo $HTTP_PROXY
echo $HTTPS_PROXY

17.3 检查 WSL 能否通过代理访问 OpenAI 认证域名

1
curl -I https://auth.openai.com

或显式指定代理:

1
2
WIN_HOST=$(ip route show | grep -i default | awk '{ print $3}')
curl -x http://${WIN_HOST}:7897 -I https://auth.openai.com

看到下面内容说明代理链路基本正常:

1
HTTP/1.1 200 Connection established

17.4 检查 Codex app-server 实际代理变量

1
ps eww -ef | grep "codex app-server" | sed 's/ /\n/g' | grep -i proxy

重点确认不要出现:

1
127.0.0.1:7897

应该全部是:

1
172.23.0.1:7897

或者当前 ip route 查询到的新 Windows Host IP。


18. 本次问题的最终结论

本次 Codex WSL 登录失败的根本原因是:

1
2
3
4
5
Windows VS Code User Settings 中配置了 http.proxy = http://127.0.0.1:7897。
导致 WSL 中的 Codex app-server 进程错误地使用了 127.0.0.1:7897 作为代理。
而 WSL 中的 127.0.0.1 并不是 Windows Clash。
所以访问 https://auth.openai.com/oauth/token 失败。
最终出现 token_exchange_failed。

最终解决方法是:

1
2
3
删除 Windows User Settings 中的 http.proxy 和 http.proxySupport。
保留 WSL 中 .bashrc 和 server-env-setup 的动态 WIN_HOST 代理配置。
确保 Codex app-server 中 HTTP_PROXY / HTTPS_PROXY 均为 172.23.0.1:7897。

最终验证成功:

1
2
Codex app-server 中所有代理变量均指向 172.23.0.1:7897。
Codex 插件在 WSL VS Code 中可以正常登录。