通过本地网络连接WSL2服务器

148

我正在使用WSL2/Ubuntu在我的Windows 10电脑上开发一个Rails应用,感觉很棒!但问题是我无法从同一网络中的另一台计算机连接到我的服务器

为了更清楚地说明,我在本地主机上运行一个Puma服务器,端口为localhost:3000。

我尝试了以下方法:

  1. 直接连接以太网适配器vEthernet(WSL)分配的IP地址 -> 172.26.208.1:3000
  2. 直接连接主机的IPv4地址 -> 192.168.0.115
  3. 添加防火墙例外(使用Bitdefender)
  4. 绑定上述IP地址rails s -b 172.26.208.1 -p 3000

到目前为止,以上所有方法都没有奏效... 我想做的是:

  • 在另一台笔记本电脑/平板电脑/手机上测试网站
  • 从另一台计算机上使用VScode

是否还有其他需要注意的地方,可以让我至少正确地查看网站?(对于VScode部分的任何评论将不胜感激)


以下任何答案都对我没有用(尝试在端口7946上连接TCP和UDP的虚拟化serf集群)。我使用了这里的解决方案:https://github.com/microsoft/WSL/issues/4150#issuecomment-1018524753(也在WSLHostPatcher网站上提到)。唯一的区别是我在`.wslconf`中添加了`dhcp=true`,因为wsl eth0保留了先前的IP(用于先前的Hyper-v适配器)。 - James Schinner
18个回答

4

WSL2-PortForward.cmd

@ECHO OFF
REM ** Set WSL Distro, Distro Port, Host Port
SET LXDISTRO=WinKDE
SET WSL2PORT=3389
SET HOSTPORT=13389
REM ** Reset any existing port proxies and delete any stale firewall rule
NETSH INTERFACE PORTPROXY RESET & NETSH AdvFirewall Firewall delete rule name="%LXDISTRO% Port Forward" > NUL
REM ** Get IP from WSL2 instance and write it out to IP.tmp
WSL -d %LXDISTRO% -- ip addr show eth0 ^| grep -oP '(?^<=inet\s)\d+(\.\d+){3}' > IP.TMP
REM ** Read IP.tmp back into batch variable
SET /p IP=<IP.TMP
REM ** Create the port proxy
NETSH INTERFACE PORTPROXY ADD v4tov4 listenport=%HOSTPORT% listenaddress=0.0.0.0 connectport=%WSL2PORT% connectaddress=%IP% 
REM ** Create a new firewall rule for the port listening on the LAN
NETSH AdvFirewall Firewall add rule name="%LXDISTRO% Port Forward" dir=in action=allow protocol=TCP localport=%HOSTPORT% > NUL
REM ** Summary
ECHO WSL2 Virtual Machine %IP%:%WSL2PORT%now accepting traffic on %COMPUTERNAME%:%HOSTPORT%

输出:

WSL2 Virtual Machine 172.17.109.95:3389 now accepting traffic on MYCOMPUTER:13389

1
脚本运作得非常好!我在WSL中有Yesod应用程序,现在我可以在不同的机器上连接到它。 - Poselsky

3

对于像我一样可能很绝望的人

我尝试了很多方法,我感到绝望 事情变得混乱,我甚至无法将localhost:3000作为默认访问(起初,我可以)

我将wsl2转换为wsl,并将其转换回wsl2(看起来像是我重置了所有wsl2的配置,无论如何,我不确定) 然后我只添加了portproxy,什么都没做,它就能工作了

PS C:\Windows\system32> netsh interface portproxy add v4tov4 listenport=3001 listenaddress=0.0.0.0 connectport=3001 connectaddress=localhost

PS C:\Windows\system32> netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=localhost

PS C:\Windows\system32> netsh interface portproxy show all

Listen on ipv4:             Connect to ipv4:

Address         Port        Address         Port
--------------- ----------  --------------- ----------
0.0.0.0         3001        localhost       3001
0.0.0.0         3000        localhost       3000

这个操作很成功!非常感谢! - Vinícius OA

2

最终我找到了一个解决方案,只需要在Windows主机启动后运行一次,可以同时处理多个WSL2实例,并且不必在WSL2实例重新启动时重新运行!

缺点:无法监听0.0.0.0;您必须明确指定要监听的IP或适配器。(此版本仅侦听一个IP地址,但可以轻松扩展为使用列表)。

$ports = @(8000,8001);     # ports to forward
$iface = "Ethernet";       # alias of the Adapter to listen on

# if your host has a fixed IP, you can specify it here explicitly
# and remove the ping-and-if safeguard;
# but 0.0.0.0 won't work!
$external_ip = (Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias $iface).IPv4Address;

ping -n 1 "$external_ip" > $null

if( !$?  ) {
    echo "error: cannot determine the external IP address";
    exit 1;
}

$firewall_rule_name = "WSL2 Firewall Hole"
Remove-NetFireWallRule -DisplayName "$firewall_rule_name"

New-NetFireWallRule -DisplayName "$firewall_rule_name" -Direction Outbound -LocalPort $ports -Action Allow -Protocol TCP
New-NetFireWallRule -DisplayName "$firewall_rule_name" -Direction Inbound -LocalPort $ports -Action Allow -Protocol TCP

ForEach( $port in $ports ) {
    netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$external_ip
    netsh interface portproxy add v4tov4 listenport=$port listenaddress=$external_ip connectport=$port connectaddress=127.0.0.1
}

致谢:

  • 起点是WSL Github问题#4150上edwindijas的这个脚本
  • 使用localhost代替获取运行中的WSL2实例的IP地址的想法来自于Charl Botha在这里的答案

原始的edwindijas脚本对我不起作用,因为我以有限用户身份运行WSL2,脚本必须以管理员身份运行,并且以管理员身份运行bashwsl -e会得到一个具有不同IP地址的新WSL2实例。


好的,你转发了8000、8001端口,接下来呢?有什么实际用途吗? - ilw

2

关于桥接模式 - 当任何Linux发行版正在运行时,Windows将防止修改WSL虚拟交换机(访问被拒绝的错误)。另一方面,当第一个Linux发行版启动时,WSL交换机会被创建。

  1. 启动wsl
  2. 离开wsl shell并检查所有发行版是否已停止(wsl -l -v)
  3. 修改WSL虚拟交换机
  4. 再次启动wsl

对我来说,这还不够。我必须像这里描述的那样取消网络适配器上的“Hyper-V可扩展虚拟交换机”设置:https://theitways.blogspot.com/2018/01/error-error-applying-virtual-switch.html - Oz Solomon

1

最近两天我一直在努力解决这个问题,但是无论我在这个帖子或其他地方都找不到解决方法。最终我通过整合我看到的几个东西来解决了这个问题,我想在这里发布我的解决方案以帮助其他人。但是有一些注意事项。首先,我绝对不是Linux大师,所以"能工作"就是我唯一的考虑因素 :) 其次,这是在家里的开发服务器上,这意味着安全性不是我最关心的问题(服务器没有以任何方式暴露在我的局域网之外),因此我做了一些我在真正重要的机器上不会做的事情。最后,我不需要让它始终工作,也就是说,如果需要,在服务器重新启动后,我可以自己手动完成所有的操作。

在这一点上,第一步是像上面所述的那样,将WSL适配器与服务器的物理适配器桥接起来。在我的情况下,服务器具有静态IP地址,因此我为IPv4配置了Network Bridge适配器的静态IP、网关和DNS服务器。

之后,我在我的主目录中编写了以下名为startup_tasks.sh的脚本:

#!/bin/bash

clear
echo Running startup tasks...

# Clear existing IP config
sudo ip addr flush eth0
echo .
sleep 2
# Add static IP
sudo ip addr add 192.168.1.100/24 dev eth0
echo .
sleep 2
# Remove existing default gateway
sudo ip route del default
echo .
sleep 2
# Add default gateway
sudo ip route add default via 192.168.1.1
echo .
sleep 2
# Remove existing name resolution config file
sudo rm /etc/resolv.conf
echo .
sleep 2
# Create name resolution config file
sudo touch /etc/resolv.conf
echo .
sleep 2
# Update permissions on file so we can edit it
sudo chmod 777 /etc/resolv.conf
echo .
sleep 2
# Add name servers
sudo echo "nameserver 8.8.8.8" >> /etc/resolv.conf
echo .
sleep 2
sudo echo "nameserver 1.1.1.1" >> /etc/resolv.conf
echo .
sleep 2

echo - Static IP set
echo .
echo ...done!

为了让这个工作正常运行,我还需要确保我的用户帐户具有无需密码的sudo权限,因此将其添加到sudoer文件中:
devuser=(ALL) NOPASSWD:ALL

在服务器重新启动后,我只需运行该脚本,结果是WSL会获得一个静态IP地址,并且我运行的所有服务器(尽管我从上面的脚本中删除了所有Docker容器)都可以访问。

对我来说,这非常简单。

我还考虑过编写一个简单的.vbs文件,并将其放入启动文件夹中,以在重新启动后自动运行该脚本。 这应该可以很好地工作并使一切完全自动化,但我还没有去做。


1
这里提供了一个可能比其他解决方案更简单的方法。您需要在使用的WSL2实例之外,还安装有socat的WSL1实例。
在WSL1实例上,像下面这样启动socat:
socat -d TCP-LISTEN:3000,reuseaddr,fork TCP:localhost:3000

当你像这样启动socat时,Windows会询问是否允许网络访问该端口。确认。
确保你的puma在所有接口上绑定到3000端口。
现在,你将能够从局域网访问你的开发服务器。这里发生的是,socat将请求转发到以太网口的3000端口,然后将其转发到本地主机的3000端口,Windows会自动将其转发到WSL2。
(我目前正在使用这个准确的设置从我的iOS应用程序访问WSL2上的Django开发服务器。)

虽然有基于socat解决方案适用于我,但这个方案会导致“分叉风暴”,因为端口3000的连接会分叉到3000,然后再分叉到3000,以此类推,直到我中断之前运行了如此多的socat,以至于我的Windows主机变得非常缓慢(而且它并不是一台懒惰的主机)。 - NotTheDr01ds
这很奇怪,我使用完全相同的公式,但使用端口8000,从WSL1连接到在WSL2上运行的Django以便通过我的iPhone访问。我们两个配置之间必须存在其他差异。 - Charl Botha
同意。我在想可能是之前尝试留下的某些转发规则造成的问题(关于我的电脑),但我已经清除了所有东西(例如 netsh接口端口代理)。我会尝试另一个端口以确保,但如果失败大概就需要重新启动电脑了,所以我必须等到准备好才行。 - NotTheDr01ds

0

不幸的是,对我来说,这是一个简化的情况,因为我的家庭网络是由我的路由器定义的。由于我的家庭设备不使用背对背连接进行通信,并且我的网络受到路由器防火墙的保护,所以我必须尊重路由器的配置。

  1. 有一个DNS列表-8.8.8.8、8.8.4.4、9.9.9.9支持我的ISP DNS。这意味着必须制作resolv.conf。 nslookup反映了正确的配置。
  2. 可以将DHCP中继配置为外部DHCP
  3. 我可以定义和配置设备如何获取动态IP,包括静态租赁。这假定设备使用正确的DHCP IP地址。
  4. 当然,我可以为已知路由器设备配置端口转发。

-11

尝试使用-b 0.0.0.0,其他操作系统上有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接