1. 问题背景
在 Windows 上使用 Codex Desktop App 时,遇到一个网络代理相关问题:
- 本地代理客户端不接管全局网络时,Codex 无法正常联网
- 开启 TUN 模式后,Codex 可以正常使用
- 但开启 TUN 后,浏览器访问网页明显变慢,部分网页甚至无法访问
- 同一网络环境下,Claude Code App 不需要开启 TUN 就能正常使用
这说明问题并不一定出在代理节点本身,而更可能是:
Codex Desktop 没有稳定识别系统代理,或者没有自动读取当前代理环境。
继续依赖 TUN 可以绕过这个问题,但代价是让代理客户端接管更大范围的系统网络流量。
更合适的处理方式是:不启用 TUN,只让 Codex 进程单独使用本地代理端口。
2. 目标
这次要实现的目标如下:
| 目标 | 说明 |
|---|---|
| Codex 不依赖 TUN | 关闭全局网络接管后,Codex 仍然可以联网 |
| 只影响 Codex | 不修改 Windows 全局代理,不影响浏览器、微信、Steam 等软件 |
| 可双击启动 | 不需要每次手动输入 PowerShell 命令 |
| 可调试 | 启动失败时可以看到错误信息 |
| 不修改 WindowsApps 权限 | 避免破坏 Microsoft Store / MSIX 应用的权限和更新机制 |
最终方案由三个文件组成:
<YOUR_LAUNCHER_DIR>\
├─ codex_launcher.ps1
├─ codex_launcher.vbs
└─ codex_launcher_debug.bat
其中:
| 文件 | 作用 |
|---|---|
codex_launcher.ps1 | 核心启动逻辑,负责查找 Codex、注入代理并启动 |
codex_launcher.vbs | 日常使用,无窗口启动 |
codex_launcher_debug.bat | 调试使用,保留 PowerShell 窗口查看错误 |
3. 原理说明
本地代理客户端通常会在本机开放一个环回地址代理端口,例如:
127.0.0.1:<LOCAL_PROXY_PORT>
只要某个应用显式使用这个代理端口,它就可以通过指定的本地代理出网。
因此可以在启动 Codex 前设置代理环境变量:
$env:HTTP_PROXY = "http://127.0.0.1:<LOCAL_PROXY_PORT>"
$env:HTTPS_PROXY = "http://127.0.0.1:<LOCAL_PROXY_PORT>"
$env:ALL_PROXY = "socks5://127.0.0.1:<LOCAL_PROXY_PORT>"
$env:NO_PROXY = "localhost,127.0.0.1,::1"
同时,Codex Desktop 作为桌面应用,可以在启动时附加代理参数:
--proxy-server=socks5://127.0.0.1:<LOCAL_PROXY_PORT>
--proxy-bypass-list=<-loopback>;localhost;127.0.0.1;::1
这样代理配置只存在于启动器创建的进程链中,不会写入系统环境变量,也不会修改 Windows 全局网络配置。
影响范围如下:
| 对象 | 是否受影响 |
|---|---|
| 通过启动器打开的 Codex | 是 |
| Codex 拉起的子进程 | 可能是 |
| 浏览器 | 否 |
| 微信 | 否 |
| Steam | 否 |
| Windows 全局网络 | 否 |
| 全局网络接管 | 不需要开启 |
4. 本地代理配置
本地代理客户端建议保持以下配置:
| 配置项 | 建议值 |
|---|---|
| TUN Mode | 关闭 |
| System Proxy | 可开可不开 |
| Mixed Port | 按实际本地端口填写脚本 |
| Mode | Rule 或 Global 均可 |
| Allow LAN | 不需要 |
| DNS / Fake-IP | 本方案不依赖 TUN,一般不需要额外处理 |
重点是确认本地代理客户端监听的代理端口。
如果端口发生变化,需要同步修改脚本中的端口:
$env:HTTP_PROXY = "http://127.0.0.1:<LOCAL_PROXY_PORT>"
$env:HTTPS_PROXY = "http://127.0.0.1:<LOCAL_PROXY_PORT>"
$env:ALL_PROXY = "socks5://127.0.0.1:<LOCAL_PROXY_PORT>"
以及启动参数中的端口:
--proxy-server=socks5://127.0.0.1:<LOCAL_PROXY_PORT>
5. Codex 安装路径处理
Codex Desktop 安装在 WindowsApps 目录下,路径通常类似:
C:\Program Files\WindowsApps\OpenAI.Codex_<VERSION>_<ARCH>__<PUBLISHER_ID>\app\Codex.exe
这个路径不适合硬编码,原因有两个:
第一,目录中包含版本号。
Codex 更新后,版本号可能变化,旧路径会失效。
第二,C:\Program Files\WindowsApps 是受保护目录。
即使当前用户是管理员,直接通过资源管理器访问也可能提示拒绝访问。
不建议为了访问该目录执行:
takeown
icacls
这类操作可能破坏 Microsoft Store / MSIX 应用的权限结构,影响后续更新或运行。
更稳妥的方式是通过 PowerShell 自动读取 Appx 包安装位置:
Get-AppxPackage | Where-Object {
$_.Name -like "*Codex*" -or $_.PackageFullName -like "*Codex*"
}
然后拼接出实际的 Codex.exe 路径。
6. 核心脚本:codex_launcher.ps1
创建目录:
<YOUR_LAUNCHER_DIR>\
新建文件:
<YOUR_LAUNCHER_DIR>\codex_launcher.ps1
写入以下内容:
$ErrorActionPreference = "Stop"
try {
Write-Host "Searching Codex..."
$ProxyHost = "127.0.0.1"
$ProxyPort = "<LOCAL_PROXY_PORT>"
$FallbackCodex = ""
$Codex = $null
$pkg = Get-AppxPackage | Where-Object {
$_.Name -like "*Codex*" -or $_.PackageFullName -like "*Codex*"
} | Select-Object -First 1
if ($pkg) {
Write-Host "Found Appx package:"
Write-Host $pkg.PackageFullName
Write-Host "Install location:"
Write-Host $pkg.InstallLocation
$candidate = Join-Path $pkg.InstallLocation "app\Codex.exe"
if (Test-Path $candidate) {
$Codex = $candidate
}
else {
Write-Host "app\Codex.exe not found. Searching recursively..."
$found = Get-ChildItem -Path $pkg.InstallLocation -Filter "Codex.exe" -Recurse -ErrorAction SilentlyContinue |
Select-Object -First 1
if ($found) {
$Codex = $found.FullName
}
}
}
else {
Write-Host "Codex Appx package not found."
}
if (-not $Codex -and $FallbackCodex -ne "") {
Write-Host "Using fallback path..."
if (Test-Path $FallbackCodex) {
$Codex = $FallbackCodex
}
}
if (-not $Codex) {
throw "Codex.exe not found."
}
Write-Host ""
Write-Host "Codex path:"
Write-Host $Codex
Write-Host ""
$env:HTTP_PROXY = "http://${ProxyHost}:${ProxyPort}"
$env:HTTPS_PROXY = "http://${ProxyHost}:${ProxyPort}"
$env:ALL_PROXY = "socks5://${ProxyHost}:${ProxyPort}"
$env:NO_PROXY = "localhost,127.0.0.1,::1"
Write-Host "Starting Codex..."
$args = @(
"--proxy-server=socks5://${ProxyHost}:${ProxyPort}",
"--proxy-bypass-list=<-loopback>;localhost;127.0.0.1;::1"
)
Start-Process -FilePath $Codex -WorkingDirectory (Split-Path $Codex) -ArgumentList $args
Write-Host "Start command executed."
}
catch {
Write-Host ""
Write-Host "Failed to start Codex:"
Write-Host $_.Exception.Message
}
脚本中保留了一个兜底变量:
$FallbackCodex = ""
如果自动查找异常,也可以把它改成已经验证可用的固定路径:
$FallbackCodex = "C:\Program Files\WindowsApps\OpenAI.Codex_<VERSION>_<ARCH>__<PUBLISHER_ID>\app\Codex.exe"
但长期使用时更推荐依赖自动查找,避免 Codex 更新后路径失效。
7. 日常启动器:codex_launcher.vbs
为了避免每次手动执行 PowerShell 命令,可以使用 VBS 做一个无窗口启动器。
新建文件:
<YOUR_LAUNCHER_DIR>\codex_launcher.vbs
写入:
Set shell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
scriptDir = fso.GetParentFolderName(WScript.ScriptFullName)
ps1Path = fso.BuildPath(scriptDir, "codex_launcher.ps1")
cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File " & Chr(34) & ps1Path & Chr(34)
shell.Run cmd, 0, False
关键是这一行:
shell.Run cmd, 0, False
含义如下:
| 参数 | 作用 |
|---|---|
cmd | 要执行的 PowerShell 启动命令 |
0 | 隐藏窗口 |
False | 不等待 PowerShell 结束 |
日常使用时,直接双击:
codex_launcher.vbs
启动链路如下:
codex_launcher.vbs
↓
powershell.exe
↓
codex_launcher.ps1
↓
set proxy environment variables
↓
find Codex.exe
↓
Start-Process Codex.exe with proxy args
8. 调试入口:codex_launcher_debug.bat
如果双击 VBS 后没有反应,需要一个可以显示错误信息的调试入口。
新建文件:
<YOUR_LAUNCHER_DIR>\codex_launcher_debug.bat
写入:
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -NoExit -File "%~dp0codex_launcher.ps1"
pause
调试版会保留 PowerShell 窗口。
如果脚本路径、Codex 安装路径、PowerShell 解析或代理端口存在问题,可以直接在窗口中看到错误信息。
注意,调试版只用于排查问题。
日常使用不建议通过它启动 Codex。
9. 为什么关闭 BAT 后 Codex 也会关闭
如果使用的是调试版 BAT:
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -NoExit -File "%~dp0codex_launcher.ps1"
pause
其中:
-NoExit
pause
会让 PowerShell 窗口一直保留。
如果此时直接关闭这个黑框,Windows 可能会连带结束同一控制台关联下的子进程,导致 Codex 也被关闭。
正确做法是:
- 日常使用
codex_launcher.vbs - 调试时才使用
codex_launcher_debug.bat - 不要手动关闭调试黑框来结束启动流程
日常启动时,PowerShell 会自动执行完并退出,Codex 会独立运行。
10. 编码问题
编写 Windows 脚本时,PowerShell 文件中的中文字符串可能触发编码问题。
曾经出现过类似错误:
Read-Host "鎸?Enter 鍏抽棴绐楀彛"
字符串缺少终止符: "
这类问题通常不是 PowerShell 逻辑错误,而是文件编码不一致导致中文字符串被破坏。
处理方式:
.ps1、.bat、.vbs中尽量使用英文 ASCII 字符- 如果必须写中文,保存为 UTF-8
- 避免在多个编辑器之间反复切换编码保存
- 调试阶段优先使用
codex_launcher_debug.bat查看完整错误
在这个启动器场景中,脚本不需要中文提示,因此全部使用英文最稳。
11. 桌面快捷方式
可以为 codex_launcher.vbs 创建桌面快捷方式:
右键 codex_launcher.vbs
发送到
桌面快捷方式
以后直接双击桌面快捷方式即可启动 Codex。
如果需要自定义图标,建议使用单独的 .ico 文件。
不建议为了使用 Codex 原始图标去修改或访问 WindowsApps 目录权限。
12. 常见问题
12.1 双击 VBS 没反应
使用调试入口:
codex_launcher_debug.bat
查看 PowerShell 窗口中的错误信息。
12.2 提示找不到 Codex.exe
可能原因包括:
- Codex Desktop 没有安装
- Appx 包名发生变化
- Codex 安装目录结构变化
- 当前用户环境中
Get-AppxPackage查询不到 Codex
可以手动测试:
Get-AppxPackage | Where-Object {
$_.Name -like "*Codex*" -or $_.PackageFullName -like "*Codex*"
}
如果能看到 Codex 包,说明应用包存在。
12.3 Codex 能启动,但不能联网
按以下顺序检查:
| 检查项 | 说明 |
|---|---|
| 本地代理客户端是否运行 | 代理客户端必须先启动 |
| 本地代理端口是否一致 | 如果不一致,需要修改脚本端口 |
| 代理连接是否可用 | 先确认当前代理配置能访问目标网络 |
| 是否通过启动器启动 Codex | 不要使用原始 Codex 图标启动 |
| 全局网络接管是否关闭 | 本方案不依赖 TUN |
12.4 浏览器会不会被代理脚本影响
不会。
脚本中的代理变量只存在于当前 PowerShell 进程以及由它启动的 Codex 进程中。
它不会写入 Windows 用户环境变量,也不会修改系统代理。
12.5 Codex 更新后是否需要修改脚本
通常不需要。
脚本会通过 Get-AppxPackage 自动读取当前 Codex 安装位置。
只有在 Codex 包名或目录结构发生变化时,才需要调整查找逻辑。
13. 最终效果
完成后,实际使用方式是:
双击 codex_launcher.vbs
最终效果如下:
| 目标 | 是否实现 |
|---|---|
| Codex 不开 TUN 也能使用 | 是 |
| 浏览器不受 TUN 影响 | 是 |
| 只让 Codex 走代理 | 是 |
| 不修改 Windows 全局代理 | 是 |
| 不修改 WindowsApps 权限 | 是 |
| 可双击启动 | 是 |
| 可调试 | 是 |
14. 总结
Codex Desktop 在 Windows 上无法直接读取当前代理环境时,不一定要开启 TUN。
TUN 是全局网络接管方案,适合兜底处理不遵循系统代理的软件,但副作用也更大。
如果只是 Codex 需要代理,更合理的方案是使用进程级代理启动器。
这套方案的核心是:
- 本地代理客户端只负责提供本地代理端口
- PowerShell 负责查找 Codex 并注入代理
- VBS 负责无窗口双击启动
- BAT 负责调试
- 不修改系统网络、不修改 WindowsApps 权限、不依赖 TUN
最终链路是:
codex_launcher.vbs
↓
codex_launcher.ps1
↓
Set proxy env
↓
Find Codex.exe
↓
Start Codex with proxy args
↓
Codex uses local proxy
这个方案的核心价值是:
把代理影响范围从整个系统缩小到 Codex 这个具体应用。
15. 追加说明(5月1日):Codex 更新后出现 Reconnecting
后续使用过程中,Codex 更新后曾出现过一个新的现象:
Codex 可以正常启动,但对话区域一直显示 reconnecting
这类问题和前面的“启动器打不开”不是同一种问题。
- 启动器打不开:通常是路径、权限、编码或脚本执行问题
- Codex 打开后一直 reconnecting:通常是 Codex 内部网络连接没有稳定建立
这说明 Codex.exe 已经被成功启动,但 Codex 客户端与其内部服务、远端服务或会话通道之间的连接出现了异常。
这次定位后,最可疑的点是旧脚本中的启动参数:
$args = @(
"--proxy-server=socks5://${ProxyHost}:${ProxyPort}",
"--proxy-bypass-list=<-loopback>;localhost;127.0.0.1;::1"
)
Start-Process -FilePath $Codex -WorkingDirectory (Split-Path $Codex) -ArgumentList $args
这组参数属于比较强的代理干预方式。它会直接影响 Codex 主进程的网络行为。更新前,这种方式可以正常工作;更新后,Codex 内部网络结构可能发生变化,强制代理参数开始干扰应用自己的连接,于是出现 reconnecting。
因此,后续推荐把启动方式调整为:
只保留代理环境变量,不再传入
--proxy-server和--proxy-bypass-list启动参数。
16. 新旧方案的区别
旧方案同时做了两件事:
- 给 Codex 启动环境注入代理环境变量
- 给 Codex 主进程传入代理启动参数
也就是:
HTTP_PROXY / HTTPS_PROXY / ALL_PROXY
+
--proxy-server / --proxy-bypass-list
这种方式代理力度更强,适合解决“应用完全不读取系统代理”的问题。缺点是它可能干扰桌面应用自身的内部通信。
新方案只保留第一部分:
HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY
不再传入:
--proxy-server
--proxy-bypass-list
两者差异如下:
| 方案 | 实现方式 | 干预强度 | 风险 |
|---|---|---|---|
| 旧方案 | 环境变量 + 启动参数 | 高 | 可能干扰 Codex 主进程内部连接 |
| 新方案 | 仅环境变量 | 中 | 更温和,更不容易误伤内部通信 |
旧方案更像是:
强制 Codex 主进程按指定代理规则走。
新方案更像是:
给 Codex 的启动环境提供代理信息,让它按需使用代理。
因此,新方案对 Codex 内部网络结构的侵入更低,更适合长期使用。
17. 推荐更新后的核心脚本写法
如果遇到 Codex 能打开但一直 reconnecting,建议把 codex_launcher.ps1 中的启动参数部分删除。
需要删除的是这一段:
$args = @(
"--proxy-server=socks5://${ProxyHost}:${ProxyPort}",
"--proxy-bypass-list=<-loopback>;localhost;127.0.0.1;::1"
)
Start-Process -FilePath $Codex -WorkingDirectory (Split-Path $Codex) -ArgumentList $args
替换为:
Start-Process -FilePath $Codex -WorkingDirectory (Split-Path $Codex)
保留前面的环境变量设置:
$env:HTTP_PROXY = "http://${ProxyHost}:${ProxyPort}"
$env:HTTPS_PROXY = "http://${ProxyHost}:${ProxyPort}"
$env:ALL_PROXY = "socks5://${ProxyHost}:${ProxyPort}"
$env:NO_PROXY = "localhost,127.0.0.1,::1"
最终推荐的启动部分如下:
$env:HTTP_PROXY = "http://${ProxyHost}:${ProxyPort}"
$env:HTTPS_PROXY = "http://${ProxyHost}:${ProxyPort}"
$env:ALL_PROXY = "socks5://${ProxyHost}:${ProxyPort}"
$env:NO_PROXY = "localhost,127.0.0.1,::1"
Write-Host "Starting Codex..."
Start-Process -FilePath $Codex -WorkingDirectory (Split-Path $Codex)
Write-Host "Start command executed."
调整后,启动链路变成:
codex_launcher.vbs
↓
codex_launcher.ps1
↓
Set proxy environment variables
↓
Find Codex.exe
↓
Start Codex.exe
↓
Codex reads proxy env when needed
也就是说,启动器仍然只影响通过它启动的 Codex,不会修改 Windows 全局代理,也不会影响浏览器等其他应用。
18. 为什么更新前正常,更新后不正常
旧方案在更新前可以使用,并不代表它在机制上永远稳定。
更准确地说,旧方案当时是“刚好兼容”:
- Codex 当时的内部连接方式没有被
--proxy-server影响 --proxy-bypass-list当时没有干扰到关键连接- Codex 主进程可以在强制代理参数下正常完成会话通信
但 Codex Desktop 更新后,内部实现可能发生变化,例如:
- 本地客户端与内部服务之间的连接方式变化
- 登录态同步方式变化
- WebSocket 或长连接路径变化
- 本地回环地址通信逻辑变化
- 主进程和子进程的网络职责发生调整
此时,原本可以正常工作的强制代理参数就可能开始误伤内部通信。表现出来就是:
应用能打开
界面能加载
但对话区域一直 reconnecting
这类现象说明问题不在启动路径,也不在 VBS 或 BAT,而在于 Codex 启动后的网络连接链路。
所以,这次调整的核心不是“修路径”,而是降低代理方案对 Codex 主进程网络层的干预。
19. 下次更新还会不会出问题
这套新方案不能保证永久不出问题,但比旧方案更抗更新。
原因有两个。
第一,脚本没有写死 Codex 的版本号路径,而是通过 Appx 包自动查找安装位置。普通版本更新导致的目录变化,一般不会影响启动器。
第二,新方案删除了 --proxy-server 和 --proxy-bypass-list,不再强行接管 Codex 主进程的网络栈。即使 Codex 内部网络结构继续调整,也更不容易被启动参数误伤。
但仍然存在几类风险:
| 风险 | 说明 | 概率 |
|---|---|---|
| Codex 包名变化 | 自动查找逻辑依赖包名或包名中包含 Codex | 低 |
| Codex.exe 改名 | 递归查找依赖可执行文件仍叫 Codex.exe | 中低 |
| 安装结构变化 | app\Codex.exe 不再存在,但递归查找通常能兜底 | 中低 |
| Codex 不再读取代理环境变量 | 新方案依赖环境变量被应用或相关进程读取 | 中 |
| 本地代理端口变化 | 端口变化后必须同步改脚本 | 中 |
因此,后续更新后的判断方式应该是:
先直接双击 codex_launcher.vbs
如果正常联网,不需要改任何东西。
如果打不开,用:
codex_launcher_debug.bat
看是否是路径、包名或脚本执行问题。
如果能打开但不能联网,优先检查:
- 本地代理客户端是否运行
- 本地代理端口是否变化
- Codex 是否仍然能读取代理环境变量
- 是否误用了旧版带
--proxy-server参数的脚本
20. 当前推荐结论
目前更推荐使用“仅环境变量”的版本作为默认方案。
也就是:
保留:HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY
删除:--proxy-server / --proxy-bypass-list
这不是因为旧方案完全错误,而是因为旧方案干预更强,短期可用但更容易被 Codex 更新破坏。
新方案的核心取舍是:
用更低的网络干预强度,换取更好的更新兼容性。
如果后续 Codex 再次更新,只要没有出现新的联网问题,就不需要继续调整脚本。
如果再次出现问题,也应先判断问题类型:
- 找不到 Codex:检查 Appx 包名和安装路径
- 能启动但不能联网:检查代理端口和环境变量
- 能启动但 reconnecting:优先确认是否仍在使用旧版强制代理参数
这套启动器后续维护的重点,不是不断增加代理参数,而是尽量保持启动逻辑简单、低侵入、可调试。