本地VSCode里的ChatGPT/Codex插件可以正常使用,浏览器也能打开。但是只要在远程vscode里面使用chatGPT插件就一直报403。
我的链路大概是这样的:
VSCode打开Remote SSH远程窗口 ↓插件启用在远程环境 ↓登录请求从远程服务器发出 ↓远程服务器访问目标认证服务失败 ↓本地电脑正常,不代表远程窗口正常 ↓把远程环境的网络链路重新梳理 ↓确认插件所在进程拿到了正确配置 ↓登录恢复正常
最开始我改的是本地VSCode代理配置:
"http.proxy":"http://127.0.0.1:<local_port>","http.proxySupport":"override"
看起来没毛病,但我忽略了一行状态:
Extension is enabled on 'SSH: xxx'
这句话很关键,它说明插件启用在远程端。
这时候真正发起登录请求的,不是我本地电脑,而是远程服务器。
所以只改本地配置,完全没用。
Remote SSH场景里容易误判的地方就在这里:你在本地操作界面,但实际执行逻辑在远程机器上。
所以第一步不是继续改插件,而是先在远程服务器上确认网络链路:
curl -I https://your-target-service.example
如果远程服务器这里就失败,说明问题不在VSCode界面,也不在账号本身,而是远程环境访问目标服务这条路有问题。
后来我又用本地测试环境做了链路验证:
curl -x http://127.0.0.1:<remote_port> -I https://your-target-service.example
如果能看到类似:
HTTP/1.1 200 Connection established
说明远程环境已经能通过指定端口建立连接。
下一步要让远程服务器上有一个可用的本地端口,然后让远程环境里的请求走这个端口。
通用命令可以写成这样:
ssh -N-R <remote_port>:127.0.0.1:<local_port> user@remote-host
这条命令的意思是:
远程服务器 127.0.0.1:<remote_port> ↓通过SSH反向端口 ↓转发到本地电脑 127.0.0.1:<local_port>
注意,这个终端窗口不能关,一关,远程服务器上的这个端口就断了。
然后在远程服务器上配置环境变量:
export http_proxy=http://127.0.0.1:<remote_port>export https_proxy=http://127.0.0.1:<remote_port>export HTTP_PROXY=http://127.0.0.1:<remote_port>export HTTPS_PROXY=http://127.0.0.1:<remote_port>export no_proxy=localhost,127.0.0.1,::1export NO_PROXY=localhost,127.0.0.1,::1
验证一下:
env | grep -i proxy
能看到对应变量,说明远程终端这层已经拿到配置了。
但这里还有一个坑,env有配置,但插件未必有
远程终端里执行:
env | grep -i proxy
输出正常,但插件还是可能失败。
原因是:终端环境好了,不代表VSCode Extension Host环境好了。
插件不是跑在你当前这个bash终端里。它跑在VSCode Remote的Extension Host进程里。
所以真正要查的是:
Extension Host这个进程有没有拿到对应环境变量。
一开始我用了这个命令:
ps eww -p $(pgrep -f "extensionHost" | head -n 1) | tr' ''\n' | grep -i proxy
结果查出来不对,我以为Extension Host一直没有配置。
后来发现,问题不在配置,而在我查错了进程。
我这台远程服务器是多人共用的。
上面有很多人的extensionHost进程。
我用:
pgrep -f "extensionHost" | head -n 1
拿到的很可能不是自己的进程,而是别人的进程。
这个判断一错,后面所有分析都会出问题。
正确做法是只查自己的进程:
for p in $(pgrep -u "$USER" -f extensionHost); doecho"========== PID=$p ==========" ps -o pid,ppid,args -p "$p"echo"--- env proxy ---"tr'\0''\n' < /proc/$p/environ | grep -iE 'proxy|<remote_port>' || echo"NO_PROXY_ENV"done
最后我查到属于自己的Extension Host进程,里面已经能看到对应环境变量。
到这里,链路才算闭环。
不是终端有配置就行,是插件所在的进程也要有配置。
每次手动export太麻烦,可以写进远程服务器的~/.bashrc:
cat >> ~/.bashrc <<'EOF'# Remote development proxy configexport http_proxy=http://127.0.0.1:<remote_port>export https_proxy=http://127.0.0.1:<remote_port>export HTTP_PROXY=http://127.0.0.1:<remote_port>export HTTPS_PROXY=http://127.0.0.1:<remote_port>export no_proxy=localhost,127.0.0.1,::1export NO_PROXY=localhost,127.0.0.1,::1EOFsource ~/.bashrc
然后确认:
env | grep -i proxy
如果远程窗口重连后还能看到这些变量,说明终端这层已经没问题。
我中间也试过Remote Settings。它对某些插件可能有用,但这次真正的判断标准不是设置页里有没有写配置,而是自己的Extension Host进程里有没有真正拿到配置。
以后再遇到类似问题,可以从这四步进行排查。
第一步,本地保持远程端口映射:
ssh -N-R <remote_port>:127.0.0.1:<local_port> user@remote-host
第二步,远程服务器测试链路:
curl -x http://127.0.0.1:<remote_port> -I https://your-target-service.example
第三步,确认远程终端有配置:
env | grep -i proxy
第四步,只查自己的Extension Host:
for p in $(pgrep -u "$USER" -f extensionHost); doecho"========== PID=$p ==========" ps -o pid,ppid,args -p "$p"echo"--- env proxy ---"tr'\0''\n' < /proc/$p/environ | grep -iE 'proxy|<remote_port>' || echo"NO_PROXY_ENV"done
这四步能确认三件事:
远程到本地端口通不通。远程终端有没有配置。真正运行插件的Extension Host有没有配置。
夜雨聆风