很多开发者都遇到过这样的场景:家里台式机性能强劲,但工作时又离不开笔记本。两台机器之间同步代码和数据成了大问题,用U盘拷来拷去太原始,云存储又担心隐私和速度。这时候如果能把台式机的WSL2变成SSH服务器,就能用熟悉的命令行工具实现无缝文件同步和远程开发。
WSL2的IP地址动态分配机制是个大坑。每次重启系统或WSL实例,分配的IP都会变化。想象一下你正用笔记本SSH连接台式机的WSL写代码,突然台式机重启了,之前的连接直接断开,新IP又得重新查,端口转发命令也得重跑,这种体验简直让人抓狂。
我在实际项目中测试过,WSL2默认的NAT网络模式下,IP变动频率高得惊人。有次连续重启三次WSL,拿到了三个不同的IP:172.28.1.2、172.28.3.11、172.28.5.7。这种不稳定性对需要持久化连接的开发环境简直是灾难。
在WSL2中执行以下命令彻底重装SSH服务:
bash复制sudo apt purge openssh-server
sudo apt install openssh-server
这里用purge而不是remove是为了彻底清除旧配置,避免残留文件干扰。安装完成后,关键的配置文件在/etc/ssh/sshd_config,需要修改几个核心参数:
bash复制sudo vim /etc/ssh/sshd_config
找到并修改以下配置项:
code复制Port 22
ListenAddress 0.0.0.0
PermitRootLogin yes
PasswordAuthentication yes
特别提醒PermitRootLogin这个参数,如果担心安全问题可以设为prohibit-password,配合密钥登录更安全。但为了方便演示,我这里先用密码登录。改完后别忘记重启服务:
bash复制sudo service ssh restart
WSL2的网络架构比较特殊,它相当于运行在Hyper-V虚拟机里。Windows主机通过虚拟交换机与WSL通信,所以需要做端口转发才能从局域网访问。在Windows管理员权限的CMD中执行:
bash复制netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=172.28.1.2 connectport=22
这里的172.28.1.2需要替换成你WSL2的实际IP,可以通过ifconfig eth0查看。这个命令的作用是把所有发往Windows主机22端口的请求,都转发到WSL2的22端口。
注意:Windows防火墙需要放行22端口,可以在高级安全Windows Defender防火墙中新建入站规则,允许TCP端口22的连接。
WSL2每次启动都会重新分配IP,我们可以用脚本自动把这个IP写入Windows的hosts文件。在WSL2的/etc/profile末尾添加:
bash复制ipaddr=$(ifconfig eth0 | grep -oP 'inet \K[\d.]+')
sudo sed -i '/wslhost/d' /mnt/c/Windows/System32/drivers/etc/hosts
echo "$ipaddr wslhost" | sudo tee -a /mnt/c/Windows/System32/drivers/etc/hosts > /dev/null
这个脚本做了三件事:
但直接修改系统hosts文件需要管理员权限,建议先给WSL2对Windows系统目录的写权限:
C:\Windows\System32\drivers\etc文件夹要实现真正的无人值守,需要三个自动化步骤:
在Windows的启动目录(Win+R输入shell:startup)创建wsl_ssh.vbs文件:
vbs复制Set ws = CreateObject("Wscript.Shell")
ws.run "wsl -d Ubuntu-20.04 -u root /etc/init.d/ssh start", 0
WScript.Sleep 5000
ws.run "cmd /c netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=wslhost connectport=22", 0
这个VBS脚本的关键点:
Wscript.Shell的run方法启动进程wslhost域名代替IP上面的VBS脚本在运行时可能弹出UAC确认窗口,这显然不符合"全自动"的要求。彻底解决需要修改组策略:
gpedit.msc打开组策略编辑器或者更安全的方法是创建计划任务:
powershell复制$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "/c netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=wslhost connectport=22"
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -Hidden -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "WSL2_SSH_PortForward" -Action $action -Trigger $trigger -Settings $settings -RunLevel Highest
当需要从多个设备连接时,建议在WSL2中做这些优化:
bash复制sudo vim /etc/ssh/sshd_config
修改以下参数:
code复制MaxSessions 10
MaxStartups 30:60:120
ClientAliveInterval 60
TCPKeepAlive yes
这些配置可以:
遇到连接问题时,可以按这个流程排查:
sudo service ssh status确认服务运行状态netstat -ano | findstr :22查看端口监听情况ssh root@localhostnetsh advfirewall firewall show rule name=allnetsh interface portproxy show all如果出现"Connection refused",通常是SSH服务没启动;如果是"Connection timed out",可能是防火墙阻挡。有个实用技巧是在WSL2中运行tail -f /var/log/auth.log,可以实时查看SSH登录日志。
我在实际部署时遇到过端口被占用的问题,解决方法是在WSL2中修改sshd_config的端口为2222,然后相应调整端口转发命令。Windows的Hyper-V有时也会占用22端口,这种情况建议用net stop sshd停止Windows自带的OpenSSH服务。