从本地网络访问在 WSL(适用于 Linux 的 Windows 子系统)上运行的 Web 服务器
- 2024-11-12 08:36:00
- admin 原创
- 25
问题描述:
将Ubuntu安装为WSL(适用于 Linux 的 Windows 子系统)后,我以 root 身份运行:
cd ~
python3 -m http.server
输出:
Serving HTTP on 0.0.0.0 port 8000 ...
http://0.0.0.0:8000
我尝试从我的 Windows 计算机或访问此 Web 服务器http://192.168.1.178:8000
,但没有任何成功。Web 服务器仅可通过地址http://127.0.0.1:8000
或访问http://localhost:8000
。这意味着我无法从网络中的另一台 PC 连接到此 Web 服务器。是否可以从外部访问 WSL?
解决方案 1:
在您的虚拟机中,执行ifconfig
。
您将在第一部分 (eth0:) inet xxxx 中看到您的 IP 地址
这个 xxxx 是您必须在浏览器中输入的 IP 地址。
解决方案 2:
现有的答案都不适合我,因为 WSL2 在自己的 VM 中运行,并且有自己的网络适配器。您需要某种桥接或端口转发才能使非本地主机请求正常工作(即来自同一网络上的另一台主机)。
我在https://github.com/microsoft/WSL/issues/4150中找到了一个可以解决该问题的脚本:
$remoteport = bash.exe -c "ifconfig eth0 | grep 'inet '"
$found = $remoteport -match 'd{1,3}.d{1,3}.d{1,3}.d{1,3}';
if( $found ){
$remoteport = $matches[0];
} else{
echo "The Script Exited, the ip address of WSL 2 cannot be found";
exit;
}
#[Ports]
#All the ports you want to forward separated by coma
$ports=@(80,443,10000,3000,5000);
#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";
#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";
#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP";
for( $i = 0; $i -lt $ports.length; $i++ ){
$port = $ports[$i];
iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}
从提升/管理员权限的 Powershell 会话运行此脚本对我来说很管用。这样就可以从同一端口上的 Windows 主机 IP 访问在端口上运行的 WSL2 服务。
解决方案 3:
这意味着我无法从网络中的另一台 PC 连接到此 Web 服务器。是否可以从外部访问 WSL?
值得注意的是,在所有答案中,这个问题最初是针对 WSL1 的(在询问时给出),并且OP自我回答为是 WSL 或 Windows 问题,已通过 Windows 更新解决。
具有讽刺意味的是,由于 WSL2 的网络通常工作方式(NAT),这是一个已知问题,因此多年后,人们开始在这种背景下发现它(并回答它)。
WSL2 上有多种解决方案。出于历史原因,我将在下面保留两个较旧的解决方案,但现在首选和官方支持的版本是第一个列出的版本:
WSL2 “镜像”网络模式
从 2023 年 9 月的 WSL2 和 Windows 11 更新开始,可以使用新的网络模式设置 - “镜像”。启用后,此模式会将 Windows 网络接口镜像到 Linux 中,从而实现(根据公告):
IPv6 支持
使用本地主机地址 127.0.0.1 从 Linux 内部连接到 Windows 服务器
直接从局域网 (LAN) 连接到 WSL
改进了 VPN 的网络兼容性
多播支持
好极了!
要启用此模式:
.wslconfig
编辑位于Windows用户配置文件目录中的文件。默认情况下,此文件不存在。如果您对确保拥有正确的文件有任何疑问,请使用 PowerShell 中的以下命令(以普通、非提升/管理员用户的身份):
notepad ($env:USERPROFILE+".wslconfig")
确保存在以下几行:
[wsl2]
networkingMode=mirrored
旁注:我的理解是,添加firewall=false
应该可以让你跳过一些后续步骤,但我无法做到这一点,所以也许我的理解是错误的。如果我了解更多信息,我会更新。目前...
退出所有正在运行的 WSL 实例
从提升的管理员PowerShell 测试 WSL2 防火墙是否可用:
Get-NetFirewallHyperVVMCreator
如果此命令返回空值,则您可能使用的是较旧的、不受支持的 Windows 版本,或者您的 WSL 需要更新(建议使用 2.0.9.0 或更高版本(wsl --version
))。
假设您从上一个命令收到了一个值,那么(仍然在提升的管理员 PowerShell 中):
* 最简单(完全禁用 WSL2 防火墙):
Set-NetFirewallHyperVVMSetting -Name ((Get-NetFirewallHyperVVMCreator).VMCreatorId) -Enabled False
* 最安全(仅允许来自私有网络的流量):
New-NetFirewallHyperVRule `
-DisplayName 'Allow All Inbound Traffic to WSL in Private Network' `
-Name 'WSL Private Inbound Rule' `
-Profiles Private `
-Direction Inbound `
-Action Allow `
-VMCreatorId ((Get-NetFirewallHyperVVMCreator).VMCreatorId) `
-Enabled True
注意:要删除此规则,请运行`Remove-NetFirewallHyperVRule -Name 'WSL Private Inbound Rule'`。^ 感谢这位 Github 用户和评论
退出管理 PowerShell 会话并返回到正常 PowerShell:
wsl --shutdown
重新启动 WSL 实例并使用问题中的原始命令进行测试:
python3 -m http.server
从本地网络上的另一台设备,您现在应该能够使用以下方式访问该服务:
* IPv4 或 IPv6:`http://<ip_address>:8000`
* 广播本地网络上的 IPv6 mDNS:`http://<windows_system_name>.local:8000`
* DNS 名称
较旧的解决方案
WSL1:首先,只需使用 WSL1。对于大多数(但不是全部)需要从网络上的另一台计算机访问应用程序的 Web 开发任务,WSL1 的网络性能会更好,并且可以很好地运行您的应用程序和工具。WSL2 引入了真正的虚拟化 Linux 内核,但 WSL1 的“假内核”(系统调用转换层)目前仍可很好地完成大多数任务。
在 WSL1 下运行时python3 -m http.server
,您将能够通过 Windows 主机的 IP 地址(或 DNS 名称)自动从网络上的其他计算机访问它。正如 OP 在自我回答中提到的那样,那个讨厌的 WSL1 错误已经修复多年了。
SSH 反向隧道如果您确实需要使用 WSL2,这里有一个选项,它不需要端口转发或任何高级防火墙规则,每次 WSL 重新启动时都需要更新这些规则。这些规则的问题在于,每次重新启动时 WSL 的 IP 地址都会发生变化,这意味着必须不断删除并重新创建这些规则。
另一方面,我们可以在 WSL2 中使用 SSH 连接到 Windows,其中名称甚至 IP 地址都是恒定的。
一次性设置:启用 SSH
虽然需要进行一些一次性设置,但无论如何它都很有用:
首先,安装/启用 Windows OpenSSH 服务器。这是 Windows 内置的功能,只需启用即可。您可以在此处找到完整说明,但通常只需执行以下操作(从管理员 PowerShell 中):
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
} else {
Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
}
编辑C:ProgramDatasshsshd_config
并设置GatewayPorts yes
。这使我们能够使用 SSH 作为网络上其他设备的网关。
最后,当然,您需要在 Windows 中设置防火墙规则,以允许您使用的 HTTP(s)(或其他)端口。示例(来自 Admin PowerShell):
New-NetFirewallRule -DisplayName "WSL Python 8000" -LocalPort 8000 -Action Allow -Protocol TCP
并重新启动 OpenSSH Server 服务:
Restart-Service sshd
创建隧道
有了这个,创建我们需要的隧道就很简单了:
ssh -R 8000:localhost:8000 NotTheDr01ds@$(hostname).local
当然,NotTheDr01ds
如果与 WSL 用户名不同,请用你自己的 Windows 用户名替换
由于 SSH 在 Windows 端运行,因此这将使用您的Windows用户名和密码。
一旦确保它可以正常工作,还有另外两个建议:
+ 设置基于密钥的身份验证,这样您就不需要每次都输入密码
+ 将 SSH 连接更改为:
ssh -fN -R 8000:localhost:8000 NotTheDr01ds@$(hostname).local
这会将 SSH 会话置于后台并且不为其分配终端。
解决方案 4:
请按照erazerbrecht分享的链接中提到的步骤,通过提供您的 IP 地址(而不是使用localhost)和端口号来运行您的 HTTP 服务器。
示例(以 root 身份):
cd ~
python3 -m http.server -b 192.168.1.178 8000
输出:
Serving HTTP on 192.168.1.178 port 8000 (http://192.168.1.178 :8000/) ...
否则,您也可以这样做,而不是点击链接:
从左侧菜单进入Windows Defender防火墙 →高级设置
选择入站
创建新规则;
Next
选择程序作为规则类型;
Next
选择所有程序;
Next
选择允许连接;
Next
检查所有三个(域,私人和公共);
Next
为规则提供名称
按
Finish
你可以走了
解决方案 5:
避免使用网络上某些答案中使用的防火墙规则。我看到其中一些创建了某种允许所有防火墙规则(允许来自任何 IP 地址和任何端口的任何流量)。这可能会导致安全问题。
只需使用此答案中的这一行,它对我来说非常有效(它只是创建一个端口代理):
netsh interface portproxy add v4tov4 listenport=<windows_port> listenaddress=0.0.0.0 connectport=<WSL_port> connectaddress=<WSL_IP>
其中是WSL<WSL_IP>
的 IP 地址。您可以通过在 WSL 上运行来获取它。此外, 是 Windows 将监听的端口,是服务器在 WSL 上运行的端口。ifconfig
`<windows_port>`<wsl_port>
您可以使用以下命令列出当前端口代理:
netsh interface portproxy show all
解决方案 6:
目前(2022 年 3 月),要从外界访问在 WSL 2 上运行的应用程序,我们需要执行以下操作:
在防火墙中制定规则,以接受应用程序正在运行的协议和端口上的传入(和传出)连接(例如TCP/80)
获取 WSL 的 VM IP 地址:
hostname -I
正如本页 (从局域网 (LAN) 访问 WSL 2 发行版) 所述,使用此 IP 地址在 Windows 中添加一个代理,该代理侦听端口并重定向到 WSL 的 VM。这可以通过以管理员身份运行的 PowerShell 中的以下命令完成:
netsh interface portproxy add v4tov4 listenport=80 listenaddress=0.0.0.0 connectport=80 connectaddress=192.168.101.100
192.168.101.100
VM 的 IP 地址来自哪里hostname -I
以及80
我们想要向外部开放的端口。
由于 WSL 的 IP 地址在重新启动时会发生变化,因此应在 PowerShell 脚本中自动执行此操作,其中删除以前的代理并将新代理设置为当前 IP 地址。所有功劳都归功于 GitHub 上的 Edwindijas,此脚本深受他的启发:
$ports=@(80,21,22) # the ports you want to open
$addr='0.0.0.0';
$wslIP = bash.exe -c "hostname -I"
if(! $wslIP -match 'd{1,3}.d{1,3}.d{1,3}.d{1,3}') {
echo "WSL's IP cannot be found. Aborting";
exit;
}
$portsStr = $ports -join ",";
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $portsStr -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $portsStr -Action Allow -Protocol TCP";
for ($i = 0; $i -lt $ports.length; $i++) {
$port = $ports[$i];
iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$wslIP";
}
解决方案 7:
与countach 的答案类似,但使用iproute2:
如果使用 Ubuntu,请在 WSL 终端中输入。查找显示某个小数字在哪里的ip address
条目。那里有一个 IP 地址。使用它。#: eth0 ...
`#`
解决方案 8:
我遇到了同样的问题,我必须从我的 WSL 机器(ubuntu)访问本地主机
因此,由于这是一个虚拟机,因此无法在浏览器中直接访问该 URL,但您可以将其想象为在同一本地网络上运行的机器,并以此方式访问它,为此只需在 ubuntu 中打开一个新终端并运行
是否配置
如果你的 wsl 中没有安装,只需运行
sudo apt 安装 net-tools
您可以在那里看到可以通过浏览器直接访问的 inet 地址
例如,在我的情况下,我可以通过以下方式在浏览器中访问服务器:
解决方案 9:
目前有一个适用于该情况的 npm 包:
npx expose-wsl@latest
解决方案 10:
看一下 Microsoft 文档,从 Windows(localhost)访问 Linux 网络应用程序:
根据文档,如果你运行的是旧版本的 Windows(Build 18945 或更低版本),则需要获取 Linux 主机虚拟机的 IP 地址
在 Windows 10 Build 18945 (2019-07-19)发布后,这应该不是一个问题。
解决方案 11:
我编写了一个 PowerShell 脚本,其中使用了两个对我来说非常有效的简单命令。
# Get the IP address of the WSL
$str = wsl -- ip -o -4 -json addr list eth0 | ConvertFrom-Json | %{ $_.addr_info.local } | ?{ $_ }
echo "WSL IP address: $str"
# Establish the connection with the WSL
# listenport,connectport ports can be changes as per the needs
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=8080 connectaddress=$str
使用此代码创建一个.ps1文件并从 PowerShell 终端执行它。它可以添加到调度程序中,以便每次 Windows 启动时都会运行该脚本。
解决方案 12:
我按照@toran-sahu 的回答向 Windows Defender 防火墙添加了入站规则,但最近(添加第二个 wsl2 实例后)它又停止工作了。我遇到了这个问题线程,在 cmd 提示符中运行以下命令使它再次正常工作。
wsl --shutdown
更新:看来此问题是由于启用了快速启动而引起的https://stackoverflow.com/a/66793101/8917310
解决方案 13:
对我有用的修复(cisco vpn 连接后无法访问网络)。使用 windows regedit 路径 -> HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss 更改 NatNetwork 和 NatGatewayIpAddress 中的值(例如 192.168.77.1 和该范围内的子网)
解决方案 14:
您可以使用此工具添加所需的netsh
防火墙规则,以便从 Windows 和网络中的其他主机访问该服务。
简单写一下:
pfwsl add 8000
在 PowerShell 中,它将使您指定的端口可访问。
要禁用它,请写入pfwsl rm
。要列出当前启用的,请写入pfwsl ls
。
我是作者
解决方案 15:
我已经在重新安装的 WSL上测试了Microsoft Windows 更新(KB4532132) ,并且它可以按预期运行。
该问题似乎与旧的 Windows 版本或旧的 WSL 版本有关。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件