跳到主要内容

WSL 中的 SSH 与远程访问

如果你只是想在 Windows 本机里打开一个 WSL 终端,其实不需要 SSH。但当你想做下面这些事情时,SSH 就会很有用:

  • 从 Windows Terminal、VS Code、其他终端工具统一连接到 WSL
  • 从局域网另一台机器登录到你的 WSL 环境
  • 在 WSL 中长期运行开发服务,希望配合 SSH 做转发或远程开发

这篇文档把整个链路拆成两层:

  1. 先让 WSL 内部的 SSH 服务 正常工作
  2. 再决定是只给 Windows 本机访问,还是给 局域网其他机器访问

1. 在 WSL 中安装 OpenSSH

以下示例以 Ubuntu / Debian 为例:

sudo apt update
sudo apt install -y openssh-server

安装完成后,先确认服务文件已经存在:

sshd -T | head

如果系统提示找不到 sshd,通常说明 openssh-server 还没安装成功。

2. 配置 SSH 的最小安全基线

编辑配置文件:

sudo nano /etc/ssh/sshd_config

建议至少确认这些项目:

Port 22
ListenAddress 0.0.0.0
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin no
AuthorizedKeysFile .ssh/authorized_keys

这里的默认思路是:

  • 优先使用公钥认证
  • 不默认开放 root 直接登录
  • 不默认保留密码登录

如果你只是临时测试,也可以把 PasswordAuthentication 改成 yes,等公钥登录确认可用后再关回去。

3. 生成并导入公钥

如果你还没有 SSH 密钥,先在 客户端机器 上生成。以 Windows PowerShell 为例:

ssh-keygen -t ed25519 -C "your_email@example.com"

生成后查看公钥内容:

Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub

再把公钥追加到 WSL 用户的 authorized_keys

mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

如果权限不对,SSH 往往会直接忽略这个文件,所以这一步不要省略。

4. 启动 SSH 服务

先判断你的 WSL 是否启用了 systemd。

方式 A:已启用 systemd

如果你的 /etc/wsl.conf 中已经启用了 systemd:

[boot]
systemd=true

那么可以直接使用:

sudo systemctl enable --now ssh
sudo systemctl status ssh

修改完 wsl.conf 后,记得在 Windows 中执行一次:

wsl --shutdown

然后重新进入发行版。

方式 B:未启用 systemd

如果你没有启用 systemd,可以先手动启动:

sudo service ssh start
sudo service ssh status

这种方式也能用,但要注意:WSL 发行版退出后,服务通常不会像传统 Linux 服务器那样一直常驻。

5. 先验证 Windows 本机能否登录

在 Windows PowerShell 中先做本机测试:

ssh <your_user>@localhost

只要这一步不通,就先不要继续做局域网端口转发。因为后面的 portproxy 只是把请求转给 WSL,不能替你解决 WSL 内部 SSH 本身的问题。

如果你使用了非 22 端口:

ssh <your_user>@localhost -p <port>

6. 让局域网其他机器访问 WSL

默认情况下,其他局域网设备并不能稳定直接访问 WSL。更稳妥的做法是:

  1. 在 Windows 上开放一个监听端口
  2. 把这个端口转发到当前 WSL 实例的 SSH 端口

6.1 获取 WSL 当前 IP

在管理员 PowerShell 中执行:

$distro = "Ubuntu"
$wslIp = wsl -d $distro -- bash -lc "hostname -I | awk '{print \$1}'"
$wslIp

$distro 改成你的发行版名称。

6.2 添加 Windows 防火墙规则

仍然在管理员 PowerShell 中执行:

New-NetFirewallRule `
-DisplayName "WSL SSH 22" `
-Direction Inbound `
-Action Allow `
-Protocol TCP `
-LocalPort 22

如果你打算转发到其他端口,把 22 换成你的监听端口。

6.3 配置 portproxy

先清理旧规则,再重新添加:

netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=22
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=$wslIp connectport=22

查看当前规则:

netsh interface portproxy show all

这里的含义是:

  • Windows 在 0.0.0.0:22 上监听
  • 收到连接后,转发到当前的 WSL IP 的 22 端口

6.4 从其他机器连接

先查 Windows 主机在局域网中的 IP:

ipconfig

然后在另一台机器上执行:

ssh <your_user>@<windows_lan_ip>

如果 Windows 监听端口不是 22,别忘了加 -p

7. WSL IP 变了怎么办

这是 portproxy 最常见的坑。WSL 重启、Windows 重启,或者网络环境变化后,WSL IP 都可能改变。

所以一旦你发现:

  • ssh user@localhost 还能连
  • ssh user@<windows_lan_ip> 突然不通

就优先怀疑 portproxy 指向的还是旧的 WSL IP。最直接的处理方式是重新执行上一节的获取 IP 和添加 portproxy 规则。

最小排错顺序

建议按这个顺序排,而不是一开始就改防火墙:

  1. 在 WSL 中执行 sudo service ssh statussudo systemctl status ssh
  2. 在 WSL 中执行 ss -lntp | grep :22
  3. 在 Windows 上执行 ssh <your_user>@localhost
  4. 在 Windows 上执行 Test-NetConnection -ComputerName localhost -Port 22
  5. 查看 netsh interface portproxy show all
  6. 再去检查 Windows 防火墙和局域网 IP

常见问题

1. 为什么不建议默认开启 root 登录

WSL 虽然常被当作本地开发环境,但只要你开放了局域网访问,它就已经变成了一个真正暴露在网络上的 SSH 服务。默认普通用户加 sudo 的习惯会稳妥很多。

2. service ssh start 成功了,但重开 WSL 后又没了

这通常不是 SSH 坏了,而是 WSL 实例退出后服务没有持续运行。要么接受“用的时候手动启动”,要么改成启用 systemd。

3. 为什么 chmod 600 /etc/ssh/sshd_config 不是排错重点

很多教程会让你上来就改这个权限,但真正更常见的问题其实是:

  • 服务没启动
  • authorized_keys 权限不对
  • portproxy 指向了旧 IP
  • Windows 防火墙没放行

关联阅读