86

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

为了更清楚起见,我在 localhost:3000 上运行 Puma 服务器

我尝试了以下方法:

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

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

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

有什么我至少可以正确查看网站的东西吗?(以及对 VScode 部分的任何评论将不胜感激)

4

16 回答 16

85

看这个视频,它帮助了我:

https://www.youtube.com/watch?v=yCK3easuYm4

netsh interface portproxy add v4tov4 listenport=<port-to-listen> listenaddress=0.0.0.0 connectport=<port-to-forward> connectaddress=<forward-to-this-IP-address>

例如

netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=172.30.16.3

微软在他们的WSL1 到 WSL2 比较页面上发布了一些关于此的信息

之后不要忘记反馈。

于 2020-09-07T16:38:48.553 回答
31

选项 1:使用端口转发

这个对我有用:

  1. 通过 xmeng1 的脚本运行端口转发:https ://gist.github.com/xmeng1/aae4b223e9ccc089911ee764928f5486

该脚本中的防火墙命令在我的系统上不起作用。所以我完全停用了 Windows 防火墙并使用以下剥离版本。(最终用户无论如何都会使用 3d 方防火墙,所以没关系)。

$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=@(123,456);

#[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 ",";

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";
}

#Then so something, e.g.
#bash.exe -c "cd /g-inverter; ./start_docker.sh"

您可能需要在脚本中为 ifconfig “apt install net-tools”。在互联网上的某个地方也有一个使用“ip addr”的解决方案,在一个很棒的线程中不需要 ifconfig”,我现在没有链接。

警告

这仅适用于 TCP 流量。netsh interface portproxy 不支持 UDP 流量的端口转发。

选项 2:桥接模式

解决方案:从 NAT 切换到桥接模式

WSL2 默认处于 NAT 模式。wsl2 系统在另一个子网中有另一个 IP,而不是主机。PC 来自外部对等方,只有 windows IP 可见,wsl2 ip/net 是隐藏/内部的。所以所有流量都需要被windows IP接受,然后转发到wsl2 ip(端口转发)。

还有另一种模式称为桥接模式。在桥接模式下,您的网络接口卡将共享给 wsl2 系统,并且它将在 wsl2 中获得自己的 IP/Net。因此,实际上您的网卡被两个系统(windows / wsl2)共享,并且将有两个 IP,就好像您有两个系统,每个系统都有自己的网卡。很酷的事情:当 Windows 也使用与 wsl2 应用程序(如 111)相同的端口时,您将永远不会发生端口冲突。

启用桥接模式

以管理员身份打开 Hyper-V 管理器

选择你的电脑,打开虚拟交换机管理器

选择 WSL

设置为外网

选择流量经过的网卡

然后登录到 wsl2 终端并配置一个 IP 地址。例如

sudo ip addr add 192.168.0.116/24 dev eth0

您需要使用另一个免费 IP(不是您的 Windows IP)。如果您的网络有 DHCP 服务器,您的 wsl 可以通过以下方式获得:

sudo ip addr flush dev eth0
sudo dhclient eth0

警告

我还没有详细说明如何让 DNS 在这种情况下工作,以防您仍然希望能够访问互联网(apt 等)。有一些来自 MS 的文档写在 /etc/resolv.conf 中,并且可能执行那里写的内容并安装 resolvconf(在上述所有步骤之前,因为一旦开始桥接就没有互联网)可能会奏效。

于 2020-06-17T21:06:25.643 回答
23

首先,您需要在您的机器上打开一个端口,以便能够从您的网络访问它。

netsh advfirewall firewall add rule name="Allowing LAN connections" dir=in action=allow protocol=TCP localport=5000

打开端口(在我的例子中为 5000)后,您需要将此端口转发到您的应用程序在 WSL 中侦听的端口。

netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=5000 connectaddress=localhost connectport=<the port that your app is listening on>

注意:我将连接地址设置为localhost而不是 WSL 的 IP 地址,因为默认情况下,转到 localhost 的请求会转发到 WSL。通过这样做,您无需在每次重新启动计算机时都设置端口转发,因为 WSL 的 IP 地址是动态的。

于 2021-03-05T02:12:32.603 回答
19

WSL2 在本地接口上公开端口(这就是为什么在 Windows 中,localhost:8080当您的8080服务在 WSL2 中运行时您可以访问),但它们会监听127.0.0.1(这就是您无法yourhostname:8080在 LAN 上的其他计算机上访问的原因)。

有一个工具可以解决这个问题,称为 WSLHostPatcher,你可以在这里找到它(通过发布部分下载):https ://github.com/CzBiX/WSLHostPatcher

WSLHostPatcher 将行为更改为侦听所有 IP,将任何 WSL2 服务公开给网络上的所有计算机。

  1. 从https://github.com/CzBiX/WSLHostPatcher/releases下载最新版本(我测试了 v0.1.0)
  2. 解压文件
  3. 跑过WSLHostPatcher.exe
  4. (重新)在 WSL2 中启动您的服务

现在应该可以通过网络上的其他计算机访问该服务。

于 2021-03-08T00:46:31.760 回答
10

考虑到上述(正确)解决方案,这是一个适用于我的简化版:

  1. 使用“ifconfig”查找您的 wsl2 公共 IP 地址。请记住,每次 Windows 重新启动时 Hyper-V 交换机 IP 都会更改,因此 wsl2 中的公共 IP 也会更改。 在此处输入图像描述
  1. 使用上一步中在 connectaddress 参数中找到的 IP 运行以下命令:

    netsh interface portproxy add v4tov4 listenport= listenaddress=0.0.0.0 connectport= connectaddress=172.24.26.277

参数说明:

  • listenport:Windows 将监听的端口

  • listenaddress:您的 Windows 将监听的地址。通常 0.0.0.0 应该可以。

  • connectport:您的 Linux Distro 通过 wsl2 将侦听的端口。

  • connectaddress :您的 Linux wsl2实例的公共 IP(在步骤 1 中找到)

以管理员身份使用 cmd 或 PowerShell 运行上述命令。

于 2020-11-24T12:19:29.260 回答
10

让您的 WSL2 发行版表现得像网络上的任何其他客户端

在 Roelofs 建议 2 的基础上,这就是我的案例中所有内容的原因。不幸的是,我太新鲜了,不能发表评论。

我的出发点: WSL2 下的
Win 10 Pro Ubuntu (带有 Linux 容器的 Docker)

我的目标:
从网络上的客户端获取 rtmp 流进出运行在 Ubuntu 机器上的 nginx 服务器。

建造桥梁

就我而言,我无法让 Hyper-V 正确设置网桥。在Hyper-V 管理器的虚拟交换机部分中为 WSL 交换机选择外部网络并点击应用后,它最终失败并出现错误 0x80070490。不知道为什么,也没有时间调查。WSL 没有运行,Docker 服务也没有运行。

相反,我只是将设置保留在内部网络上,并在网络连接 (run->ncpa.cpl) 下以手动方式桥接接口。就我而言,WiFi 连接和vEthernet (WSL)。这样做之后,我立即失去了互联网连接,我花了很长时间才发现需要重新启动。(Windows 曾经没有要求我这样做!)

使 VM 成型

重启后,我现在可以从主机访问互联网,网桥设置为 DHCP,并继承了 WiFi 接口的 IP (192.168.1.246)。伟大的。

但是,VM 仍在获取虚拟交换机的 IP(或者您想查看它,windows 似乎分配给交换机和 VM 的随机 172.xxx 地址)。

启动 Ubuntu,我决定做一个:

sudo ip addr flush dev eth0

继续:

sudo dhclient eth0

自从我使用来自 Windows 商店的香草 Ubuntu 发行版以来,向我抛出了一些错误,没有systemd,没有乐趣。尽管如此,它还是设法将网桥的 IP 添加到 eth0。由于这不是很方便,我摆脱了它:

sudo ip addr del 192.168.1.248/24 dev eth0

但在偷看路由表之前:

user@vm:~$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

删除旧 IP 后,我从我的 DHCP 范围之外添加了一个唯一的 IP:

sudo ip addr add 192.168.1.50/24 dev eth0

我再次检查了路由表,第一个条目不见了。在这个阶段,我可以ping LAN,但不能ping WAN。

将条目添加回:

sudo ip route add default via 192.168.1.1 dev eth0

现在可以 Ping WAN IP,但没有 DNS 解析。LMGTFM:添加永久 DNS 万一解决方案丢失,这归功于non-static

创建一个文件:/etc/wsl.conf。
将以下行放入文件中

[网络]
generateResolvConf = false

在 cmd 窗口中,运行 wsl --shutdown
重启 WSL2
创建一个文件:/etc/resolv.conf。如果存在,则用这个新文件替换现有文件。
将以下行放入文件中

名称服务器 8.8.8.8

或者您要使用的任何 DNS 服务器的 IP,重复步骤 3 和 4。

因此,总而言之,检查您的路由并正确设置您的 DNS-conf。不幸的是,每次重新启动 WSL 时都会恢复 IP 设置。如果您每次都在讨论如何在此处此处实现自动化时不同意手动执行此操作。我没有时间找到我最喜欢的。

最好的问候亚历山大

于 2020-10-05T23:12:06.837 回答
7
  1. 在 WSL 上安装 ssh 服务器

  2. 在 windows 上找一些 ssh 客户端

  3. 在windows上执行:(Windows的IP为192.168.xx,WSL ip为172.28.xx)

    ssh -L 192.168.x.x:3000:172.28.x.x:3000 someuser@172.28.x.x

如果不起作用,请尝试使用另一个本地端口,例如 (192.168.xx: 3001 :172.28.xx:3000)

于 2020-07-18T05:36:32.893 回答
7

以下是我发现用于 LAN 开发访问在 WSL2(Windows 10 20H2 上的 Ubuntu 20)中运行的东西的完整三个步骤:

1. 一开始:在Windows防火墙中打开Expo ports inbound

Windows 防火墙应该打开——不要关闭它!—,默认情况下它应该阻止入站尝试。

以下将打开端口 19000–19001,入站,但仅在您配置为“私有”的网络上(这是部分,如果您在域中,请-Profile Private替换为):Domain

  • 将 替换为19000-19001您需要的端口。
  • 替换DisplayName为适合您的。方便以后查找规则。

(powershell作为管理员)

New-NetFireWallRule -Profile Private -DisplayName 'Expo ports for LAN development' `
    -Direction Inbound -LocalPort 19000-19001 -Action Allow -Protocol TCP

(您可以在使用后检查它Get-NetFirewallRule |Where-Object {$_.DisplayName -Match "Expo.*"}- 将-Matcharg 替换为您选择的 DisplayName)

2.指向portproxyWSL;重新运行“每次 WSL 有一个新的 IP 地址”

(我还不确定 WSL IP 地址多久更改一次,但我怀疑只有重新启动会)

我在网上看到了一些东西,包括这里的其他答案,说 portproxy toconnectaddress=127.0.0.1但它对我不起作用(WSL2,Windows 10 20H2)。
我不能说为什么其他人发现它有效,我只能说重复测试对我确认127.0.0.1没有用,但 WSL IP 地址确实有效。

所以这里有一个可重用的命令来自动将连接地址设置为正确的 WSL 地址:
(powershell - 只是为了方便内联Trim()- 作为管理员)

netsh interface portproxy add v4tov4 listenport=19000 listenaddress=0.0.0.0 `
    connectport=19000 connectaddress=$($(wsl hostname -I).Trim());

netsh interface portproxy add v4tov4 listenport=19001 listenaddress=0.0.0.0 `
    connectport=19001 connectaddress=$($(wsl hostname -I).Trim());

3.(可选)如果您的 WSL 需要知道您的开发机器 LAN IP 地址

(例如 QR-Code 移动应用程序,如 Expo)

您需要在 WSL 中重新运行以下命令“每次开发主机都有一个新的 IP 地址”

  • 这可能是变化最频繁的一个。当您更改网络(例如家庭/办公室)时,您的笔记本电脑本地网络 IP 肯定会发生变化 - 并且在其他时间也会发生变化。

幸运的是,它也是可粘贴/可别名的:
WSL2 shell

netsh.exe interface ip show address "Wi-Fi" | grep 'IP Address' | sed -r 's/^.*IP Address:\W*//'

# e.g. for Expo, I used:
export REACT_NATIVE_PACKAGER_HOSTNAME=$(netsh.exe interface ip show address "Wi-Fi" | grep 'IP Address' | sed -r 's/^.*IP Address:\W*//')

echo Meteor will use dev machine IP address: $REACT_NATIVE_PACKAGER_HOSTNAME

我“希望我不必重新运行东西,一切都可以自动化”,
但同样的懒惰让我很高兴至少有命令 2(和 3)易于“重新运行”并始终获得 LAN 访问我需要我的 WSL2 托管服务。

于 2020-12-14T19:23:18.500 回答
2

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

  1. 启动wsl
  2. 离开 wsl shell 并检查所有发行版是否已停止 (wsl -l -v)
  3. 修改后的 WSL 虚拟交换机
  4. 再次启动wsl
于 2020-08-21T08:38:54.570 回答
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
}

学分:

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

于 2021-03-03T23:28:43.023 回答
1

这是一个可能比已提供的许多其他解决方案更简单的解决方案。socat除了您正在使用的 WSL2 实例之外,您还需要一个已安装的 WSL1 实例。

在 WSL1 实例上,socat像这样开始:

socat -d TCP-LISTEN:3000,reuseaddr,fork TCP:localhost:3000

当您像这样启动 socat 时,Windows 会询问您是否要允许网络访问该端口。确认。

确保您的 puma 绑定到所有接口上的端口 3000。

您现在可以从 LAN 访问您的开发服务器。这里发生的事情是,socat 正在将请求转发到您的以太网端口上的 3000 到 localhost 上的端口 3000,这将神奇地被 Windows 转发到 WSL2。

(我目前正在使用这个确切的设置从我 LAN 上的 iOS 应用程序访问我在 WSL2 上的 Django 开发服务器。)

于 2020-10-09T11:07:48.777 回答
1

另一种解决方案是将 WSL2 直接桥接到相关的网络适配器。我尝试在 Hyper-V 中执行此操作,但无法使其正常工作。但是,起作用的是Control Panel\Network and Internet\Network Connections,选择 NIC(Ethernet 3在我的情况下)并vEthernet (WSL)通过右键单击并选择“Bridge Connections”来桥接它们:

桥接菜单项

你应该得到这样的结果:

桥接连接

建立桥之后,让 Windows 做一分钟左右(说真的!),然后再继续。

接下来打开 WSL 并让它运行 dhcp 以获取新地址:

sudo ip addr flush dev eth0 && sudo dhclient eth0

此时,WSL 和 Windows 都应该具有连接性。通过 ping 一些 IP 地址(如 1.1.1.1 或 8.8.8.8)进行检查。如果这不起作用,请拆除桥并重试。请记住在 Windows 配置所有内容时等待一两分钟。

此外,请确保它eth0具有来自您的 LAN ( ip addr sh eth0) 的地址。

现在的问题是 WSL 可能无法解析域名,因为 WSL/etc/resolv.conf在启动时创建指向不再存在的虚拟网关。这可以通过要求 wsl 不/etc/resolv.conf通过附加以下内容来/etc/wsl.conf创建(如果文件不存在则创建文件)来解决:

[network]
generateResolvConf=false

然后通过重启LxssManagerwindows服务来重启wsl。唯一剩下的就是在 WSL 中设置备用 DNS 服务器。而不是生成的/etc/resolv.conf,只需创建一个类似的/etc/resolv.conf东西:

nameserver 1.1.1.1
nameserver 1.0.0.1

而已!WSL 现在应该桥接到您的网络并在其上拥有自己的唯一地址。

于 2021-11-01T11:39:39.390 回答
1

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
于 2021-12-31T18:41:21.420 回答
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. 当然,我可以为路由器设备配置端口转发。
于 2020-06-29T08:20:58.227 回答
0

所以,在过去的两天里,我为此苦苦挣扎了一段时间,在这个线程或其他地方似乎没有任何效果。我终于通过拼凑我看到的一些东西来解决它,我想我会在这里发布我的解决方案,以防它帮助任何人。不过有一些注意事项。首先,我绝对不是 Linux 专家,所以“它可以工作”只是我真正唯一考虑的 :) 其次,这是在家庭开发服务器上,这意味着安全不是我最关心的问题(服务器不是以任何方式暴露在我的局域网之外),所以我做了一些我不会在真正重要的机器上做的事情。最后,我不需要它一直工作,这意味着我可以在服务器重新启动后自己做一些事情来让它全部工作。

考虑到所有这些,第一步是,如上所述,将 WSL 适配器与服务器的物理适配器桥接。在我的例子中,服务器有一个静态 IP,所以我配置了网桥适配器,结果是 IPv4 的静态 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 文件并将其放入我的启动文件夹中,以便在自动重新启动后运行该脚本。这应该可以正常工作并使其完全自动化,但我还没有完成。

于 2021-12-30T20:19:35.850 回答
-8

试试-b 0.0.0.0 这对其他操作系统有效

于 2020-04-03T21:25:11.490 回答