博主头像
MoYan's Blog

前进,不择手段的前进!

让 Windows 访问到 WSL 中监听本地的应用

引言

WSL (Windows Subsystem for Linux) 2 已经极大地提升了 Windows 上 Linux 开发体验,它提供了更高效的性能和更好的兼容性。然而,一个常见的“陷阱”是:你在 WSL 中运行了一个服务,比如一个 Web 服务器或一个数据库,它默认监听在 127.0.0.1 (localhost)。此时,你可能会发现从你的 Windows 宿主机无法直接通过 localhost 或 WSL 的 IP 地址访问到这个服务。这就像是 WSL 内部的 localhost 有一道无形的墙,将服务“隔离”在了 Linux 环境中。

那么,如何打破这堵墙,让 Windows 也能愉快地访问 WSL 中监听本地端口的应用呢?本文将深入探讨这个问题及其解决方案,特别是针对 Arch Linux 环境下的持久化配置。

为什么会出现这个问题?

默认情况下,127.0.0.1(或 localhost)是一个回环地址,设计初衷就是让运行在同一台设备上的应用程序可以相互通信。当你的 WSL 内部的 Linux 应用监听在 127.0.0.1 时,它只接受来自 WSL 内部的连接请求。

尽管 WSL 2 通常会尝试为一些常见服务(如 HTTP/HTTPS)进行自动端口转发,但在某些特定情况下(比如服务没有绑定在 0.0.0.0,或者端口转发没有按预期工作),你就需要手动干预。问题在于,从 Windows 宿主机的视角来看,WSL 的 127.0.0.1 并不是 Windows 的 127.0.0.1;它们是两个独立的网络空间。

核心解决方案:网络地址转换 (NAT)

要解决这个问题,我们需要在 WSL 内部进行一些高级网络配置,具体来说是利用 Linux 内核参数 (sysctl)防火墙规则 (iptables) 来实现网络地址转换 (NAT)。其核心思想是将所有进入 WSL 的特定 TCP 流量,强制重定向到 WSL 内部的 127.0.0.1 地址。

我们通过一个 shell 函数 expose_local 来实现这一逻辑:

expose_local(){
    # 步骤1: 允许内核路由本地回环地址
    # 默认情况下,Linux不允许从非回环接口路由到127.0.0.0/8地址。
    # 开启此选项后,外部流量才能通过DNAT被重定向到127.0.0.1。
    sudo sysctl -w net.ipv4.conf.all.route_localnet=1 >/dev/null 2>&1

    # 步骤2: 设置iptables DNAT规则
    # 这条规则将所有进入的TCP流量(PREROUTING链)的目的地址修改为127.0.0.1。
    # 这意味着任何试图连接到WSL IP的TCP请求,都会被透明地转发到WSL内部的localhost服务。
    sudo iptables -t nat -I PREROUTING -p tcp -j DNAT --to-destination 127.0.0.1
}

命令详解:

  1. sudo sysctl -w net.ipv4.conf.all.route_localnet=1

    • 这个命令设置了一个内核参数。它的作用是告诉 Linux 内核,即使数据包的目标地址是 127.0.0.0/8(本地回环网络范围),也允许它从非回环接口(例如 WSL 的虚拟网卡)进行路由。这是进行后续 DNAT 的前提。
    • >/dev/null 2>&1 则用于抑制命令的输出,使其静默执行。
  2. sudo iptables -t nat -I PREROUTING -p tcp -j DNAT --to-destination 127.0.0.1

    • 这是一条 iptables 规则,利用了网络地址转换 (NAT) 功能。
    • -t nat: 指定操作的是 NAT 表,用于地址或端口转换。
    • -I PREROUTING: 在 PREROUTING 链的开头插入规则。这条链在数据包进入网络堆栈后,但在路由决策之前被处理。这允许我们在数据包被路由到应用程序之前修改其目标地址。
    • -p tcp: 规则只适用于 TCP 协议的流量。
    • -j DNAT: 执行目标地址转换 (Destination NAT)。
    • --to-destination 127.0.0.1: 将所有符合条件的 TCP 数据包的目的地址修改为 127.0.0.1
    • 简单来说,这条规则会拦截所有进入 WSL 的 TCP 连接,并把它们的目的地强制改为 WSL 内部的 localhost

在 Arch Linux 中实现持久化

上述命令在重启 WSL 实例后会失效。为了让这些配置永久生效,我们需要将它们添加到系统启动时加载的配置文件中。对于 Arch Linux,我们主要通过 sysctl.diptables systemd 服务来实现。

1. 持久化 sysctl 参数

/etc/sysctl.d/ 目录下创建一个配置文件:

# 1. 创建或编辑配置文件
sudo vim /etc/sysctl.d/99-custom-network.conf

# 2. 在文件中添加以下内容:
# net.ipv4.conf.all.route_localnet = 1

# 3. 保存并退出。
# 4. 立即应用更改(无需重启):
sudo sysctl --system

2. 持久化 iptables 规则

Arch Linux 通常使用 iptables-nft (基于 nftables 后端) 和 Systemd 服务来管理 iptables 规则。

# 1. 确保已安装 iptables-nft 包:
sudo pacman -S iptables-nft

# 2. 在当前WSL会话中,先应用iptables规则(如果你还没有应用过)
sudo iptables -t nat -I PREROUTING -p tcp -j DNAT --to-destination 127.0.0.1

# 3. 保存当前的IPv4 iptables规则到系统默认文件:
sudo iptables-save > /etc/iptables/iptables.rules

# 4. 启用并启动 iptables systemd 服务,使其在每次WSL启动时自动加载规则:
sudo systemctl enable iptables.service
sudo systemctl start iptables.service

# 如果你也需要IPv6规则的持久化,可以启用ip6tables服务:
# sudo systemctl enable ip6tables.service
# sudo systemctl start ip6tables.service

完成以上步骤后,即使你关闭并重新启动 WSL 实例,这些网络配置也会自动生效,你的 Windows 宿主机就能访问 WSL 中监听 localhost 的服务了!

让 Windows 访问到 WSL 中监听本地的应用
https://blog.moyanjdc.top/archives/16/
本文作者 MoYan
发布时间 2025-08-17
许可协议 CC BY-NC 4.0
发表新评论