![](/img/trans.png)
[英]Crontab not running python script on Windows Subsystem for Linux (WSL)
[英]Access a web server which is running on WSL (Windows Subsystem for Linux) from local network
将 Ubuntu 安装为 WSL(适用于 Linux 的 Windows 子系统)后,我运行了:
root@teclast:~# python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 ...
and try to access to this web server from my windows machine http://0.0.0.0:8000
or http://192.168.1.178:8000
but no success, web server available only by the address http://127.0.0.1:8000
或http://localhost:8000
这意味着我无法从 my.network 中的另一台电脑连接到这个 web 服务器。 是否可以从外部访问 WSL?
现有的答案都不适合我,因为 WSL2 在自己的虚拟机中运行并且有自己的网络适配器。 您需要某种桥接或端口转发才能使非本地主机请求工作(即来自同一网络上的另一台主机)。
我在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 服务。
在你的虚拟机中,执行 ifconfig
您将在第一部分 (eth0:) inet xxxx 中看到您的 IP
这个 xxxx 是您必须在浏览器中输入的 IP。
请按照@erazerbrecht 分享的链接中提到的步骤,通过提供您的 IP 地址(而不是使用 localhost)和端口号来运行您的 HTTP 服务器。
例子:
root@teclast:~# 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/) ...
否则,您也可以这样做,而不是点击链接:
1.转到Windows防御者防火墙
2.选择inbound
3.创建new rule
; 下一个
4.规则类型选择Program
; 下一个
5.选择All Program
; 下一个
6.选择allow the connection
; 下一个
7. 检查所有 3 个(域、私有、公共); 下一个
8. 提供规则名称
9.完成
10. 你很高兴
对于刚接触这篇文章的任何人,请查看 Microsoft 文档https://docs.microsoft.com/en-us/windows/wsl/networking#accessing-linux-networking-apps-from-windows-localhost 。
根据文档,如果您运行的是旧版本的 Windows(Build 18945 或更低版本),则需要获取 Linux 主机 VM 的 IP 地址
这应该是 Windows Build 18945 之后的非问题。
我遵循@toran-sahu 关于向 Windows Defender 防火墙添加入站规则的答案,但最近(在添加第二个 wsl2 实例之后)它再次停止工作。 我遇到了这个问题线程并在 cmd 提示符下运行以下命令让它再次为我工作。
wsl --shutdown
更新:似乎这个问题来自启用快速启动https://stackoverflow.com/a/66793101/8917310
类似于@countach 的回答:
如果使用 Ubuntu,请在 WSL 终端中输入ip address
。 查找显示#: eth0 ...
的条目,其中#
是一个小数字。 那里有一个ip地址。 用那个。
我编写了一个PowerShell脚本,使用了 2 个对我来说非常有效的简单命令。
# get the IP address of the WSL
$str = wsl -- ip -o -4 -json addr list eth0 | ConvertFrom-Json | %{ $_.addr_info.local } | ?{ $_ }
echo "Wsl IP: $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 启动时运行。
现在 (03.2022) 要从运行在 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
是来自hostname -I
的 vm 的 IP,而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"
$found = $wslIP -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
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";
}
脚本中提到的 ifconfig 如何在 windows 中工作? 不需要是“ipconfig”吗?
避免使用 web 的某些答案中使用的防火墙规则,我看到其中一些创建了某种允许所有防火墙规则(允许来自任何 ip 和任何端口的任何 terrafic),这可能会导致安全问题
只需使用此答案中的这一行,这对我来说非常有效(只需创建一个端口代理):
netsh interface portproxy add v4tov4 listenport=<windows_port> listenaddress=0.0.0.0 connectport=<wsl_port> connectaddress=<WSL_IP>
其中<WSL_IP>
是 wsl 的 ip,您可以通过在 wsl 上运行ifconfig
来获取它。 <windows_port>
windows_port> 是 windows 将监听的端口, <wsl_port>
是在 WSL 上运行的端口服务器。
您可以使用以下命令列出当前端口代理:
netsh interface portproxy show all
这意味着我无法从我网络中的另一台电脑连接到这个 web 服务器。 是否可以从外部访问 WSL?
应该注意的是,在这里的所有答案中,这个问题最初是针对 WSL1(在被问到时给出的)并且由 OP自行回答为 WSL 或 Windows 问题,该问题已通过 Windows 更新解决。
具有讽刺意味的是,这是 WSL2 上的一个已知问题(见脚注),所以多年后,人们开始在这种情况下找到它(并回答它)。
在 WSL2 上有多种解决方案,但在不尊重其他回答者的情况下,他们都错过了两个最简单的解决方案:
WSL1 :首先,只需使用 WSL1。 对于大多数(但不是全部)web 开发任务,您需要从网络上的另一台机器访问您的应用程序,WSL1 将更擅长联网,并且可以很好地运行您的应用程序和工具。 WSL2 引入了真实的、虚拟化的 Linux kernel,但是 WSL1 的“假内核”(系统调用转换层)今天对于大多数任务仍然可以正常工作。
When running python3 -m http.server
under WSL1, you'll automatically be able to access it from other machines on the network via the Windows host's IP address (or DNS name). 正如自我回答中提到的 OP,那个讨厌的 WSL1 错误已经修复多年了。
SSH 反向隧道如果您确实需要使用 WSL2,这里有一个不需要端口转发或任何高级防火墙规则的选项,每次 WSL 重新启动时都需要更新。 这些规则的问题在于,每次重新启动时,WSL 的 IP 地址都会更改,这意味着必须不断删除并重新创建这些规则。
另一方面,我们可以在 WSL2 中使用 SSH 连接到 Windows,其中的名称,甚至可能是 IP 地址,都是不变的。
有一些一次性设置,但无论如何它都很有用:
首先,安装/启用 Windows OpenSSH 服务器。 这是 Windows 内置的功能,只需启用即可。 您可以在此处找到完整的说明,但这通常只是(来自 Admin 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:\ProgramData\ssh\sshd_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
用户名替换 NotTheDr01ds,如果它不同于 WSL 用户名
这将使用您的Windows用户名和密码,因为 SSH 在 Windows 端运行。
确保它有效后,还有另外两个建议:
ssh -fN -R 8000:localhost:8000 NotTheDr01ds@$(hostname).local
这会将 SSH session 置于后台,而不是为其分配终端。我已经在重新安装 WSL的 Microsoft Windows 更新(KB4532132)上进行了测试,它按预期工作。 似乎问题与旧 Windows 版本或旧 WSL 版本有关。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.