Windows 代理配置教程
v2rayN · mixed 端口 127.0.0.1:10808 Codex Claude Code PowerShell

Windows 代理配置教程

v2rayN 本机代理 同时打通到 Windows 系统、命令行工具、Codex、Claude Code 与浏览器。 日常只记三个命令:po 开启、ph 取消、psw 查看。

01 Overview

这套配置在解决什么

浏览器走代理不代表 CLI 也走代理。本教程把代理写到三处入口: Windows 系统代理(浏览器)用户级环境变量(CLI)工具自身配置(Git / npm / pnpm / Codex / Claude),并用一个脚本统一管理。

po · OUTSIDE

一键开启代理

同时写入 Windows 环境变量、系统代理、Git/npm/yarn/pnpm、Codex 的 config.toml 与 Claude 的 settings.json,所有路径统一指向 10808。

ph · HOME

一键取消代理

清理环境变量、关闭系统代理、移除工具链代理、剥离 Codex 托管块、清空 Claude env 字段。直连状态可重复幂等执行。

psw · STATUS

一键查看状态

输出当前环境变量、注册表中的系统代理、Git / npm / pnpm 代理、Codex 配置路径与 Claude 的 env 字段,判断到底在哪一层生效。

i
本教程不包含家庭局域网 / OpenWrt / PassWall 场景,只保留 OUTSIDE(开启)HOME(取消)STATUS(查看) 三个模式。
02 Mental Model

代理不是一个开关,而是多层入口

不同程序读取代理的方式不一样,所以要在每一层都把代理写清楚,而不是只开一个系统代理就指望全覆盖。

体系影响对象典型场景脚本管理
WinINET 系统代理 当前用户图形应用 Edge / Chrome / 部分 Electron outside ✅ / home ❌
用户级环境变量 命令行与跨平台工具 curl / git / npm / node / python / Codex 子进程 outside ✅ / home ❌
工具自身配置 单个工具 git config / npm config / Codex TOML outside ✅ / home ❌
Codex shell_environment_policy Codex 启动的子进程 ~/.codex/config.toml 管理块 outside ✅ / home ❌
Claude Code env Claude Code 会话 ~/.claude/settings.json 的 env 字段 outside ✅ / home ❌

v2rayN 入口

使用 mixed 端口 127.0.0.1:10808,同时接受 HTTP 与 SOCKS5。

注:https_proxy=http://... 不是写错,而是用 HTTP 代理协议为 HTTPS 建立 CONNECT 隧道。

关键路径

切换脚本
%USERPROFILE%\Documents\PowerShell\proxy-switch.ps1
PS Profile
%USERPROFILE%\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
Codex 配置
%USERPROFILE%\.codex\config.toml
Claude 配置
%USERPROFILE%\.claude\settings.json
03 AI Tools

Codex / Claude Code 的代理片段

Codex 通过 shell_environment_policy 给子进程注入代理;Claude Code 通过 settings.jsonenv 字段注入会话代理。

TOML ~/.codex/config.toml · 由 proxy-switch.ps1 托管
# >>> proxy-switch managed shell_environment_policy
[shell_environment_policy]
inherit = "core"

[shell_environment_policy.set]
http_proxy = "http://127.0.0.1:10808"
https_proxy = "http://127.0.0.1:10808"
HTTP_PROXY = "http://127.0.0.1:10808"
HTTPS_PROXY = "http://127.0.0.1:10808"
all_proxy = "socks5://127.0.0.1:10808"
ALL_PROXY = "socks5://127.0.0.1:10808"
no_proxy = "localhost,127.0.0.1,::1"
NO_PROXY = "localhost,127.0.0.1,::1"
# <<< proxy-switch managed shell_environment_policy
JSON ~/.claude/settings.json · 由 proxy-switch.ps1 托管
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "env": {
    "HTTP_PROXY": "http://127.0.0.1:10808",
    "HTTPS_PROXY": "http://127.0.0.1:10808",
    "NO_PROXY": "localhost,127.0.0.1"
  }
}
!
Codex 的 config.toml 不要手工反复改:执行 po / ph 会在标记块之间自动写入或剥离,并生成 config.toml.bak 备份。
Claude Code 仅写入 HTTP_PROXY / HTTPS_PROXY / NO_PROXY 三个大写键,不写入 SOCKS、不写入小写键。po 写入 env 字段,ph 整体移除该字段,每次写入前生成 settings.json.bak 备份。
04 Switch Script

proxy-switch.ps1 · 一处脚本统管所有入口

脚本接收 -Mode 参数(home / outside / status)。outside 同时写入环境变量、系统代理、工具链代理、Codex 托管块与 Claude env 字段;home 全部清理;status 只读输出。

OUTSIDE

Env + WinINET + Git/npm/yarn/pnpm + Codex TOML + Claude settings.json 全部指向 10808,并刷新 WinINet 让浏览器立即生效。

HOME

清空 Env、关闭 WinINET、卸载工具链代理、剥离 Codex 托管块、移除 Claude envconfig.tomlsettings.json 自动备份。

STATUS

分区打印当前 Env / 注册表 / Git / npm / pnpm / Codex / Claude 状态,便于排障。

PS1 C:\Users\Dan\Documents\PowerShell\proxy-switch.ps1
param(
    [ValidateSet("home", "outside", "status")]
    [string]$Mode = "status"
)

# ============================================================
# proxy-switch.ps1
# 说明:
#   home    = 取消本机显式代理
#   outside = 开启本机 v2rayN 127.0.0.1:10808 代理
#   status  = 查看当前代理状态
# ============================================================

$LocalHttp        = "http://127.0.0.1:10808"
$LocalSocks       = "socks5://127.0.0.1:10808"
$LocalSystemProxy = "127.0.0.1:10808"

$NoProxy = "localhost,127.0.0.1,::1"
$ClaudeNoProxy = "localhost,127.0.0.1"
$CodexConfig = Join-Path $env:USERPROFILE ".codex\config.toml"

function Update-InternetSettings {
    try {
        Add-Type -Namespace WinINet -Name NativeMethods -MemberDefinition @"
[System.Runtime.InteropServices.DllImport("wininet.dll", SetLastError = true)]
public static extern bool InternetSetOption(System.IntPtr hInternet, int dwOption, System.IntPtr lpBuffer, int dwBufferLength);
"@ -ErrorAction SilentlyContinue

        [WinINet.NativeMethods]::InternetSetOption([IntPtr]::Zero, 39, [IntPtr]::Zero, 0) | Out-Null
        [WinINet.NativeMethods]::InternetSetOption([IntPtr]::Zero, 37, [IntPtr]::Zero, 0) | Out-Null
    } catch {
        Write-Host "WinINet refresh skipped." -ForegroundColor DarkYellow
    }
}

function Set-ProxyEnv {
    param(
        [string]$HttpProxy,
        [string]$SocksProxy
    )

    $pairs = @(
        @("http_proxy",  $HttpProxy),
        @("https_proxy", $HttpProxy),
        @("HTTP_PROXY",  $HttpProxy),
        @("HTTPS_PROXY", $HttpProxy),
        @("all_proxy",   $SocksProxy),
        @("ALL_PROXY",   $SocksProxy),
        @("no_proxy",    $NoProxy),
        @("NO_PROXY",    $NoProxy)
    )

    foreach ($pair in $pairs) {
        $name  = $pair[0]
        $value = $pair[1]

        [Environment]::SetEnvironmentVariable($name, $value, "User")
        Set-Item -Path "Env:\$name" -Value $value
    }
}

function Clear-ProxyEnv {
    $names = @(
        "http_proxy",
        "https_proxy",
        "HTTP_PROXY",
        "HTTPS_PROXY",
        "all_proxy",
        "ALL_PROXY",
        "no_proxy",
        "NO_PROXY"
    )

    foreach ($name in $names) {
        [Environment]::SetEnvironmentVariable($name, $null, "User")
        Remove-Item "Env:\$name" -ErrorAction SilentlyContinue
    }
}

function Enable-SystemProxy {
    param([string]$ProxyServer)

    $path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
    Set-ItemProperty -Path $path -Name ProxyEnable -Value 1
    Set-ItemProperty -Path $path -Name ProxyServer -Value $ProxyServer
    Update-InternetSettings
}

function Disable-SystemProxy {
    $path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
    Set-ItemProperty -Path $path -Name ProxyEnable -Value 0
    Remove-ItemProperty -Path $path -Name ProxyServer -ErrorAction SilentlyContinue
    Update-InternetSettings
}

function Set-ToolProxy {
    param(
        [string]$HttpProxy,
        [string]$SocksProxy
    )

    if (Get-Command git -ErrorAction SilentlyContinue) {
        git config --global http.proxy  $SocksProxy
        git config --global https.proxy $SocksProxy
    }

    if (Get-Command npm -ErrorAction SilentlyContinue) {
        npm config set proxy       $HttpProxy 2>$null
        npm config set https-proxy $HttpProxy 2>$null
    }

    if (Get-Command yarn -ErrorAction SilentlyContinue) {
        yarn config set proxy       $HttpProxy 2>$null
        yarn config set https-proxy $HttpProxy 2>$null
    }

    if (Get-Command pnpm -ErrorAction SilentlyContinue) {
        pnpm config set proxy       $HttpProxy 2>$null
        pnpm config set https-proxy $HttpProxy 2>$null
    }
}

function Clear-ToolProxy {
    if (Get-Command git -ErrorAction SilentlyContinue) {
        git config --global --unset http.proxy 2>$null
        git config --global --unset https.proxy 2>$null
    }

    if (Get-Command npm -ErrorAction SilentlyContinue) {
        npm config delete proxy 2>$null
        npm config delete https-proxy 2>$null
    }

    if (Get-Command yarn -ErrorAction SilentlyContinue) {
        yarn config delete proxy 2>$null
        yarn config delete https-proxy 2>$null
    }

    if (Get-Command pnpm -ErrorAction SilentlyContinue) {
        pnpm config delete proxy 2>$null
        pnpm config delete https-proxy 2>$null
    }
}

function Get-CodexConfigPath {
    $codexDir = Join-Path $env:USERPROFILE ".codex"
    New-Item -ItemType Directory -Force -Path $codexDir | Out-Null
    return (Join-Path $codexDir "config.toml")
}

function Get-ClaudeSettingsPath {
    $claudeDir = Join-Path $env:USERPROFILE ".claude"
    New-Item -ItemType Directory -Force -Path $claudeDir | Out-Null
    return (Join-Path $claudeDir "settings.json")
}

function Remove-ProxySwitchManagedBlock {
    param([string]$Content)

    if ([string]::IsNullOrWhiteSpace($Content)) {
        return ""
    }

    $pattern = '(?ms)^\s*# >>> proxy-switch managed shell_environment_policy\s*\r?\n.*?^\s*# <<< proxy-switch managed shell_environment_policy\s*\r?\n?'
    return ($Content -replace $pattern, '').TrimEnd()
}

function Remove-ShellEnvironmentPolicySections {
    param([string]$Content)

    if ([string]::IsNullOrWhiteSpace($Content)) {
        return ""
    }

    $lines = $Content -split "`r?`n"
    $out = New-Object System.Collections.Generic.List[string]
    $skip = $false

    foreach ($line in $lines) {
        if ($line -match '^\s*\[(shell_environment_policy|shell_environment_policy\.set)\]\s*$') {
            $skip = $true
            continue
        }

        if ($skip -and $line -match '^\s*\[.+\]\s*$') {
            $skip = $false
            $out.Add($line)
            continue
        }

        if (-not $skip) {
            $out.Add($line)
        }
    }

    return (($out -join "`r`n").TrimEnd())
}

function Write-CodexConfig {
    param([string]$Content)

    $config = Get-CodexConfigPath

    if (Test-Path $config) {
        Copy-Item $config "$config.bak" -Force
    }

    Set-Content -Path $config -Value $Content -Encoding UTF8

    Write-Host "Codex config updated:" -ForegroundColor Green
    Write-Host $config -ForegroundColor Cyan
}

function Read-ClaudeSettings {
    $settingsPath = Get-ClaudeSettingsPath

    if (!(Test-Path $settingsPath)) {
        return [ordered]@{
            '$schema' = "https://json.schemastore.org/claude-code-settings.json"
        }
    }

    $raw = Get-Content $settingsPath -Raw

    if ([string]::IsNullOrWhiteSpace($raw)) {
        return [ordered]@{
            '$schema' = "https://json.schemastore.org/claude-code-settings.json"
        }
    }

    return ($raw | ConvertFrom-Json -AsHashtable)
}

function Write-ClaudeSettings {
    param([object]$Settings)

    $settingsPath = Get-ClaudeSettingsPath

    if (Test-Path $settingsPath) {
        Copy-Item $settingsPath "$settingsPath.bak" -Force
    }

    $json = $Settings | ConvertTo-Json -Depth 100
    Set-Content -Path $settingsPath -Value $json -Encoding UTF8

    Write-Host "Claude settings updated:" -ForegroundColor Green
    Write-Host $settingsPath -ForegroundColor Cyan
}

function Set-ClaudeProxy {
    param([string]$HttpProxy)

    $settings = Read-ClaudeSettings

    if (!$settings.Contains("env")) {
        $settings["env"] = [ordered]@{}
    }

    if ($null -eq $settings["env"]) {
        $settings["env"] = [ordered]@{}
    }

    if ($settings["env"] -isnot [System.Collections.IDictionary]) {
        $settings["env"] = [ordered]@{}
    }

    $envSettings = $settings["env"]

    foreach ($name in @("HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy", "ALL_PROXY", "all_proxy", "NO_PROXY", "no_proxy")) {
        if ($envSettings.Contains($name)) {
            $envSettings.Remove($name)
        }
    }

    $pairs = @(
        @("HTTP_PROXY",  $HttpProxy),
        @("HTTPS_PROXY", $HttpProxy),
        @("NO_PROXY",    $ClaudeNoProxy)
    )

    foreach ($pair in $pairs) {
        $name = $pair[0]
        $value = $pair[1]

        if ($envSettings.Contains($name)) {
            $envSettings[$name] = $value
        } else {
            $envSettings[$name] = $value
        }
    }

    Write-ClaudeSettings -Settings $settings
}

function Clear-ClaudeProxy {
    $settingsPath = Get-ClaudeSettingsPath

    if (!(Test-Path $settingsPath)) {
        Write-Host "Claude settings does not exist, skipped:" -ForegroundColor Yellow
        Write-Host $settingsPath -ForegroundColor Cyan
        return
    }

    $settings = Read-ClaudeSettings
    if ($settings.Contains("env")) {
        $settings.Remove("env")
    }

    Write-ClaudeSettings -Settings $settings
}

function Set-CodexProxy {
    param(
        [string]$HttpProxy,
        [string]$SocksProxy
    )

    $config = Get-CodexConfigPath

    if (Test-Path $config) {
        $content = Get-Content $config -Raw
    } else {
        $content = ""
    }

    $content = Remove-ProxySwitchManagedBlock -Content $content
    $content = Remove-ShellEnvironmentPolicySections -Content $content

    $block = @"

# >>> proxy-switch managed shell_environment_policy
[shell_environment_policy]
inherit = "core"

[shell_environment_policy.set]
http_proxy = "$HttpProxy"
https_proxy = "$HttpProxy"
HTTP_PROXY = "$HttpProxy"
HTTPS_PROXY = "$HttpProxy"
all_proxy = "$SocksProxy"
ALL_PROXY = "$SocksProxy"
no_proxy = "$NoProxy"
NO_PROXY = "$NoProxy"
# <<< proxy-switch managed shell_environment_policy
"@

    $newContent = ($content.TrimEnd() + "`r`n" + $block).TrimStart()
    Write-CodexConfig -Content $newContent
}

function Clear-CodexProxy {
    $config = Get-CodexConfigPath

    if (!(Test-Path $config)) {
        Write-Host "Codex config does not exist, skipped:" -ForegroundColor Yellow
        Write-Host $config -ForegroundColor Cyan
        return
    }

    $content = Get-Content $config -Raw
    $content = Remove-ProxySwitchManagedBlock -Content $content
    $content = Remove-ShellEnvironmentPolicySections -Content $content
    $newContent = $content.Trim()
    Write-CodexConfig -Content $newContent
}

function Show-ProxyStatus {
    $path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
    $reg = Get-ItemProperty -Path $path

    Write-Host ""
    Write-Host "========== Windows 用户环境变量 ==========" -ForegroundColor Cyan
    Write-Host "http_proxy  = $env:http_proxy"
    Write-Host "https_proxy = $env:https_proxy"
    Write-Host "all_proxy   = $env:all_proxy"

    Write-Host ""
    Write-Host "========== Windows 系统代理 ==========" -ForegroundColor Cyan
    Write-Host "ProxyEnable = $($reg.ProxyEnable)"
    Write-Host "ProxyServer = $($reg.ProxyServer)"

    Write-Host ""
    Write-Host "========== Git ==========" -ForegroundColor Cyan
    if (Get-Command git -ErrorAction SilentlyContinue) {
        Write-Host "git http.proxy  = $(git config --global --get http.proxy)"
        Write-Host "git https.proxy = $(git config --global --get https.proxy)"
    } else {
        Write-Host "git not found"
    }

    Write-Host ""
    Write-Host "========== npm ==========" -ForegroundColor Cyan
    if (Get-Command npm -ErrorAction SilentlyContinue) {
        Write-Host "npm proxy       = $(npm config get proxy)"
        Write-Host "npm https-proxy = $(npm config get https-proxy)"
    } else {
        Write-Host "npm not found"
    }

    Write-Host ""
    Write-Host "========== pnpm ==========" -ForegroundColor Cyan
    if (Get-Command pnpm -ErrorAction SilentlyContinue) {
        Write-Host "pnpm proxy       = $(pnpm config get proxy)"
        Write-Host "pnpm https-proxy = $(pnpm config get https-proxy)"
    } else {
        Write-Host "pnpm not found"
    }

    Write-Host ""
    Write-Host "========== Codex ==========" -ForegroundColor Cyan
    Write-Host "config = $(Get-CodexConfigPath)"

    Write-Host ""
    Write-Host "========== Claude ==========" -ForegroundColor Cyan
    $claudeSettingsPath = Get-ClaudeSettingsPath
    Write-Host "settings = $claudeSettingsPath"

    if (Test-Path $claudeSettingsPath) {
        try {
            $claudeSettings = Read-ClaudeSettings

            if ($claudeSettings.Contains("env") -and $null -ne $claudeSettings["env"]) {
                $claudeEnv = $claudeSettings["env"]
                Write-Host "HTTP_PROXY  = $($claudeEnv["HTTP_PROXY"])"
                Write-Host "HTTPS_PROXY = $($claudeEnv["HTTPS_PROXY"])"
                Write-Host "NO_PROXY    = $($claudeEnv["NO_PROXY"])"
            } else {
                Write-Host "env = <not set>"
            }
        } catch {
            Write-Host "settings.json could not be parsed." -ForegroundColor Red
        }
    } else {
        Write-Host "settings.json not found"
    }
}

function Switch-Home {
    Clear-ProxyEnv
    Disable-SystemProxy
    Clear-ToolProxy
    Clear-CodexProxy
    Clear-ClaudeProxy

    Write-Host ""
    Write-Host "已切换到 HOME 模式:已取消本机显式代理。" -ForegroundColor Green
    Write-Host "本机环境变量、Windows 系统代理、Git/npm/yarn/pnpm、Codex/Claude 代理配置均已清除。" -ForegroundColor Yellow
    Write-Host "建议重启 Codex App 和 Claude Code,让新配置完全生效。" -ForegroundColor Yellow
}

function Switch-Outside {
    Set-ProxyEnv -HttpProxy $LocalHttp -SocksProxy $LocalSocks
    Enable-SystemProxy -ProxyServer $LocalSystemProxy
    Set-ToolProxy -HttpProxy $LocalHttp -SocksProxy $LocalSocks
    Set-CodexProxy -HttpProxy $LocalHttp -SocksProxy $LocalSocks
    Set-ClaudeProxy -HttpProxy $LocalHttp

    Write-Host ""
    Write-Host "已切换到 OUTSIDE 模式:本机 v2rayN mixed 代理 127.0.0.1:10808。" -ForegroundColor Green
    Write-Host "Windows 环境变量、Windows 系统代理、Git/npm/yarn/pnpm、Codex/Claude 均已指向 127.0.0.1:10808。" -ForegroundColor Yellow
    Write-Host "请确认 v2rayN 正在运行,并且 mixed 端口是 10808。" -ForegroundColor Yellow
    Write-Host "Claude Code 仅写入 HTTP/HTTPS 代理,不写入 SOCKS 代理。" -ForegroundColor Yellow
    Write-Host "建议重启 Codex App 和 Claude Code,让新配置完全生效。" -ForegroundColor Yellow
}

switch ($Mode) {
    "home" {
        Switch-Home
    }

    "outside" {
        Switch-Outside
    }

    "status" {
        Show-ProxyStatus
    }
}
i
每次写入 Codex / Claude 配置前都会生成 config.toml.baksettings.json.bak(同目录,覆盖式备份,无时间戳);Codex 管理块由 # >>> proxy-switch managed# <<< proxy-switch managed 标记,po / ph 均可重复幂等执行。
05 PowerShell Profile

Profile · 把命令收敛成 ph / po / psw

Profile 把 proxy-switch.ps1 包装成 px 函数,再为三种模式提供别名。脚本是在子 PowerShell 进程中执行的,所以执行后 Sync-CurrentProxyEnv 会把用户级环境变量同步回当前窗口。

po

OUTSIDE:开启代理。

ph

HOME:取消代理。

psw

STATUS:查看当前状态。

px

统一入口:px h/o/s

PS1 C:\Users\Dan\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
# ============================================================
# PowerShell Profile for Dan
# 作用:
#   提供代理切换快捷命令
#
# 依赖脚本:
#   C:\Users\Dan\Documents\PowerShell\proxy-switch.ps1
#
# 快捷命令:
#   px h / ph    -> HOME 模式:清除本机显式代理
#   px o / po    -> OUTSIDE 模式:开启本机 v2rayN 127.0.0.1:10808
#   px s / psw   -> 查看当前代理状态
#
# 说明:
#   proxy-switch.ps1 会在子 PowerShell 进程里执行。
#   子进程可以修改 Windows 用户级环境变量,
#   但不会自动刷新当前 PowerShell 窗口的 $env:。
#
#   所以这里额外加入 Sync-CurrentProxyEnv,
#   每次执行 px / ph / po / psw 后,
#   自动把当前窗口的环境变量同步到最新状态。
# ============================================================

$global:ProxySwitchScript = "C:\Users\Dan\Documents\PowerShell\proxy-switch.ps1"

function Sync-CurrentProxyEnv {
    $names = @(
        "http_proxy",
        "https_proxy",
        "HTTP_PROXY",
        "HTTPS_PROXY",
        "all_proxy",
        "ALL_PROXY",
        "no_proxy",
        "NO_PROXY"
    )

    foreach ($name in $names) {
        $value = [Environment]::GetEnvironmentVariable($name, "User")

        if ([string]::IsNullOrEmpty($value)) {
            Remove-Item "Env:\$name" -ErrorAction SilentlyContinue
        } else {
            Set-Item "Env:\$name" $value
        }
    }
}

function px {
    param(
        [Parameter(Position = 0)]
        [ValidateSet("home", "h", "outside", "out", "o", "status", "s")]
        [string]$Mode = "status"
    )

    if (!(Test-Path $global:ProxySwitchScript)) {
        Write-Host ""
        Write-Host "proxy-switch.ps1 not found:" -ForegroundColor Red
        Write-Host $global:ProxySwitchScript -ForegroundColor Yellow
        Write-Host ""
        return
    }

    switch ($Mode) {
        "h"       { $realMode = "home" }
        "home"    { $realMode = "home" }

        "o"       { $realMode = "outside" }
        "out"     { $realMode = "outside" }
        "outside" { $realMode = "outside" }

        "s"       { $realMode = "status" }
        "status"  { $realMode = "status" }
    }

    Write-Host ""
    Write-Host "Running proxy-switch mode: $realMode" -ForegroundColor Cyan
    Write-Host ""

    pwsh.exe -NoProfile -ExecutionPolicy Bypass -File $global:ProxySwitchScript -Mode $realMode

    # 同步当前 PowerShell 窗口的代理环境变量
    Sync-CurrentProxyEnv
}

function ph {
    px home
}

function po {
    px outside
}

function psw {
    px status
}

function proxy-help {
    Write-Host ""
    Write-Host "Proxy Switch Commands" -ForegroundColor Cyan
    Write-Host "--------------------------------"
    Write-Host "ph        -> home mode, clear local explicit proxy"
    Write-Host "po        -> outside mode, local v2rayN 127.0.0.1:10808"
    Write-Host "psw       -> show proxy status"
    Write-Host ""
    Write-Host "px h      -> same as ph"
    Write-Host "px o      -> same as po"
    Write-Host "px s      -> same as psw"
    Write-Host ""
    Write-Host "After switching, current PowerShell env is synced automatically." -ForegroundColor Yellow
    Write-Host ""
}
06 Install & Use

安装与日常使用

安装步骤

  1. proxy-switch.ps1 放到 PowerShell 目录
  2. 打开并编辑当前用户的 PowerShell Profile
  3. 加载 Profile 让快捷命令立即生效
  4. 执行 po / ph / psw 验证
PowerShell1)放置切换脚本
notepad "C:\Users\Dan\Documents\PowerShell\proxy-switch.ps1"
PowerShell2)编辑 Profile
$PROFILE
notepad $PROFILE
PowerShell3)加载 Profile
. $PROFILE
PowerShell4)日常命令
po      # 开启代理(OUTSIDE)
ph      # 取消代理(HOME)
psw     # 查看状态(STATUS)

# 等价写法
px o
px h
px s
PowerShell直接执行脚本(不依赖 Profile)
pwsh -ExecutionPolicy Bypass -File "C:\Users\Dan\Documents\PowerShell\proxy-switch.ps1" -Mode outside
pwsh -ExecutionPolicy Bypass -File "C:\Users\Dan\Documents\PowerShell\proxy-switch.ps1" -Mode home
pwsh -ExecutionPolicy Bypass -File "C:\Users\Dan\Documents\PowerShell\proxy-switch.ps1" -Mode status
日常只记三个命令:pophpsw。执行后当前 PowerShell 窗口的 $env: 会自动同步,不必手动重开终端。
07 Verify & Troubleshoot

验证链路与排障

不要凭感觉判断代理有没有生效。链路问题大多出现在三处:v2rayN 自己没起来、终端没读到环境变量、工具没有读环境变量。

PowerShell验证当前会话与系统状态
echo $env:http_proxy
echo $env:https_proxy
echo $env:all_proxy

netstat -ano | findstr 10808

Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" |
  Select-Object ProxyEnable, ProxyServer

git config --global --get http.proxy
npm config get proxy
pnpm config get proxy

Get-Content "$env:USERPROFILE\.claude\settings.json"

curl.exe -I https://api.openai.com

按失败对象切入

  • Codex 子进程失败:检查 echo $env:http_proxy、v2rayN 是否运行、10808 是否监听、config.toml 是否有托管块,然后重启 Codex App。
  • Claude Code 失败:查看 settings.json 是否包含 env 字段及 HTTP_PROXY / HTTPS_PROXY / NO_PROXY 三个键,确认后重启 Claude Code。
  • 浏览器失败:用 Switchy 切到 Local Proxy 或临时开启 v2rayN 系统代理。
  • Git / npm 失败:git config --global --get http.proxynpm config get proxy,再检查环境变量。
  • 全部失败:先确认节点可用、10808 监听正常,再排查 DNS / 路由 / 防火墙。
i
看到 HTTP/1.1 200 Connection established 说明 HTTPS 隧道已经通过代理建立。后续 401 / 403 / 404 不一定代表代理没生效,更可能是凭据或 URL 问题。
!
修改 config.tomlsettings.json 后建议重启 Codex App 与 Claude Code,否则它们仍在用旧配置启动子进程 / 会话。
已复制到剪贴板