![从公共 IP 地址访问 WSL2](https://linux22.com/image/765741/%E4%BB%8E%E5%85%AC%E5%85%B1%20IP%20%E5%9C%B0%E5%9D%80%E8%AE%BF%E9%97%AE%20WSL2.png)
我已经在 Windows 10 上安装了带有 Ubuntu 20.04 的 WSL2。
我有一个在 WSL2 中运行的 Apache 服务器,当我使用 Windows(Chrome)中的浏览器通过 WSL IP 地址访问它时,它可以正常工作。
由于 WSL2 IP 地址可能会发生变化,我创建了以下 Powershell 脚本,该脚本重新启动 WSL,获取新的 WSL IP 地址,重新启动服务(用于网站本身的 Apache 和 MySQL,以及用于运行“certbot”以进行 SSL 证书更新的 Cron),然后我设置了从 Windows 到 WSL IP 的端口 80 和 443 的端口转发,确保 Windows 防火墙对这些端口开放,然后将域的 hosts 文件更新为新的 WSL IP 地址。
Write-Host "Shutting down WSL"
wsl --shutdown
Write-Host "Starting services..."
wsl sudo service mysql restart
wsl sudo service apache2 restart
wsl sudo service cron restart
$wsl_ip = wsl hostname -I
Write-Host "Port forwarding to $wsl_ip"
netsh interface portproxy reset
netsh interface portproxy add v4tov4 listenport=80 connectport=80 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenport=443 connectport=443 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenaddress=192.168.1.165 listenport=80 connectport=80 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenaddress=192.168.1.165 listenport=443 connectport=443 connectaddress=$wsl_ip
netsh interface portproxy show all
Write-Host "Open Firewall"
Remove-NetFirewallRule -DisplayName "Apache2 Port 80 TCP"
Remove-NetFirewallRule -DisplayName "Apache2 Port 443 TCP"
New-NetFirewallRule -DisplayName "Apache2 Port 80 TCP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow -EdgeTraversalPolicy Allow
New-NetFirewallRule -DisplayName "Apache2 Port 80 TCP" -Direction Outbound -Protocol TCP -LocalPort 80 -Action Allow
New-NetFirewallRule -DisplayName "Apache2 Port 443 TCP" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow -EdgeTraversalPolicy Allow
New-NetFirewallRule -DisplayName "Apache2 Port 443 TCP" -Direction Outbound -Protocol TCP -LocalPort 443 -Action Allow
Write-Host "Updating hosts..."
$domain = "example.com"
$line = "$wsl_ip`t$domain"
$hostsPath = "$env:windir\System32\drivers\etc\hosts"
$items = Get-Content $hostsPath | Select-String $domain
if($items -eq $null)
{
Add-Content $hostsPath $line
}
else
{
foreach($item in $items)
{
(Get-Content $hostsPath) -replace $item, $line | Set-Content $hostsPath
}
}
pause
我已经测试了该脚本,它确实正确完成了所有任务。“hosts”文件已更新,防火墙规则已添加(这个可以只运行一次,不需要包含在“重启服务器”脚本中,但我已将所有步骤捆绑到此脚本中)。
该脚本显示了所有的 portproxy 规则,并且它们都按预期设置(没有必要监听所有地址,然后还专门监听 Windows LAN IP - 这只是一种偏执和测试不同的东西,当它不起作用时)。
并且服务器本身已经启动并正在运行,因为如果我浏览到 WSL IP 地址(或使用域名,这要归功于主机条目 - 使用正确的域名与 SSL 证书匹配,就不必忽略浏览器警告)或“localhost”,那么网站就会正常运行。
但是,如果我尝试浏览“127.0.0.1”或 Windows LAN IP 地址(192.168.1.165,如脚本中所示),那么我就会收到“连接被拒绝”的提示。
请注意,我已将脚本中的 portproxy 命令直接放置在 IP 192.168.1.165 的 WSL IP 地址上(直接使用时有效),因此此 portproxy 被明确拒绝(被防火墙拒绝?但我已经添加了防火墙规则来打开这些端口,对吗?)。
如果我尝试使用公共 IP 地址(或真实域名),浏览器就会一直旋转,直到显示“超时”。这有一点不同,因为 127.0.0.1 和 LAN IP 地址都是“拒绝连接”(立即返回),但这是由于根本没有响应而超时。
服务器本身位于 DMZ 中,并且公共 IP 地址被 NAT 为 LAN IP 地址,这就是我特意尝试使其正常工作的原因,因为它应该使其可供公众访问。
我之前确实启动并运行了这台服务器 - 具有完全的公共访问权限并且一切正常 - 但是服务器遭遇了断电,现在我无法让它再次工作。
有可能我之前执行的一些命令或设置没有保存并在断电时丢失了,但我想不出是什么原因。
有什么想法可能导致 LAN IP / 127.0.0.1 失败并出现“连接被拒绝”,而“localhost”和 WSL2 IP 却正常工作?
虽然 127.0.0.1 不太重要,因为它是 LAN IP,需要工作才能使其可供公众访问,因为这是 NAT 发送数据包的目标。
编辑:哦,天哪。我读了别人的一篇文章,显然,如果你在“netsh interface portproxy”命令中使用变量,那么虽然列出时显示正确,但实际上不起作用。但是,如果你手动输入命令,不使用变量,而是直接输入 WSL2 IP 地址,那么一切都会开始工作,包括公共访问。
这是 Powershell 中的一个严重错误,不仅仅是因为它意味着我无法自动执行它,必须手动输入命令,因为变量不起作用,而且因为没有迹象表明它坏了。当你列出规则时,它们看起来 100% 正确,IP 地址也正确,但它就是不起作用。
好的,现在我已经让它工作了。但我想我会改变我的问题,问是否有办法解决这个问题?因为我希望我的小自动化脚本能够工作,因为这样我就可以在启动时运行它而无需手动干预。哦,我想服务器不应该经常断电。
这让我想起了为什么我更喜欢 Linux 而不是 Windows。