sing-box on Windows
参考上篇 sing-box on Linux 中的思路, 通过任务计划程序 sing-box-trigger 来开机自启动脚本 Update.ps1, 这个脚本将脚本循环检测网络可用性, 当网络可用时, 从远端下载配置文件替换本地的配置文件, 然后启动任务计划程序 sing-box。
1 Core
从 https://github.com/SagerNet/sing-box/releases/ 下载, 解压到 sing-box 工作目录下, 比如 C:\Users\<UserName>\Apps\sing-box\sing-box.exe。
2 Dashboard
创建 sing-box 工作目录: C:\Users\<UserName>\Apps\sing-box。
下载 Yacd-meta 或者 MetaCubeXD, 解压后将文件夹重命名为 ui, 移动到 sing-box 工作目录下。
后续一切工作正常后, 可以打开 Dashboard (http://127.0.0.1:9090/ui) 查看相应信息并进行管理。
3 Task Scheduler
3.1 sing-box-trigger
打开任务计划程序, 点击右侧操作列表中的“创建任务”:
常规
名称填
sing-box-trigger。安全选项中, 不用
更改用户或组, 使用默认的用户就行, 如果使用Administrators或者SYSTEM账户, 任务计划程序启动时会弹出运行窗口。选择
不管用户是否登录都要运行, 勾选不存储密码。不然任务计划程序启动时也会弹出运行窗口。勾选
使用最高权限运行。触发器
新建,
开始任务选择登录时或启动时, 按需选择延迟任务时间, 确认勾选已启用。操作
新建,
操作选择启动程序;程序或脚本填写powershell.exe;添加参数填写-ExecutionPolicy Bypass -File "Update.ps1";起始于填写脚本所在目录, 比如C:\Users\<UserName>\Apps\sing-box。条件
全部取消勾选, 包括灰显的。
设置
- 仅勾选
允许按需运行任务。 - 最下方的
如果此任务已经运行, 以下规则适用, 确认选择请勿启动新实例。
- 仅勾选
3.2 sing-box
打开任务计划程序, 点击右侧操作列表中的“创建任务”:
常规
名称填
sing-box。安全选项中,
更改用户或组, 输入system, 点击检查名称按钮, 变为 SYSTEM, 即使用SYSTEM账户。不使用触发器
操作
新建,
操作选择启动程序;程序或脚本填写sing-box.exe;添加参数填写-D .\ -c .\config.json run;起始于填写 sing-box 工作目录, 比如C:\Users\<UserName>\Apps\sing-box。条件
全部取消勾选, 包括灰显的。
设置
- 仅勾选
允许按需运行任务。 - 最下方的
如果此任务已经运行, 以下规则适用, 确认选择请勿启动新实例。
- 仅勾选
4 智能多宿主名称解析与防火墙
注意, 在 Windows 中, 如果在 TUN 配置中启用了严格路由,
- 不必手动启用组策略中
计算机配置→管理模板→网络→DNS 客户端→禁用智能多宿主名称解析这一策略了, 保持这一策略为未配置/已禁用即可。 - 不必手动为 sing-box 配置 Windows 防火墙, sing-box 会自动配置的。
- 不然, 你会发现虽然测速延迟还可以, 但实际速度很慢。
- 由于 mihomo 和 sing-box 都使用 sing-tun, 所以上述注意事项同样适用于 mihomo。
5 日常使用
5.1 更新配置文件
按需修改 Update.ps1 的内容:
更改 $url_sub 的值为自己的订阅链接, 至于模板 $url_tpl, 可以参考 Generate config of sing-box 选择更多模板。
对于 sing-box 的运行参数, 由 sing-box help 得知:
Flags:
-c, --config stringArray set configuration file path
-C, --config-directory stringArray set configuration directory path
-D, --directory string set working directory
--disable-color disable color output
-h, --help help for sing-box-C 指定了配置文件所在文件夹的路径, 但没有指定使用哪一个配置文件; -c 则指明了使用的配置文件的路径。
如果在 Service 中 ExecStart 部分使用的 sing-box 运行参数是 -D .\ -C .\ run。
则要求配置文件所在的文件夹中不能有多个 json 文件, 否则 sing-box 无法判定使用哪一个作为配置, 继而无法启动。
- 从下面两种方案中选择一个即可。
- 手动运行这个更新配置文件的脚本时需要“以管理员身份运行”。
- 在系统环境变量
PATH中添加C:\Users\<UserName>\Apps\sing-box\以便在脚本中方便地调用sing-box.exe。
5.1.1 一种配置
下载使用 mixed 或 tun 入站的配置文件。
修改以下内容, 写入到脚本 C:\Users\<UserName>\Apps\sing-box\Update.ps1:
$task = "sing-box"
$process = "sing-box"
$ping = "223.5.5.5"
$dir_config = "$env:USERPROFILE\Apps\sing-box"
$url_gene = "https://example.com" # 生成配置的后端地址
$url_sub = "https://example.com" # 来自机场的订阅链接
$inbound = "tun" # mixed or tun
$url_tpl = "https://raw.githubusercontent.com/senzyo/sing-box-templates/public/$inbound/doh/ali/google/testingcf.jsdelivr.net/config.json" # 配置所用模板的地址
$url_dl = "$url_gene/config/$url_sub&ua=clashmeta&emoji=1&file=$url_tpl" # 或者ua=sing-box等等, 具体看机场对于客户端和协议的支持情况
$proxy_port = "7890"
Stop-ScheduledTask -TaskName $task
Stop-Process -Name $process -Force > $null 2>&1
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyEnable -Value 0
Clear-DnsClientCache
while (!(Test-Connection -ComputerName $ping -Count 1 -Quiet)) {
Start-Sleep -Seconds 2
}
Set-Location -Path $dir_config
$count = 0
while ($count -lt 3) {
Invoke-WebRequest -OutFile temp.json -Uri "$url_dl" -TimeoutSec 40
sing-box.exe check -c temp.json 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "Downloaded config($inbound) is valid."
Remove-Item "config_$inbound.json" 2>$null
Rename-Item temp.json "config_$inbound.json"
Write-Host "Use config($inbound)."
Copy-Item "config_$inbound.json" config.json
break
}
Remove-Item temp.json 2>$null
$count++
Write-Host "Downloaded config($inbound) is invalid. Tried $count times."
}
if ($count -eq 3) {
Write-Host "No changes, keep the existing files."
}
Start-Sleep -Seconds 1现在可以运行任务计划程序 sing-box-trigger 测试一下整个流程, 应该一切正常。
现在可以打开 Dashboard (http://127.0.0.1:9090/ui) 查看相应信息并进行管理。
5.1.2 两种配置
下载使用 mixed 和 tun 入站的配置文件。优先使用 tun 入站。搭配 切换模式重启 脚本来切换模式。
修改以下内容, 写入到脚本 C:\Users\<UserName>\Apps\sing-box\Update.ps1:
$task = "sing-box"
$process = "sing-box"
$ping = "223.5.5.5"
$dir_config = "$env:USERPROFILE\Apps\sing-box"
$url_gene = "https://example.com" # 生成配置的后端地址
$url_sub = "https://example.com" # 来自机场的订阅链接
$inbound_prefer = "tun" # mixed or tun
$proxy_port = "7890"
Stop-ScheduledTask -TaskName $task
Stop-Process -Name $process -Force > $null 2>&1
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyEnable -Value 0
Clear-DnsClientCache
while (!(Test-Connection -ComputerName $ping -Count 1 -Quiet)) {
Start-Sleep -Seconds 2
}
Set-Location -Path $dir_config
$inbound_list = @("mixed", "tun")
foreach ($inbound in $inbound_list) {
$url_tpl = "https://raw.githubusercontent.com/senzyo/sing-box-templates/public/$inbound/doh/ali/google/testingcf.jsdelivr.net/config.json" # 配置所用模板的地址
$url_dl = "$url_gene/config/$url_sub&ua=clashmeta&emoji=1&file=$url_tpl" # 或者ua=sing-box等等, 具体看机场对于客户端和协议的支持情况
$count = 0
while ($count -lt 3) {
Invoke-WebRequest -OutFile temp.json -Uri "$url_dl" -TimeoutSec 40
sing-box.exe check -c temp.json 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "Downloaded config($inbound) is valid."
Remove-Item "config_$inbound.json" 2>$null
Rename-Item temp.json "config_$inbound.json"
if ($inbound -eq $inbound_prefer) {
Write-Host "Use config($inbound)."
Copy-Item "config_$inbound.json" config.json
}
break
}
Remove-Item temp.json 2>$null
$count++
Write-Host "Downloaded config($inbound) is invalid. Tried $count times."
}
if ($count -eq 3) {
Write-Host "No changes, keep the existing files."
}
}
Start-Sleep -Seconds 1现在可以运行任务计划程序 sing-box-trigger 测试一下整个流程, 应该一切正常。
现在可以打开 Dashboard (http://127.0.0.1:9090/ui) 查看相应信息并进行管理。
5.2 当前配置重启
修改以下内容, 写入到脚本 C:\Users\<UserName>\Apps\sing-box\Restart.ps1:
$dir_config = "$env:USERPROFILE\Apps\sing-box"
$task = "sing-box"
$process = "sing-box"
$proxy_port = "7890"
Set-Location -Path $dir_config
sing-box.exe check -c config.json 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Host "File config.json is invalid."
Start-Sleep -Seconds 2
Exit 1
}
Stop-ScheduledTask -TaskName $task
Stop-Process -Name $process -Force > $null 2>&1
Clear-DnsClientCache
# 随机化 tun 接口名称避免启动失败
$find = Select-String -Path config.json -Pattern '"type": "tun"'
if ($find) {
$random_hex = -join (1..3 | ForEach-Object { "{0:x2}" -f (Get-Random -Min 0 -Max 256) })
$json_result = & jq --arg new_name "$random_hex" '(.inbounds[] | select(.type == \"tun\") | .interface_name) = $new_name' config.json 2>$null
if ($LASTEXITCODE -eq 0 -and $json_result) {
$temp_path = "$dir_config\temp.json"
[System.IO.File]::WriteAllLines($temp_path, $json_result)
Move-Item -Path temp.json -Destination config.json -Force
Write-Host "TUN interface name randomized."
} else {
Write-Host "TUN interface name randomization failed."
pause
exit
}
}
Start-ScheduledTask -TaskName $task
Start-Sleep -Seconds 5
$state = Get-ScheduledTask -TaskName $task | Select-Object -ExpandProperty State
Write-Host "State of ${task}: ${state}"
if ($state -eq "Running") {
$find = Select-String -Path config.json -Pattern '"type": "tun"'
if ($find) {
Write-Host "Use tun mode."
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyEnable -Value 0
Write-Host "System proxy disabled."
} else {
Write-Host "Use system proxy mode."
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyServer -Value "127.0.0.1:$proxy_port"
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyEnable -Value 1
Write-Host "System proxy enabled."
}
} else {
Write-Host "Run ${task} failed."
}
Start-Sleep -Seconds 15.3 停止运行
修改以下内容, 写入到脚本 C:\Users\<UserName>\Apps\sing-box\Stop.ps1:
$task = "sing-box"
$process = "sing-box"
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyEnable -Value 0
Write-Host "System proxy disabled."
Stop-ScheduledTask -TaskName $task
Stop-Process -Name $process -Force > $null 2>&1
Clear-DnsClientCache
$state = Get-ScheduledTask -TaskName $task | Select-Object -ExpandProperty State
Write-Host "State of ${task} ScheduledTask: ${state}"
Start-Sleep -Seconds 15.4 切换模式重启
sing-box 的入站方式是固定在配置文件中的, 而且不支持通过 API 切换, 所以只能切换配置文件来切换 mixed 或 tun 模式。
修改以下内容, 写入到脚本 C:\Users\<UserName>\Apps\sing-box\Switch.ps1:
$dir_config = "$env:USERPROFILE\Apps\sing-box"
$task = "sing-box"
$process = "sing-box"
$proxy_port = "7890"
Set-Location -Path $dir_config
$find = Select-String -Path config.json -Pattern '"type": "tun"'
if ($find) {
$inbound = "mixed"
} else {
$inbound = "tun"
}
sing-box.exe check -c config_$inbound.json 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Host "File config_$inbound.json is invalid."
Start-Sleep -Seconds 2
Exit 1
}
Stop-ScheduledTask -TaskName $task
Stop-Process -Name $process -Force > $null 2>&1
Clear-DnsClientCache
# 随机化 tun 接口名称避免启动失败
if ($inbound -eq "tun") {
$random_hex = -join (1..3 | ForEach-Object { "{0:x2}" -f (Get-Random -Min 0 -Max 256) })
$json_result = & jq --arg new_name "$random_hex" '(.inbounds[] | select(.type == \"tun\") | .interface_name) = $new_name' "config_$inbound.json" 2>$null
if ($LASTEXITCODE -eq 0 -and $json_result) {
$temp_path = "$dir_config\temp.json"
[System.IO.File]::WriteAllLines($temp_path, $json_result)
Move-Item -Path temp.json -Destination config.json -Force
Write-Host "TUN interface name randomized."
} else {
Write-Host "TUN interface name randomization failed."
pause
exit
}
} else {
Copy-Item "config_$inbound.json" config.json
}
Start-ScheduledTask -TaskName $task
Start-Sleep -Seconds 5
$state = Get-ScheduledTask -TaskName $task | Select-Object -ExpandProperty State
Write-Host "State of ${task}: ${state}"
if ($state -eq "Running") {
if ($inbound -eq "mixed") {
Write-Host "Use system proxy mode."
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyServer -Value "127.0.0.1:$proxy_port"
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyEnable -Value 1
Write-Host "System proxy enabled."
} else {
Write-Host "Use tun mode."
Set-ItemProperty -Path 'Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyEnable -Value 0
Write-Host "System proxy disabled."
}
} else {
Write-Host "Run ${task} failed."
}
Start-Sleep -Seconds 15.5 更新sing-box.exe
# 停止运行 sing-box
if (Get-Process sing-box -ErrorAction SilentlyContinue) {
Stop-Process -Name sing-box -Force
Write-Host "sing-box has stopped." -ForegroundColor Green
} else {
Write-Host "sing-box is not running." -ForegroundColor Yellow
}
Clear-DnsClientCache
Start-Sleep -Seconds 1
# ---- 公共函数 ----
# 校验 Hash
function VerifyHash {
$Digest = $Response.assets | Where-Object { $_.name -eq "$FileName.zip" } | Select-Object -ExpandProperty digest
$RemoteHash = $Digest.Split(':')[-1]
$LocalHash = (Get-FileHash $ZipPath -Algorithm SHA256).Hash.ToLower()
Write-Host "Verifying SHA256 checksum... " -NoNewline
if ($RemoteHash -eq $LocalHash) {
Write-Host "Correct!" -ForegroundColor Green
return $true
} else {
Write-Host "Wrong!" -ForegroundColor Red
return $false
}
}
# 升级
function Upgrade {
$Url = $Response.assets | Where-Object { $_.name -eq "$FileName.zip" } | Select-Object -ExpandProperty browser_download_url
do {
if (Test-Path -Path $ZipPath) {
Remove-Item $ZipPath -Force
}
Write-Host "Downloading..."
Invoke-WebRequest -OutFile $ZipPath -Uri "https://gh-proxy.org/$Url"
$Correct = VerifyHash
if ($Correct) {
$script:Cover = $true
} else {
Write-Host "Retry Downloading..."
Start-Sleep -Seconds 1
}
} until ($Correct)
}
# 检查更新
function CheckUpdate ($ExeName) {
$LocalVersionStr = "0.0.0"
if (Test-Path -Path $ExePath) {
$VersionOutput = (& $ExePath version) 2>&1
if ($VersionOutput[0] -match "([\d.]+)") {
$LocalVersionStr = $Matches[1]
}
}
$LocalVersionObj = [System.Version]$LocalVersionStr
$RemoteVersionObj = [System.Version]$RemoteVersionStr
if ($RemoteVersionObj -gt $LocalVersionObj) {
Write-Host "version: $LocalVersionStr -> " -NoNewline
Write-Host "$RemoteVersionStr" -ForegroundColor Yellow
Upgrade
}
else {
Write-Host "Up to date: " -NoNewline
Write-Host "$ExeName $LocalVersionStr" -ForegroundColor Green
}
}
# ---- 公共函数 结束 ----
$OutDir = "$env:USERPROFILE\Apps\sing-box"
# ---- 更新 sing-box ----
$ExePath = "$OutDir\sing-box.exe"
$Response = Invoke-RestMethod -Uri "https://api.github.com/repos/SagerNet/sing-box/releases/latest" -Method Get
$TagName = $Response.tag_name
$RemoteVersionStr = $TagName.TrimStart('v')
$FileName = "sing-box-$RemoteVersionStr-windows-amd64"
$ZipPath = "$OutDir\$FileName.zip"
CheckUpdate sing-box
# 解压缩并覆盖 sing-box
if ($script:Cover) {
Expand-Archive -Path $ZipPath -DestinationPath $OutDir -Force
Move-Item -Path "$OutDir\$FileName\sing-box.exe" -Destination "$OutDir\sing-box.exe" -Force
Remove-Item -Recurse "$OutDir\$FileName*" -Force
}
# ---- 更新 sing-box 结束 ----
Start-Sleep -Seconds 16 附件
几个用于脚本快捷方式的自制图标: