从网络上的另一台 PC 访问在 Ubuntu/WSL 中运行的 Web 应用程序

Wik*_*esa 4 permissions kernel networking windows-subsystem-for-linux 20.04

我在 WSL 中使用 Windows 10 和 Ubuntu 20.04.04 LTS(来自 Microsoft Store)。

它运行具有 Web 界面的软件,我可以在这台 PC 上的 Windows 中使用 Edge 连接到 来访问此应用程序,不会出现任何问题localhost:4040

不幸的是,同一网络中的另一台电脑无法做到这一点。

我需要配置什么才能使网络中的另一台 PC 也可以访问在 WSL 上的 Ubuntu 中运行的软件的 Web 界面?

如果我使用该软件的Windows版本,网络上的其他PC访问Web界面没有问题。然而,Windows 版本的软件不适合我。

Not*_*1ds 5

背景

原因是 WSL2 的网络在 Hyper-V 管理程序创建的虚拟交换机中运行。WSL2 VM 的网络接口在 Windows 主机本身内部(或“后面”,取决于您如何看待它)运行(NAT)。

这意味着 WSL2 内运行的服务本质上是在一个单独的网络中运行,您的其他 PC/设备对此一无所知。

对于 Windows 主机本身,WSL2 提供了称为“localhostForwarding”的功能,默认情况下启用该功能。正如您所注意到的,当您localhost:4040从本地 Windows 进行访问时,它首先检查是否有某些内容绑定到Windows中的该端口,如果没有,则将其转发到 WSL2 VM 中的端口 4040。

现在至少有四种方法可以解决这个问题:

选项 1:WSL1(对于许多(但不是全部)用例而言,这是最佳/最简单的选项)

您可能会认为 WSL2 已经发布近两年了,它在各方面都会比 WSL1 更好,但事实并非如此。仍然存在 WSL1 效果更好的场景,网络访问就是其中之一。

如果您运行的应用程序不需要 Linux 内核的所有功能,那么它可能会在 WSL1 下运行得很好。WSL1 提供了一个“系统调用翻译层”,将 Linux API 映射到 Windows。这就像一种“反向葡萄酒”。该方法的优点之一是网络调用实际上使用 Windows 网络接口。因此,当应用程序绑定到 WSL1 中的端口 4040 时,它实际上是在 Windows 界面上进行的,并且可以从网络上的其他计算机进行访问。

您可以在 PowerShell(或 CMD,但实际上,为什么?;-)中通过以下方式将 WSL2 实例转换为 WSL1:

wsl -l -v
# Confirm the distribution name is Ubuntu, adjust the next commands otherwise
wsl --export Ubuntu .\path\to\ubuntu_backup.tar # Optional, and you put the backup where ever you want
wsl --set-version Ubuntu 1
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建 Ubuntu 的第二个副本并将其设为 WSL1:

wsl -l -v 
# Confirm the distribution name is Ubuntu, adjust the next commands otherwise
wsl --export Ubuntu .\path\to\ubuntu_backuptar
mkdir .\location\for\new\Ubuntu\
wsl --import UbuntuWSL1 .\location\for\new\Ubuntu .\path\to\ubuntu_backup.tar --version 1
Run Code Online (Sandbox Code Playgroud)

然后通过启动发行版并按照我的超级用户答案wsl ~ -d UbuntuWSL1中的说明在新副本中设置您的用户名。

如果您发现您的应用程序由于某种原因无法在 WSL1 下运行,请继续阅读...还有其他选项。

选项2:SSH反向隧道转发

这是我个人的偏好,可以轻松地将连接转发到 WSL2 发行版(例如 Ubuntu)。

  • 一次性设置:

    • 按照官方文档中的说明安装 Windows OpenSSH Server 。

    • 编辑C:\ProgramData\ssh\sshd_config并取消注释GatewayPorts yes

    • 打开管理 PowerShell。

    • 使用以下命令重新启动 Windows SSH 服务器Restart-Service sshd

    • 添加防火墙规则以允许您的端口(在您的情况下为 4040):

      New-NetFirewallRule -DisplayName 4040 -Direction Inbound -LocalPort 4040 -Protocol TCP -Action Allow
      # Set DisplayName to whatever you need to remember it
      
      Run Code Online (Sandbox Code Playgroud)

      注意:如果您需要删除此规则,那就是Remove-NetFirewallRule -DisplayName 4040(或任何您命名的规则)。

  • 然后,在 Ubuntu/WSL2 中,要建立转发,请运行:

    ssh -fN -R 4040:localhost:4040 $(hostname).local
    
    Run Code Online (Sandbox Code Playgroud)

    使用您的Windows(不是 Ubuntu/WSL2)用户名和密码。

    解释:

    • sshto $(hostname).local,应解析为您的 Windows 计算机名称 + .local解析为 Hyper-V 交换机的正确 IP 地址。请参阅我关于 mDNS 解析主题的Stack Overflow 回答。

    • -f请求密码后将 ssh 会话置于后台(如果需要)

    • -N说“不要启动终端或在远程主机上运行任何命令,只需设置连接和转发”。

    • -R 4040:localhost:4040是关键,它设置一个反向隧道,以便当有人连接到 Windows 端的端口 4040 时,该连接会转发到同样位于端口 4040 上的 Ubuntu/WSL2 的本地主机。

此时,您就可以使用一个命令来启动转发,您也可以将其放入启动 Web 应用程序的脚本中。

选项 3:Windows 端口转发

虽然您可以从 Windows 端设置转发,但由于 WSL2/Ubuntu 的 IP 地址是动态设置的,并且每次重新启动(或关闭 WSL)时都会发生变化,因此这会变得更加困难。

我将向您指出Microsoft 文档以获取确切的命令,但请注意,您必须确定每次运行该命令时要使用的 IP 地址。

您可以编写脚本(请参阅有关该主题的原始 Github 问题中的示例),但它比 SSH 方法复杂得多,我不明白这一点。

选项 4:使用 Bridge 进行 WSL2 预览

对于某些人(但不是您)来说,这可能是最好的选择,如果他们愿意运行 WSL2 预览版并拥有 Windows 11 专业版/教育版(或更高版本),而您则不然。对我个人而言,预览版中的一个单独的 SSH 错误/限制使我无法将其作为我的日常驱动程序运行。

在 Windows 11 上,您可以通过 Microsoft Store 安装更新的预览版 WSL。此版本将取代现有的 WSL,但您始终可以通过卸载 Store 应用程序恢复到原始版本。

此预览版有一项新功能,允许您指定与 WSL2 一起使用的特定 Hyper-V 网络交换机,并且您可以创建该网络交换机并将其配置为桥接。

虽然我还没有亲自测试过它(我会在某个时候进行测试),但您可以按照这篇博文(不是我的)中的说明进行操作。一位 Microsoft 开发人员的最初声明隐藏在我上面链接的 Github 问题(目前)650 多条评论中。