0%

vscode devcontainer中codex插件代理问题记录

vscode devcontainer中codex插件代理问题记录

问题环境:

  • 系统:Windows + Docker Desktop + VS Code Dev Container
  • 容器:road_ortho
  • 项目路径:/code/road_ortho_code/road_lunwen_code/merge_tiffs_lunwen_code_newest
  • 代理端口:宿主机 7897
  • 容器访问宿主机代理地址:http://host.docker.internal:7897

问题现象:

在 VS Code 的 Codex 插件中反复出现网络请求失败,日志类似:

1
2
3
4
Error fetching error="TypeError: fetch failed" url=https://ab.chatgpt.com/v1/initialize
Error fetching error="TypeError: fetch failed" url=https://chatgpt.com/ces/v1/rgstr
Error fetching error="TypeError: fetch failed" url=/wham/accounts/check
Error fetching error="TypeError: fetch failed" url=/wham/tasks/list?limit=20&task_filter=current

同时还可能出现:

1
unsupported feature enablement `workspace_dependencies`

以及 Git 或 VS Code Remote 日志中出现:

1
2
Failed to connect to 127.0.0.1 port 7897
Failed to establish a socket connection to proxies: PROXY 127.0.0.1:7897

问题原因

核心原因:容器内的 127.0.0.1 不是 Windows 宿主机。

在 Windows 上代理软件监听:

1
127.0.0.1:7897

但是 Codex 插件运行在 Docker 容器中。容器内部访问 127.0.0.1:7897 时,访问的是容器自己,而不是 Windows 宿主机,因此会连接失败。

在 Docker Desktop 环境中,容器访问宿主机应使用:

1
host.docker.internal

因此容器内正确代理地址是:

1
http://host.docker.internal:7897

需要修改的位置

这个问题不是只改一个环境变量即可,因为 VS Code Codex 插件涉及多层进程:

  • VS Code Remote Server
  • VS Code extensionHost
  • OpenAI ChatGPT/Codex 插件
  • Codex app-server
  • Git

所以需要同时处理以下位置。

1. VS Code Remote Server 环境变量

文件:

1
/root/.vscode-server/server-env-setup

内容:

1
2
3
4
5
6
7
8
export HTTP_PROXY=http://host.docker.internal:7897
export HTTPS_PROXY=http://host.docker.internal:7897
export ALL_PROXY=http://host.docker.internal:7897
export http_proxy=http://host.docker.internal:7897
export https_proxy=http://host.docker.internal:7897
export all_proxy=http://host.docker.internal:7897
export NO_PROXY=localhost,127.0.0.1,::1
export no_proxy=localhost,127.0.0.1,::1

2. VS Code Remote settings

文件:

1
/root/.vscode-server/data/Machine/settings.json

需要包含:

1
2
3
4
5
{
"http.proxy": "http://host.docker.internal:7897",
"http.proxyStrictSSL": false,
"http.proxySupport": "off"
}

其中:

  • http.proxy:设置容器可访问的代理地址
  • http.proxySupport: off:避免 VS Code Remote 继续把宿主机的 127.0.0.1:7897 代理注入到容器内部

3. Git 全局代理

在容器中执行:

1
2
git config --global http.proxy http://host.docker.internal:7897
git config --global https.proxy http://host.docker.internal:7897

检查:

1
git config --global --get-regexp proxy

正确结果应类似:

1
2
http.proxy http://host.docker.internal:7897
https.proxy http://host.docker.internal:7897

4. Codex 插件启动脚本

Codex 插件自带的启动文件位置类似:

1
/root/.vscode-server/extensions/openai.chatgpt-版本号-linux-x64/bin/linux-x86_64/codex

需要将其替换为 wrapper,使 Codex app-server 启动时继承正确代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
export HTTP_PROXY=http://host.docker.internal:7897
export HTTPS_PROXY=http://host.docker.internal:7897
export ALL_PROXY=http://host.docker.internal:7897
export http_proxy=http://host.docker.internal:7897
export https_proxy=http://host.docker.internal:7897
export all_proxy=http://host.docker.internal:7897
export NO_PROXY=localhost,127.0.0.1,::1
export no_proxy=localhost,127.0.0.1,::1
if command -v /usr/local/bin/codex >/dev/null 2>&1; then
exec /usr/local/bin/codex "$@"
fi
exec "$(dirname "$0")/codex.real" "$@"

其中:

  • 原始插件二进制保存为:codex.real
  • 优先使用 npm 安装的稳定版:/usr/local/bin/codex
  • 如果没有 npm 版本,则回退到插件自带的 codex.real

一键修复脚本

已经在项目中保存脚本:

1
/mnt/f/code/road_ortho/road_ortho_code/road_lunwen_code/merge_tiffs_lunwen_code_newest/scripts/fix_codex_vscode_proxy.sh

以后再次出现类似问题,直接在项目根目录执行:

1
./scripts/fix_codex_vscode_proxy.sh

脚本默认参数:

1
2
3
CONTAINER_NAME=road_ortho
PROXY_URL=http://host.docker.internal:7897
RESTART_VSCODE=1

如果容器名或代理端口变化,可以这样运行:

1
CONTAINER_NAME=road_ortho PROXY_URL=http://host.docker.internal:7897 ./scripts/fix_codex_vscode_proxy.sh

如果只想写配置,不想立即停止 VS Code 相关进程:

1
RESTART_VSCODE=0 ./scripts/fix_codex_vscode_proxy.sh

完整脚本代码

文件名:

1
scripts/fix_codex_vscode_proxy.sh

完整内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env bash
set -euo pipefail

CONTAINER_NAME="${CONTAINER_NAME:-road_ortho}"
PROXY_URL="${PROXY_URL:-http://host.docker.internal:7897}"
RESTART_VSCODE="${RESTART_VSCODE:-1}"

if ! docker inspect "$CONTAINER_NAME" >/dev/null 2>&1; then
echo "Container not found: $CONTAINER_NAME" >&2
echo "Set CONTAINER_NAME=... if your container name changed." >&2
exit 1
fi

echo "Fixing VS Code Codex proxy in container: $CONTAINER_NAME"
echo "Proxy: $PROXY_URL"

docker exec \
-e PROXY_URL="$PROXY_URL" \
-e RESTART_VSCODE="$RESTART_VSCODE" \
"$CONTAINER_NAME" \
sh -s <<'EOF'
set -eu

proxy="${PROXY_URL:-http://host.docker.internal:7897}"
restart="${RESTART_VSCODE:-1}"
vscode_root="/root/.vscode-server"

echo "Writing $vscode_root/server-env-setup"
mkdir -p "$vscode_root"
cat > "$vscode_root/server-env-setup" <<ENVEOF
export HTTP_PROXY=$proxy
export HTTPS_PROXY=$proxy
export ALL_PROXY=$proxy
export http_proxy=$proxy
export https_proxy=$proxy
export all_proxy=$proxy
export NO_PROXY=localhost,127.0.0.1,::1
export no_proxy=localhost,127.0.0.1,::1
ENVEOF
chmod 644 "$vscode_root/server-env-setup"

echo "Writing VS Code machine settings"
mkdir -p "$vscode_root/data/Machine"
python3 - <<PYEOF
import json
from pathlib import Path

p = Path("/root/.vscode-server/data/Machine/settings.json")
try:
data = json.loads(p.read_text())
except FileNotFoundError:
data = {}
except json.JSONDecodeError:
backup = p.with_suffix(p.suffix + ".bak_proxyfix")
backup.write_text(p.read_text())
data = {}

data["http.proxy"] = "$proxy"
data["http.proxyStrictSSL"] = False
data["http.proxySupport"] = "off"
p.write_text(json.dumps(data, indent="\t", ensure_ascii=False))
PYEOF

echo "Writing Git proxy"
git config --global http.proxy "$proxy"
git config --global https.proxy "$proxy"

echo "Patching OpenAI ChatGPT/Codex extension launchers"
for codex_bin in /root/.vscode-server/extensions/openai.chatgpt-*/bin/linux-x86_64/codex; do
[ -e "$codex_bin" ] || continue
codex_dir="$(dirname "$codex_bin")"

if [ ! -f "$codex_dir/codex.real" ]; then
cp "$codex_bin" "$codex_dir/codex.real"
fi

cat > "$codex_bin" <<SH_EOF
#!/bin/sh
export HTTP_PROXY=$proxy
export HTTPS_PROXY=$proxy
export ALL_PROXY=$proxy
export http_proxy=$proxy
export https_proxy=$proxy
export all_proxy=$proxy
export NO_PROXY=localhost,127.0.0.1,::1
export no_proxy=localhost,127.0.0.1,::1
if command -v /usr/local/bin/codex >/dev/null 2>&1; then
exec /usr/local/bin/codex "\$@"
fi
exec "\$(dirname "\$0")/codex.real" "\$@"
SH_EOF
chmod +x "$codex_bin"
echo "Patched: $codex_bin"
done

echo "Current proxy config:"
git config --global --get-regexp proxy || true
cat "$vscode_root/server-env-setup"

if [ "$restart" = "1" ]; then
echo "Stopping VS Code server/extensionHost/Codex app-server processes."
# VS Code will restart these when the window/dev-container reconnects.
pkill -f "openai.chatgpt.*codex" 2>/dev/null || true
pkill -f "codex app-server" 2>/dev/null || true
pkill -f "bootstrap-fork --type=extensionHost" 2>/dev/null || true
pkill -f "out/server-main.js" 2>/dev/null || true
fi
EOF

echo
echo "Done."
if [ "$RESTART_VSCODE" = "1" ]; then
echo "Now run 'Reload Window' in VS Code, or reconnect the Dev Container."
fi

修复后需要做的操作

执行脚本后,需要在 VS Code 中执行:

1
Reload Window

或者重新连接 Dev Container。

原因是:

1
/root/.vscode-server/server-env-setup

只会在新的 VS Code Remote Server / extensionHost 启动时读取。旧进程不会自动更新已经继承的环境变量。

验证方法

查看 Codex 进程

1
docker exec road_ortho sh -lc 'ps aux | grep -E "openai.chatgpt|codex|extensionHost" | grep -v grep'

查看 Codex app-server 环境变量

1
docker exec road_ortho sh -lc 'pid=$(pgrep -f "codex app-server" | head -n 1); tr "\0" "\n" < /proc/$pid/environ | grep -i proxy'

正确结果应包含:

1
2
3
4
HTTP_PROXY=http://host.docker.internal:7897
HTTPS_PROXY=http://host.docker.internal:7897
ALL_PROXY=http://host.docker.internal:7897
NO_PROXY=localhost,127.0.0.1,::1

查看 Git 代理

1
docker exec road_ortho git config --global --get-regexp proxy

正确结果:

1
2
http.proxy http://host.docker.internal:7897
https.proxy http://host.docker.internal:7897

测试容器访问代理

1
docker exec road_ortho curl -I --max-time 8 -x http://host.docker.internal:7897 https://chatgpt.com

如果能返回 HTTP 响应,说明容器可以通过宿主机代理访问外网。

注意事项

unsupported feature enablement workspace_dependencies 不一定是代理问题。

这个错误表示当前 Codex app-server 不支持 VS Code 插件尝试启用的某个 experimental feature。它可能和插件版本、Codex CLI 版本有关。

但是如果同时出现:

1
2
3
TypeError: fetch failed
Failed to connect to 127.0.0.1 port 7897
PROXY 127.0.0.1:7897

则优先处理代理问题。

总结

这个问题的关键不是代理端口本身,而是 Docker 容器中的地址语义:

1
127.0.0.1:7897

在容器中表示容器自己,不是 Windows 宿主机。

因此容器内所有 VS Code、Codex、Git 相关代理都应统一改为:

1
http://host.docker.internal:7897

并在修改后重启 VS Code Remote / Dev Container,使新环境变量生效。