说实话,Windows里跑Linux,我以前一直是默认Ubuntu的。直到有一阵子被WSL里那些用不上的常驻进程和堆叠的服务搞得有点烦,才开始琢磨换一个更轻的发行版。折腾了一圈下来,最终留在WSL里的反而是Alpine——一个最小rootfs只有几MB、跑起来几乎不吃内存的发行版。这篇帖子就是把Alpine在WSL下配置成SSH门户的完整过程记下来,包括我踩过的坑和改过的配置,也希望能帮到那些想在Windows上拥有一个轻量Linux入口的朋友。
这里说的“SSH门户”,本质上就是把WSL里的Alpine当作一个常驻的SSH服务端:从Windows终端、局域网其他机器,甚至配合端口转发从外网,都能通过SSH进入这个轻量环境,加载密钥后免密登录,日常拿来跑脚本、做跳板、调试网络、连被管理的服务器都很顺手。如果你正好需要这样一个“随时能进的Linux小站”,或者对WSL里跑非Ubuntu发行版感兴趣,这篇内容应该能省你不少弯路。
1. 为什么选Alpine当WSL的SSH门户
1.1 Alpine这个发行版到底强在哪
先说结论:Alpine最适合的场景就是“小、快、干净”的专用环境。它在WSL里的优势非常直接。
第一是体量。Alpine的基础rootfs大约只有3到5MB,完整装完OpenSSH、常用工具之后,整个WSL发行版经常不到100MB。对比Ubuntu动辄几个GB的WSL实例,Alpine在磁盘占用上的优势是碾压级的。你甚至可以在同一个Windows系统里装好几个不同用途的Alpine环境,相互隔离,互不干扰。
第二是资源占用。Alpine默认没有systemd,没有一堆“顺便启动”的守护进程。空闲状态下内存占用经常只有几十MB,CPU占用几乎为零。我拿它当SSH门户跑了一周,Windows任务管理器里几乎看不到它的存在。对一个要常驻后台的服务入口来说,这种轻量程度非常舒服。
第三是安全和稳定。Alpine使用musl libc,静态链接的软件多,攻击面相对小。加上没有systemd那套复杂的启动依赖,出问题时排查链路短,配置起来心智负担低。对“门户”这种对外暴露的服务来说,越精简的系统,越不容易出幺蛾子。
1.2 “门户”这个定位,为什么推荐放WSL里
很多人把WSL只当成“在Windows里跑Linux命令”的工具,但WSL其实很适合承载一个网络服务入口,也就是所谓的“门户”。
一方面,WSL和Windows共享网络,可以直接利用Windows的防火墙、端口转发和已有的网络环境。另一方面,WSL环境本身可以随时快照、导出、迁移,万一搞坏了,一条命令就能恢复。比起开一台虚拟机或者用独立服务器,用WSL做SSH门户的成本几乎可以忽略。
把这个门户选在Alpine上,还有一层意思:你不需要在这个环境里安装一堆开发工具和依赖,它只负责“接客”——接受SSH连接、转发请求、跑些轻量脚本。真要干重活,从门户再跳去其他机器或者启动另一个WSL发行版都行。门户机保持精简,本身就是一种安全策略。
1.3 WSL2网络模式怎么选:NAT和镜像模式对比
WSL2默认是NAT网络模式,虚拟机有自己的内部IP,Windows通过虚拟网卡转发访问。外部设备想要直接访问WSL里的服务,需要额外的端口转发配置,否则只能从Windows本机访问。
Windows 11 22H2之后,WSL支持了镜像网络模式。启用后WSL会直接共享Windows的IP地址,Alpine里监听的端口就等同于Windows上监听的端口,局域网里的其他机器可以直接访问。
我用表格对比一下这两种模式对SSH门户的影响:
| 对比项 | NAT模式 | 镜像模式 |
|---|---|---|
| WSL是否有独立IP | 有,每次启动可能变化 | 无,与Windows共用IP |
| 从Windows本机SSH | 直接连接localhost即可 | 直接连接localhost即可 |
| 从局域网其他设备访问 | 需要portproxy端口转发 | 直接访问Windows IP即可 |
| 从外网访问 | 需要路由器端口映射+Windows转发 | 需要路由器端口映射 |
| 配置复杂度 | 较高,IP会变,规则不好维护 | 低,一次配置长期有效 |
| 依赖条件 | Windows 10 21H2+/WSL2 | Windows 11 22H2+,较新WSL版本 |
我个人强烈建议,如果你的Windows版本支持,直接上镜像模式。它把“门户”这件事简化成了“Alpine里起SSH服务,局域网马上就能连”,非常顺滑。后面配置我会以镜像模式为主,同时也会给出NAT模式下的端口转发方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 安装Alpine WSL环境前的准备
2.1 Windows侧开启WSL并确认版本
如果你之前从没装过WSL,先以管理员身份打开PowerShell或Windows Terminal,执行:
bash复制wsl --install
这条命令会启用WSL功能并安装默认的Ubuntu发行版。如果不想装Ubuntu,可以加参数:
bash复制wsl --install --no-distribution
只装WSL运行环境,不装任何Linux发行版。之后想装什么发行版再自己导入。
装好之后建议确认一下WSL版本和内核版本:
bash复制wsl --version
如果输出提示WSL版本太旧,执行:
bash复制wsl --update
这里说句题外话,很多人一开始wsl --install卡在“正在下载”很久不动,大多是网络波动或者默认下载源慢。可以换一个网络再试,或者手动下载最新WSL安装包安装。WSL本身是一个MSI安装包,下载后双击即可,不依赖应用商店。
2.2 下载Alpine rootfs并导入WSL
WSL导入自定义发行版的原理很简单:官方不提供Alpine的WSL一键安装包,但你可以直接下载Alpine的最小rootfs压缩包,然后交给WSL导入。
去Alpine官网下载minirootfs包,选择对应架构的版本,x86_64机器就用x86_64。下载地址一般在Alpine的官方下载页面,文件名类似:
text复制alpine-minirootfs-3.20.2-x86_64.tar.gz
下载完成后,在Windows上执行导入命令:
bash复制wsl --import Alpine D:\WSL\Alpine D:\Downloads\alpine-minirootfs-3.20.2-x86_64.tar.gz
参数含义:
- Alpine:发行版名称,后面用wsl -d Alpine进入
- D:\WSL\Alpine:安装目录,可以把整个发行版放到大容量或固态盘上
- 后面跟的是rootfs压缩包路径
导入完成后,直接进入:
bash复制wsl -d Alpine
默认你会以root用户进入,这是因为rootfs默认没有配置普通用户。看到类似/ #的提示符就说明成功了。
提示:WSL导入的发行版默认没有启动菜单,所有交互都要通过wsl -d Alpine完成。首次进入后不要急着装东西,先把软件源和基础环境配好。
2.3 Alpine首次进入后的基础配置
进入Alpine后,先更新软件源索引:
bash复制apk update
Alpine的包管理命令是apk,比较简洁。如果觉得官方源慢,可以修改/etc/apk/repositories,把官方域名替换为国内镜像源地址。替换完成后再次apk update即可。
接着装几个顺手的基础工具:
bash复制apk add bash sudo curl wget openssh-server openssh-client
bash不是必需的,但很多人用不惯Alpine默认的ash,装上更顺手。sudo则是后面给普通用户授权用的。
再配置hostname和时区:
bash复制setup-hostname alpine-portal
echo "alpine-portal" > /etc/hostname
setup-timezone -z Asia/Shanghai
setup-timezone是Alpine的配置命令,会写入/etc/timezone并链接/usr/share/zoneinfo目录下的时区文件。
接下来创建普通用户。SSH门户不建议整天用root直接登录,风险太大。创建用户并加到wheel组:
bash复制adduser -s /bin/ash -G wheel portal
passwd portal
Alpine的adduser和Debian系有点区别,-s指定shell,-G指定附加组。wheel组在Alpine里默认配置了sudo权限,只要在已安装sudo的情况下给wheel组放开sudo权限就行。
编辑/etc/sudoers:
bash复制visudo
找到下面这行并取消注释:
text复制%wheel ALL=(ALL:ALL) ALL
保存退出后,用这个普通用户测试一下sudo是否正常:
bash复制su - portal
sudo whoami
输出root就说明sudo权限没问题。
2.4 配置WSL层面的默认用户和启动行为
新导入的Alpine默认用root登录,如果想一进WSL就是普通用户,可以在Alpine内部创建/etc/wsl.conf文件:
ini复制[user]
default=portal
这样每次wsl -d Alpine都会自动以portal用户进入,不需要手动su。
如果希望WSL启动时自动把SSH服务拉起来,WSL较新版本支持在wsl.conf里配置启动命令。在同一个文件中追加:
ini复制[boot]
command = "rc-service sshd start"
这个配置的意思是,WSL实例每次启动时,运行指定的命令来启动sshd服务。有了它,Windows开机后只要WSL被启动,SSH服务就会自动运行,省去手动启动的麻烦。
注意:wsl.conf的[boot]段落需要WSL版本相对较新才支持。配置完成后执行wsl --shutdown重启WSL,再wsl -d Alpine进入,查看sshd进程是否跑起来了。
3. SSH服务配置与密钥认证实操
3.1 安装并启动OpenSSH服务端
Alpine的OpenSSH服务端由openssh-server包提供,前面已经装过了。如果还没装,执行:
bash复制apk add openssh-server
Alpine不像Ubuntu那样有systemd,它的服务管理默认走OpenRC。启动sshd:
bash复制rc-service sshd start
也可以直接手动启动以便调试:
bash复制/usr/sbin/sshd
手动启动时如果失败,错误会直接打在终端上,排查起来比rc-service转一手更直接。
但我更推荐还是走rc-service,因为Alpine会生成对应的进程守护脚本,后面配置开机自启或查询状态都方便:
bash复制rc-service sshd status
如果配置了wsl.conf里的[boot] command,wsl --shutdown之后重新进入,sshd应该已经自动运行。
3.2 sshd_config里我最关心的几个参数
OpenSSH的配置文件在/etc/ssh/sshd_config。改之前先备份一下:
bash复制cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
然后编辑。下面这几个参数是“门户”场景必须关注的:
text复制# 端口:不建议用默认22,容易被扫描
Port 2222
# 监听地址:0.0.0.0代表所有网卡,如果只想本机访问就改成127.0.0.1
ListenAddress 0.0.0.0
# root登录策略:
# prohibit-password:允许root用密钥登录,禁止用密码登录
# no:完全禁止root登录
# yes:允许密码登录,不推荐
PermitRootLogin prohibit-password
# 公钥认证必须开启
PubkeyAuthentication yes
# 密码认证:用了密钥之后可以关掉,增强安全性
PasswordAuthentication no
# 允许登录的用户组:只让wheel组成员SSH进来
AllowGroups wheel
# 会话保持:60秒发一次心跳,最多3次没响应就断开
ClientAliveInterval 60
ClientAliveCountMax 3
# 禁止X11转发,门户机用不到,关掉减少暴露面
X11Forwarding no
# 最大尝试次数,防爆破
MaxAuthTries 3
AllowGroups这个参数正是前面提到的“只有wheel组成员能SSH登录”的实现方法。如果哪天想临时放开root密码登录,可以改成PermitRootLogin yes,但墙裂不建议在公网环境这么做。
改完配置先校验语法:
bash复制sshd -t
没有任何输出就是没问题。然后重启服务:
bash复制rc-service sshd restart
验证监听状态:
bash复制ss -tlnp | grep 2222
看到LISTEN状态的sshd监听在0.0.0.0:2222,服务就算起来了。
3.3 生成SSH密钥,完成免密登录
接下来配置密钥登录。密钥对生成在客户端机器上,也就是你平时用来连接SSH的那台电脑,比如Windows本机。
在Windows的PowerShell或CMD中执行:
bash复制ssh-keygen -t ed25519 -C "alpine-portal" -f C:\Users\你的用户名\.ssh\alpine_portal
这里我推荐ed25519算法,密钥短、安全强度够、生成速度快。如果环境不支持ed25519,用rsa也可以,命令换成ssh-keygen -t rsa -b 4096。
生成后会有两个文件:
- alpine_portal:私钥,留在自己电脑上
- alpine_portal.pub:公钥,要放到Alpine的~/.ssh/authorized_keys里
Windows的OpenSSH客户端没有内置ssh-copy-id,可以手动复制。先把公钥内容读出来:
bash复制type C:\Users\你的用户名\.ssh\alpine_portal.pub
复制输出的一整行公钥。然后登录Alpine(此时密码登录还是开着的),以portal用户身份执行:
bash复制mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "粘贴你的公钥内容" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
这里有两个关键权限:~/.ssh目录必须是700,authorized_keys文件必须是600。权限过宽OpenSSH会直接拒绝使用该公钥。
配置完成后再从Windows测试:
bash复制ssh -p 2222 -i C:\Users\你的用户名\.ssh\alpine_portal portal@localhost
如果能够直接进入Alpine而不需要输入密码,说明密钥认证已经生效。确认无误后,再回头把sshd_config里的PasswordAuthentication改成no,重启sshd。
提示:改密码认证前一定要先确认密钥能登录,否则一旦关掉密码认证又发现密钥有问题,你只能通过wsl -d Alpine进入系统去改回配置。
3.4 通过SSH config统一管理连接参数
端口、用户名、密钥路径每次敲全是很烦的。Windows的OpenSSH支持~/.ssh/config配置文件,帮你把参数固化下来。
编辑C:\Users\你的用户名.ssh\config,追加:
text复制Host alpine
HostName localhost
Port 2222
User portal
IdentityFile C:\Users\你的用户名\.ssh\alpine_portal
ServerAliveInterval 60
保存后,只需要一条命令:
bash复制ssh alpine
就等效于之前那一大串参数。ServerAliveInterval让客户端每60秒发一个心跳包,防止长时间无操作时连接被中间设备断开。
这个config文件还能顺手管理你经常连接的其他机器。比如你还有一台远程开发机,配置几个块,就能实现“一条命令切一个环境”,日常使用非常舒服。
3.5 局域网访问:镜像模式和端口转发两种方案
如果只是Windows本机用,上面配置已经够了。但既然是“门户”,自然希望局域网里其他设备也能访问。
先看镜像模式。在Windows用户目录下找到或创建.wslconfig文件(路径是C:\Users\你的用户名.wslconfig),编辑:
ini复制[wsl2]
networkingMode=mirrored
然后在Windows管理员PowerShell里执行:
bash复制wsl --shutdown
重启WSL后再进入Alpine,运行ip addr确认网卡IP变成Windows局域网IP。这时在Alpine里任意ip addr出现的地址,应该是和Windows一致的局域网地址。从办公室另一台电脑上执行:
bash复制ssh -p 2222 portal@你的Windows局域网IP
就能连进这个门户了。
如果你的Windows版本不支持镜像模式,只能走NAT加端口转发。先用wsl -d Alpine进入系统,查看WSL的IP:
bash复制hostname -I
假设输出172.20.10.5,那么在Windows管理员PowerShell里执行端口转发规则:
bash复制netsh interface portproxy add v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=2222 connectaddress=172.20.10.5
这一步把Windows的2222端口流量全部转发给WSL内部IP的2222端口。接着放行Windows防火墙:
bash复制netsh advfirewall firewall add rule name="WSL SSH Portal" dir=in action=allow protocol=TCP localport=2222
之后局域网机器同样可以访问Windows IP的2222端口进入Alpine。
注意:NAT模式下WSL内部IP每一次重启都可能变,如果发现突然连不上了,先重新查看hostname -I,再用netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=2222删掉旧规则,按新IP重新添加。
4. 常见问题与排查技巧实录
4.1 sshd起不来?先分清是哪一层的问题
我调试SSH服务时最常用的排查顺序是“进程→端口→配置→日志”。在Alpine里依次执行:
bash复制ps aux | grep sshd
ss -tlnp | grep 2222
sshd -t
tail -f /var/log/messages
sshd -t专门检查配置语法,如果有参数拼错、路径不对,它会直接报出来。如果配置没问题但进程就是起不来,看/var/log/messages。Alpine没有journald,所有系统日志都打到这个文件里。
常见原因之一:系统里没有host key。首次启动sshd时它会自动生成,但如果rootfs被裁剪过或者手动清理过,可能导致没有host key。解决办法:
bash复制ssh-keygen -A
-A参数会为所有支持的算法生成缺失的host key。生成完再启动服务。
另一个常见原因是端口被占用。Alpine里可能跑着别的进程占用了2222,用ss -tlnp看一下监听关系,换一个高位端口即可。
4.2 密钥不生效,十个有九个是权限问题
密钥认证失败时,客户端会提示Permission denied (publickey)。出现这个先别急着怀疑公钥没写对,按顺序检查:
bash复制ls -ld ~/.ssh
ls -l ~/.ssh/authorized_keys
标准结果应该是:
text复制drwx------ 2 portal portal 4096 ... .ssh
-rw------- 1 portal portal ... authorized_keys
注意:~/.ssh不能是755或777,authorized_keys不能是644。OpenSSH为了保证安全会拒绝权限过宽的文件。
还要检查authorized_keys文件所属用户。如果文件属于root,普通用户登录时同样会拒绝。遇到这种情况:
bash复制chown -R portal:portal ~/.ssh
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
此外,别把公钥追加到root的authorized_keys里却用portal用户登录。这个低级错误我见过太多次了。
4.3 端口不通?按“本机→局域网→防火墙”顺序排查
从Windows本机连接Alpine失败,和从局域网连接失败,原因大概率不一样。
本机连接失败,先确认Alpine里的sshd监听在0.0.0.0还是127.0.0.1。如果sshd_config只写了ListenAddress 127.0.0.1,Windows本机虽然能连,但局域网全部无法访问。门户场景要改成0.0.0.0。
局域网连接失败,重点检查Windows防火墙和端口转发。NAT模式下,即使portproxy配好了,Windows防火墙没有放行端口一样连不进来。镜像模式下,则要确认Alpine里的服务监听确实是所有接口。用命令行确认端口转发规则:
bash复制netsh interface portproxy show all
输出了正确的新旧IP映射,问题大概率在防火墙,重新添加入站规则即可。
如果连外网也想访问,那还要在路由器上再映射一次端口,把外网端口的流量转发到Windows的局域网IP上。这个属于家里或公司网络设备配置,具体入口可以在路由器管理界面找“端口映射”或“虚拟服务器”,把外部端口2222映射到内网主机IP。
4.4 我这个配置做了哪些安全加固
门户机是对外暴露的,安全上我做了几层基础防护:
第一,不开放默认22端口。扫描脚本默认扫22,换了2222至少能挡住一大波无差别攻击。想更隐蔽可以换到五位数的随机端口,但别太难记。
第二,完全禁止密码登录,只保留ed25519密钥。没有密码这道脆弱环节,爆破就无从谈起。前提是私钥一定要保管好,可以给私钥再加一个口令,即使被拷走也无法直接使用。
第三,用AllowGroups限制登录用户组。就算系统里还有其他普通用户,不在wheel组里就进不来。这个在多人共用一台Windows机器时特别有用。
第四,定期查看/var/log/messages。Alpine把SSH登录日志都记录在这里,grep sshd过滤出来看看有没有异常的登录尝试。
bash复制grep sshd /var/log/messages
看到大量Failed password记录,就要考虑更换端口或者增加Fail2ban之类的防护手段。
4.5 把VS Code Remote-SSH也用起来
既然门户已经通了,顺手把VS Code的Remote-SSH接到这里,就是一个非常顺手的远程开发环境。
VS Code装好Remote-SSH插件后,在Remote-SSH设置里添加上面写的Host alpine,连接时选择这个配置,VS Code就会通过SSH打开远程环境。在这个轻量Alpine里编写脚本、查看日志、调试配置,都很流畅,因为Alpine本身资源占用极小,VS Code远程服务跑在上面不会有明显的卡顿感。
如果你平时还要连GitLab、GitHub之类,把同一把公钥加到对应网站的后台里,Windows本机就能实现“一把私钥走天下”:SSH进门户、推送代码、管理服务器,全都用同一个密钥,非常省心。
最后说两句
我在实际使用中最大的感受是,Alpine做WSL里的SSH门户,不是一个“花活”,而是真的把Windows和Linux之间的关系理顺了:Windows负责日常办公和图形化工具,Alpine负责当一个安静的连接入口和轻量执行环境,两边互不干扰。配置完密钥和SSH config之后,我几乎感觉不到“门户”的存在,它就在那里,随时能进,从不惹事。
如果你也打算照这个思路折腾,记得先把密钥认证调通再关密码登录,改完配置一定执行一次sshd -t,wsl.conf改了之后用wsl --shutdown彻底重启一次WSL。遇到问题就按“进程→端口→配置→日志”的顺序一层层查,大部分坑都能自己走出来。希望这篇记录能帮你少走几步弯路,早点拥有自己的轻量SSH门户。
