跳到正文
返回博客列表

博客文章

Codex 代理启动器

2026-04-29

目录

    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按实际本地端口填写脚本
    ModeRule 或 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 需要代理,更合理的方案是使用进程级代理启动器。

    这套方案的核心是:

    1. 本地代理客户端只负责提供本地代理端口
    2. PowerShell 负责查找 Codex 并注入代理
    3. VBS 负责无窗口双击启动
    4. BAT 负责调试
    5. 不修改系统网络、不修改 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. 新旧方案的区别

    旧方案同时做了两件事:

    1. 给 Codex 启动环境注入代理环境变量
    2. 给 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:优先确认是否仍在使用旧版强制代理参数

    这套启动器后续维护的重点,不是不断增加代理参数,而是尽量保持启动逻辑简单、低侵入、可调试。