WSL 中的 SSH 与远程访问
如果你只是想在 Windows 本机里打开一个 WSL 终端,其实不需要 SSH。但当你想做下面这些事情时,SSH 就会很有用:
- 从 Windows Terminal、VS Code、其他终端工具统一连接到 WSL
- 从局域网另一台机器登录到你的 WSL 环境
- 在 WSL 中长期运行开发服务,希望配合 SSH 做转发或远程开发
这篇文档把整个链路拆成两层:
- 先让 WSL 内部的 SSH 服务 正常工作
- 再决定是只给 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。更稳妥的做法是:
- 在 Windows 上开放一个监听端口
- 把这个端口转发到当前 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 规则。
最小排错顺序
建议按这个顺序排,而不是一开始就改防火墙:
- 在 WSL 中执行
sudo service ssh status或sudo systemctl status ssh - 在 WSL 中执行
ss -lntp | grep :22 - 在 Windows 上执行
ssh <your_user>@localhost - 在 Windows 上执行
Test-NetConnection -ComputerName localhost -Port 22 - 查看
netsh interface portproxy show all - 再去检查 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 防火墙没放行