这篇记录用 Mac 通过 SSH 直连 Windows 上的 WSL2,在原生 Linux 环境里调 GPU 进行 CUDA 开发的完整配置过程。
方案的核心思路:在 WSL2 内部装 sshd,配合 mirrored 网络模式,让 WSL 直接共享 Windows 的网络栈。Mac 连 <windows-ip>:22 就是在连 WSL 里的 Linux,不需要经过 Windows OpenSSH,不需要 .bat 跳板脚本,不需要端口转发。SSH 和 SFTP 走的都是同一个原生 Linux sshd,PyCharm、VS Code Remote-SSH 直接就能用。
NOTE前提条件
- Windows 11
- NVIDIA GPU + 已装 GeForce / Studio 驱动(2020 年后的版本均支持 WSL2 CUDA 直通)
- Windows 已启用虚拟化(BIOS 中 VT-x / AMD-V + Hyper-V)
- Mac 与 Windows 在同一局域网(校园网、家庭网都行)
- Mac 已生成 SSH 密钥(没有的话:
ssh-keygen -t ed25519)
1. 安装 WSL2 + Ubuntu
PowerShell(管理员):
wsl --install -d Ubuntu-24.04装完重启 Windows,首次进入 WSL 设置 Linux 用户名和密码。
确认版本:
wsl -l -vVERSION 列应该是 2。如果是 1:
wsl --set-version Ubuntu-24.04 2TIP推荐 Ubuntu 24.04 而不是 20.04——20.04 已经接近 EOL,而且 24.04 对 systemd 的支持更好,后面配 sshd 自启更省事。
2. 启用 mirrored 网络模式
这是整个方案的关键。默认情况下 WSL2 用 NAT 网络,有自己的虚拟 IP,外部访问需要端口转发。mirrored 模式让 WSL 直接共享 Windows 的网络栈,WSL 里 0.0.0.0:22 监听的端口,从局域网 <windows-ip>:22 就能直接访问。
在 Windows 上创建或编辑 C:\Users\<用户>\.wslconfig:
[wsl2]networkingMode=mirrored然后在 PowerShell 中重启 WSL:
wsl --shutdown再次进入 WSL,验证网络模式:
hostname -IWARNINGmirrored 模式下,
hostname -I显示的 IP 和 Windows 的局域网 IP 相同——这是正常的,说明网络栈已经共享。不需要做任何端口转发。如果启用 mirrored 后遇到
0x8007054f之类的错误,说明 WSL 版本太旧不支持。可以用wsl --update升级,或者回退到 NAT +netsh portproxy方案(见文末附录)。
3. 修复 DNS
部分 WSL 安装后 /etc/resolv.conf 缺失或 DNS 不可用,网都连不上,后面什么都装不了。先修这个。
关闭 WSL 自动生成 resolv.conf:
sudo bash -c 'cat > /etc/wsl.conf <<EOF[network]generateResolvConf = falseEOF'手动写入 DNS:
sudo bash -c 'cat > /etc/resolv.conf <<EOFnameserver 223.5.5.5nameserver 119.29.29.29EOF'验证:
ping -c 2 223.5.5.5ping -c 2 mirrors.tuna.tsinghua.edu.cn两个都通就 OK。不通的话在 PowerShell 里 wsl --shutdown 再重新进。
4. 换清华源
国内用户建议换源,后面装包快很多。
sudo cp /etc/apt/sources.list /etc/apt/sources.list.baksudo sed -i 's|http://archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g; s|http://security.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.listsudo apt update5. 在 WSL 内安装 sshd
这里直接在 WSL 的 Linux 里装 openssh-server,而不是用 Windows 的 OpenSSH。这样 SSH 和 SFTP 走的都是同一个原生 Linux sshd,IDE 的远程开发功能才能正常工作。
sudo apt install -y openssh-server写一份自定义配置:
sudo bash -c 'cat > /etc/ssh/sshd_config.d/custom.conf <<EOFPort 22PasswordAuthentication noPubkeyAuthentication yesEOF'6. 配置密钥认证
Mac 上查看公钥:
cat ~/.ssh/id_ed25519.pub在 WSL 里把公钥加到 authorized_keys:
mkdir -p ~/.sshchmod 700 ~/.ssh# 把 Mac 上的公钥内容粘贴进去vim ~/.ssh/authorized_keyschmod 600 ~/.ssh/authorized_keys权限必须严格:~/.ssh 是 700,authorized_keys 是 600。sshd 对权限很挑剔,多一个 bit 都会拒绝认证,而且不给明显报错。
7. 启动 sshd 并验证
sudo service ssh startsudo ss -tlnp | grep :22应该看到 sshd 在 0.0.0.0:22 监听。
8. 禁用 Windows OpenSSH
WSL 的 sshd 已经占了 22 端口,Windows 自带的 OpenSSH Server 如果也在跑会冲突。而且我们不需要它了——直接关掉。
PowerShell(管理员):
Stop-Service sshd -ErrorAction SilentlyContinueSet-Service -Name sshd -StartupType Disabled -ErrorAction SilentlyContinueWARNING千万不要在 mirrored 模式下用
netsh portproxy把 22 端口转发到 Windows 自己的 IP。这会造成自环——端口 22 的流量转发到自己的端口 22,系统会在几秒内产生数千个 ESTABLISHED 连接,直到资源耗尽,只能重启才能恢复。
9. 配置 Windows 防火墙
让局域网能访问 WSL 的 22 端口。
PowerShell(管理员):
New-NetFirewallRule -Name sshd-public-lan ` -DisplayName 'SSH (LAN only)' ` -Enabled True -Direction Inbound -Protocol TCP -Action Allow ` -LocalPort 22 -Profile Public ` -RemoteAddress 10.0.0.0/8-RemoteAddress 不可省略,否则等于对整个 Public 网络开放 22 端口——在校园网上这约等于裸奔。网段替换为实际值。
验证:
Get-NetFirewallRule -Name sshd-public-lan | Get-NetFirewallAddressFilterRemoteAddress 应该显示你设定的网段,不能是 Any。
10. 设置 sshd 开机自启
WSL 默认没有 systemd(Ubuntu 24.04 可以手动开启),sshd 不会随 Windows 开机自动启动。用 Windows 计划任务解决:
PowerShell(管理员):
$action = New-ScheduledTaskAction -Execute "wsl.exe" ` -Argument "-d Ubuntu-24.04 -u root -- service ssh start"$trigger = New-ScheduledTaskTrigger -AtLogOn$principal = New-ScheduledTaskPrincipal -UserId "$env:USERNAME" -RunLevel HighestRegister-ScheduledTask -TaskName "Start WSL SSHD" ` -Action $action -Trigger $trigger -Principal $principal -Force这样每次 Windows 登录后,WSL 的 sshd 就会自动拉起。
TIP如果你用的是 Ubuntu 24.04,可以在
/etc/wsl.conf里加[boot]+systemd=true,然后sudo systemctl enable ssh就行,不需要计划任务。但这个选项在 20.04 上不可用。
11. Mac 端 SSH 配置
编辑 ~/.ssh/config:
Host gpu HostName <windows-ip> Port 22 User <wsl-user> IdentityFile ~/.ssh/id_ed25519 UseKeychain yes AddKeysToAgent yes ServerAliveInterval 60 ServerAliveCountMax 10之后 ssh gpu 一条命令就能连进 WSL。
12. 验证 SSH 和 SFTP
SSH 能通不等于 IDE 能用。一定要同时验证 SFTP,否则 PyCharm 和 VS Code 的远程文件同步会挂。
# 验证 SSHssh gpu "pwd && hostname && uname -a"# 期望:/home/<user>、WSL 主机名、Linux ... GNU/Linux
# 验证 SFTPsftp gpusftp> pwd# 期望:Remote working directory: /home/<user># 如果显示的是 C:\Users\... 说明连到了 Windows OpenSSH,检查是不是没禁用两个都返回 Linux 路径就 OK。VS Code Remote-SSH 和 PyCharm Professional 的远程开发功能可以直接用 gpu 这个 Host 名。
13. 验证 CUDA + PyTorch
GPU 直通是 WSL2 自带的,不需要在 WSL 内装 NVIDIA 驱动。先确认直通正常:
nvidia-smi看到 GPU 信息就行。然后装 uv 管理 Python 环境:
curl -LsSf https://astral.sh/uv/install.sh | shexport PATH="$HOME/.local/bin:$PATH"创建一个测试项目验证 PyTorch CUDA:
mkdir ~/projects/test-cuda && cd ~/projects/test-cudauv venv --python 3.12source .venv/bin/activateuv pip install torch --index-url https://download.pytorch.org/whl/cu121python -c "import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))"期望输出:
2.x.x+cu121TrueNVIDIA GeForce RTX xxxx输出 True 就 OK。
14. Shell 美化(可选)
如果习惯 zsh:
sudo apt install -y zshsh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestionsgit clone https://github.com/zsh-users/zsh-syntax-highlighting ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting编辑 ~/.zshrc,把 plugins=(git) 改成 plugins=(git zsh-autosuggestions zsh-syntax-highlighting),source ~/.zshrc 生效。
避坑要点
- mirrored 模式下
hostname -I等于 Windows IP——这不是 bug,是 feature。说明网络栈已共享,不需要端口转发。 - 不要用
netsh portproxy转发到 Windows 自身 IP。mirrored 模式下这会造成 22→22 自环,系统在几秒内产生数千个连接,只能重启恢复。 - 验证 SFTP,不只是 SSH。
ssh gpu "pwd"能通不代表 IDE 能用——一定要测sftp gpu看路径是不是 Linux 的/home/...。如果是C:\Users\...,说明连到了 Windows OpenSSH,没禁干净。 - WSL 的 sshd 不会自动启动。Ubuntu 20.04 没有 systemd,必须用 Windows 计划任务拉起。24.04 可以开启 systemd 后用
systemctl enable。 - 防火墙规则必须带
-RemoteAddress。不带等于对整个 Public 网络开放端口。 - 用 ed25519 密钥,不要 RSA。更短、更快、更安全。
- WSL 内不要装 NVIDIA 驱动。CUDA 通过 Windows 驱动直通,WSL 只需要装 PyTorch wheel。需要
nvcc编译的话装 CUDA Toolkit 即可。 - PyTorch 自带 CUDA runtime。
nvidia-smi显示的 CUDA 版本是驱动支持的上限,跟 PyTorch wheel 自带的版本不需要完全一致。 - 项目和数据放
~/,别放/mnt/c/。跨文件系统 I/O 慢 10 倍以上。 - 长时间训练用 tmux。
tmux new -s train→ 开始训练 →Ctrl+B D脱离 → 关掉 SSH 也不影响 →tmux attach -t train重连。
附录:mirrored 模式不可用时的备选方案
如果你的 WSL 版本太旧不支持 mirrored 网络模式,可以用 NAT + netsh portproxy 作为替代:
# 获取 WSL 的 NAT IPwsl -d Ubuntu-24.04 -- hostname -I
# 添加端口转发(WSL IP 每次重启可能变)netsh interface portproxy add v4tov4 listenport=22 listenaddress=0.0.0.0 connectport=22 connectaddress=<wsl-ip>注意 NAT 模式下 WSL 的 IP 每次重启可能变,需要写脚本自动更新 portproxy 规则。这比 mirrored 模式麻烦得多,建议优先升级 WSL 版本。
写在最后
这套方案的本质很简单:WSL2 mirrored 网络让 Linux sshd 直接暴露在局域网上,Mac 连过去就是一个标准的 Linux 远程开发环境,SSH 和 SFTP 都走原生 Linux,IDE 远程开发开箱即用。
之前走 Windows OpenSSH + .bat 跳板的弯路,根源在于没意识到 mirrored 模式能让 WSL 直接上网。绕了一圈发现,最简单的架构往往也是最可靠的。