WSL2 内启动的服务,如果想要被外部访问,需要在 Windows 上创建防火墙规则并开启端口转发,将该服务暴露出去。
管理端口转发
使用 Windows 自带的 Netsh(Network Shell) 可以管理端口转发,其中创建和删除操作需要管理员权限:
PS> $WSL_IP = (wsl hostname -I).Trim() -split ' ' | Select-Object -First 1
PS> netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=8080 connectaddress=$WSL_IP
PS> netsh interface portproxy show all
PS> netsh interface portproxy delete v4tov4 listenport=9030 listenaddress=0.0.0.0
|
管理防火墙规则
开启端口转发后,外部请求可能仍然无法到达 WSL2,原因是数据包在到达物理网卡后就被 Windows 防火墙拦截下来了,此时需要创建防火墙规则允许入站请求,规则的创建和删除操作同样需要管理员权限:
PS> netsh advfirewall firewall add rule name="WSL 8080" dir=in action=allow protocol=TCP localport=8080 description="WSL TEI 服务"
PS> netsh advfirewall firewall show rule name="WSL 8080"
PS> Get-NetFirewallRule -DisplayName "WSL *"
PS> Get-NetFirewallRule -DisplayName "WSL *" | Get-NetFirewallPortFilter
PS> netsh advfirewall firewall delete rule name="WSL 8080"
PS> Get-NetFirewallRule -DisplayName "WSL *" | Remove-NetFirewallRule
|
WSL2 执行 Powershell
在 WSL2 中也可以执行 Powershell 命令:
$ powershell.exe -Command ' Get-NetFirewallRule -DisplayName "WSL *" | ForEach-Object { $portFilter = $_ | Get-NetFirewallPortFilter [PSCustomObject]@{ DisplayName = $_.DisplayName Description = $_.Description LocalPort = $portFilter.LocalPort RemotePort = $portFilter.RemotePort } } | Sort-Object { [int]$_.LocalPort } | Format-Table -Wrap -AutoSize ' DisplayName Description LocalPort RemotePort ----------- ----------- --------- ---------- WSL 5601 WSL Kibana 服务 5601 Any WSL 8020 WSL Namenode RPC 服务 8020 Any WSL 8030 WSL Doris WEBUI 服务 8030 Any WSL 8080 WSL TEI 服务 8080 Any WSL 8088 WSL YARN RM WEBUI 服务 8088 Any WSL 9030 WSL Doris JDBC 服务 9030 Any WSL 9091 WSL milvus 服务 9091 Any WSL 9200 WSL ES 服务 9200 Any WSL 9870 WSL Namenode WEBUI 服务 9870 Any WSL 18042 WSL YARN NM WEBUI 服务 18042 Any WSL 18080 WSL Spark HistoryServer WEBUI 服务 18080 Any WSL 19888 WSL Mapreduce JobHistory WEBUI 服务 19888 Any
$ powershell.exe -Command "[Security.Principal.WindowsPrincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)" True
|
注意到当前 WSL2 会话执行的 Powershell 命令具有管理员权限,在此基础上可以编写一个端口转发和防火墙规则管理脚本,在 WSL2 终端内就能完成端口的管理。
端口管理脚本
创建端口管理脚本 PortManager.ps1:
PortManager.ps1 >foldedparam( [Parameter(ParameterSetName="add", Mandatory=$true)] [switch]$Add,
[Parameter(ParameterSetName="remove", Mandatory=$true)] [switch]$Remove,
[Parameter(ParameterSetName="search", Mandatory=$true)] [switch]$Search, [Parameter(ParameterSetName="show", Mandatory=$true)] [switch]$Show,
[Parameter(ParameterSetName="add", Mandatory=$true)] [Parameter(ParameterSetName="remove", Mandatory=$true)] [Parameter(ParameterSetName="search", Mandatory=$true)] [int]$Port, [Parameter(ParameterSetName="add")] [string]$Desc = "" )
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$RuleName = "WSL $Port"
if ($Add) { $WSL_IP = (wsl hostname -I).Trim() -split ' ' | Select-Object -First 1
if (-not $WSL_IP) { Write-Error "获取 WSL IP 失败" exit 1 }
if (-not $Desc) { $Desc = "WSL Port $Port" }
Write-Host "WSL IP: $WSL_IP" Write-Host "添加端口转发: $Port -> $WSL_IP`:$Port"
netsh interface portproxy delete v4tov4 ` listenaddress=0.0.0.0 listenport=$Port 2>$null
netsh interface portproxy add v4tov4 ` listenaddress=0.0.0.0 listenport=$Port ` connectaddress=$WSL_IP connectport=$Port
netsh advfirewall firewall delete rule name="$RuleName" > $null 2>&1
netsh advfirewall firewall add rule ` name="$RuleName" ` dir=in action=allow protocol=TCP ` localport=$Port ` description="$Desc"
Write-Host "创建完成" -ForegroundColor Green }
elseif ($Remove) { Write-Host "删除端口转发: $Port"
netsh interface portproxy delete v4tov4 ` listenaddress=0.0.0.0 listenport=$Port 2>$null
if ($LASTEXITCODE -eq 0) { Write-Host "portproxy 已删除" -ForegroundColor Green } else { Write-Host "portproxy 不存在" -ForegroundColor Yellow }
Write-Host "删除防火墙规则: $RuleName"
netsh advfirewall firewall delete rule ` name="$RuleName" > $null 2>&1
if ($LASTEXITCODE -eq 0) { Write-Host "防火墙规则已删除" -ForegroundColor Green } else { Write-Host "防火墙规则不存在" -ForegroundColor Yellow }
Write-Host "删除完成" }
elseif ($Search) { Write-Host "查询端口: $Port" Write-Host "------------------------"
Write-Host "[PortProxy]" $pp_all = netsh interface portproxy show v4tov4 $pp_header = $pp_all[0..4] $pp_data = $pp_all[5..($pp_all.Count-1)] | Select-String "\s+$Port(\s+|$)" $pp = $pp_header + $pp_data if ($pp_data) { $pp | ForEach-Object { Write-Host $_ -ForegroundColor Green } } else { Write-Host "未找到 portproxy 规则" -ForegroundColor Yellow }
Write-Host ""
Write-Host "[Firewall Rule]" $fw = netsh advfirewall firewall show rule name="$RuleName"
if ($fw -match "No rules match") { Write-Host "未找到防火墙规则" -ForegroundColor Yellow } else { $fw | ForEach-Object { Write-Host $_ -ForegroundColor Green } } }
elseif ($Show) { Write-Host "[PortProxy]" $pp = netsh interface portproxy show v4tov4 if ($pp) { $pp | ForEach-Object { Write-Host $_ -ForegroundColor Green } } else { Write-Host "未找到 portproxy 规则" -ForegroundColor Yellow } Write-Host "[Firewall Rule]" $fw = Get-NetFirewallRule -DisplayName "WSL *" | ForEach-Object { $portFilter = $_ | Get-NetFirewallPortFilter [PSCustomObject]@{ DisplayName = $_.DisplayName Description = $_.Description LocalPort = $portFilter.LocalPort RemotePort = $portFilter.RemotePort } } if ($fw) { $fw | Sort-Object { [int]$_.LocalPort } | Format-Table -Wrap -AutoSize | Out-String | Write-Host -ForegroundColor Green } else { Write-Host "未找到防火墙规则" -ForegroundColor Yellow } }
|
使用方式如下,需要在有管理员权限的 Powershell 中运行:
PS> ./PortManager.ps1 -Add -Port 12345 PS> ./PortManager.ps1 -Add -Port 12346 -Desc "测试端口管理脚本"
PS> ./PortManager.ps1 -Remove -Port 12345
PS> ./PortManager.ps1 -Search -Port 12345
PS> ./PortManager.ps1 -Show
|
在 WSL 中可以调用:
$ powershell.exe -Command 'D:\Develop\PortManager.ps1 -Show'
|