跳到主要内容

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 status 或 sudo 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 防火墙没放行

关联阅读​