为什么要给 Linux 服务器配私钥免密登录
每天登一次堡垒机,再 SSH 跳到机房那台 Linux 服务器——密码记不住,记本子上又怕泄露;改成 12 位强密码后,每次输错一次就锁 5 分钟。更糟的是:服务器一旦暴露在公网,SSH 22 端口每天被扫几万次,一晚上能在 /var/log/auth.log 里看到一堆 Failed password 暴力破解记录。
私钥登录把这两件事一起解决:
- 更安全:本地一把私钥,公钥放服务器;攻击者就算猜中你账号,没拿到私钥也进不来。配合
PasswordAuthentication no,直接关掉密码登录通道 - 更省事:
ssh user@host回车就进,再也不用输密码
但还有一个前置问题——服务器在公司机房或家里,没公网 IP,从家里/出差时连不上。本文配合 MoleSDN 把客户端电脑和 Linux 服务器接进同一张虚拟内网,无需公网 IP、无需路由器端口映射,全过程一把私钥连到底。

你需要准备什么
| 项 | 说明 |
|---|---|
| 一台目标 Linux 服务器 | Ubuntu / Debian / CentOS / Rocky 任一发行版均可,确保 openssh-server 已装并启动 |
| 一台运维客户端 | Windows 10/11(自带 OpenSSH)、macOS、或另一台 Linux 都行 |
| 服务器现有的 SSH 账户 | 用户名 + 密码(暂时还要用一次,后面就关掉密码登录) |
| 一个 MoleSDN 账户 | 免费档 3 个客户端够用:1 台服务器 + 1-2 台运维设备 |
💡 关于 root 登录:本文示例用普通用户(如
ops)演示。生产环境建议把PermitRootLogin设为no或prohibit-password,root 永远走普通用户 sudo 上去——这是比换密钥更基本的硬性安全要求。
第一步:在客户端生成 SSH 密钥对
私钥留在你自己的电脑上,公钥才会被传到服务器。在客户端(你日常运维用的那台机器)打开终端:
ssh-keygen -t ed25519 -C "ops@my-laptop"
💡 推荐用
ed25519,比传统rsa更短更安全;老服务器实在不支持时再退回ssh-keygen -t rsa -b 4096。
一路回车(或给私钥设个 passphrase 双重保护),生成两个文件:
~/.ssh/id_ed25519 # 私钥,绝不外传
~/.ssh/id_ed25519.pub # 公钥,可以丢出去
Windows 用户在 PowerShell 里跑同样的命令即可,密钥默认落在 C:\Users\<你>\.ssh\ 下。命令成功后会看到类似下图的输出(截图为 RSA 演示,ed25519 输出结构一致,只是没有那张 ASCII random-art):

第二步:把公钥上传到服务器
最省事的一行命令(先用密码登录一次,仅这一次):
ssh-copy-id ops@192.168.1.100
它会把 ~/.ssh/id_ed25519.pub 追加到服务器上 ~/.ssh/authorized_keys,并自动修正权限。
如果 ssh-copy-id 不可用(比如 Windows 自带 OpenSSH 没带这个工具),手工等价做法:
# 客户端:先把公钥内容拷出来
cat ~/.ssh/id_ed25519.pub
# 服务器:贴到 authorized_keys 末尾
mkdir -p ~/.ssh
echo "<刚才拷出来的整段公钥>" >> ~/.ssh/authorized_keys
# 设好权限(最关键,错了就登不上)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
⚠️ 权限是免密失败最常见原因。
~/.ssh必须 700,authorized_keys必须 600;权限太松,sshd 会直接拒绝读取这个文件,回退要密码。
试一次免密登录验证:
ssh ops@192.168.1.100
不再提示密码 = 公钥配对成功。如果你客户端用了非默认位置的私钥,则要显式指定:ssh -i ~/.ssh/id_ed25519 ops@192.168.1.100,登录效果如下(左半窗口先用默认私钥被拒,右半显式 -i 指定后立刻登录上):

Windows 客户端:私钥是从别处复制来的?先把权限收紧
如果你直接按第一步在本机 PowerShell 跑 ssh-keygen,这一节可以跳过——系统生成时默认权限就只给当前用户读,OpenSSH 不会拒。
但如果你把私钥从别处搬过来(U 盘拷过来、从 Linux 服务器导出、从同事那拿的备份),Windows 资源管理器默认会让多个用户(Authenticated Users、Users 等)可读这个文件——Windows OpenSSH 检测到这种"过松"权限会直接拒绝读私钥,登录回退到要密码或干脆失败。下面把 id_rsa 的 ACL 收紧到只剩当前用户。
打开资源管理器找到你打算放私钥的位置(推荐 C:\Users\<你>\.ssh\ 或独立目录如 E:\ssh\),新建一个没有扩展名的文件 id_rsa——系统会弹「如果改变文件扩展名,可能会导致文件不可用」,选「是」:

用记事本打开 id_rsa,粘贴从源头拷出来的整段私钥(包含 -----BEGIN ... PRIVATE KEY----- 和 -----END ... PRIVATE KEY----- 两行),保存关闭:

接下来修权限。右键 id_rsa → 属性 → 切换到「安全」选项卡,看到一堆继承下来的用户(Authenticated Users、SYSTEM、Administrators、Users)都有访问权——这就是 OpenSSH 拒绝的原因。点右下角「高级」:

「高级安全设置」窗口里,左下角点「禁用继承」:

弹出「阻止继承」对话框——选「将已继承的权限转换为此对象的显式权限」(不要选直接删除,否则没东西可以编辑):

现在所有权限条目变成"显式"。逐个选中、点删除,把 4 个用户全部清掉:

删空后列表会显示"所有组或用户均不具有访问此对象的权限。但是该对象的所有者可以分配权限"——这就是我们要的中间状态:

点左下角「添加」→「选择主体」→ 在弹出框输入你当前 Windows 用户名(不知道用户名就开 cmd 跑 whoami 查),点「检查名称」让系统自动补全:

确定后回到权限项目对话框,只勾「读取和执行」+「读取」,不要勾「写入」——OpenSSH 只需要读私钥,写权限会让它怀疑文件可被篡改:

确定,列表里现在只剩你一个用户的「读取和执行」记录:

逐层点「确定」/「应用」回到属性窗口,最后再点一次「确定」生效:

⚠️ 如果上面任何一步报错"拒绝访问",先在属性「常规」/「安全 → 高级」里把 id_rsa 的"所有者"改成自己(「高级 → 所有者 → 更改」),再回来收紧 ACL。
权限收紧之后,cmd / PowerShell 里 ssh -i E:\ssh\id_rsa ops@<host> 就能顺利登录了。
第三步:改 sshd_config,关掉密码登录
公钥能用之后,下一步是把密码通道关上——否则前面所有努力都被一个弱密码废掉。在服务器上:
sudo vim /etc/ssh/sshd_config
确认/改成下面这几项(注释掉的去掉 #):
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin prohibit-password
ChallengeResponseAuthentication no
UsePAM yes
最关键的是 PubkeyAuthentication yes(启用公钥验证)和 PasswordAuthentication no(关闭密码验证)这两行——其他几项是配套加固:

保存后重载(不要直接重启,免得当前会话被踢且没法回头):
sudo systemctl reload sshd
⚠️ 保留一个登录中的窗口!万一配错了导致连不上,新会话被拒,旧窗口还能改回来。验证没问题再关掉它。
新开一个终端用密钥登录通过,再试一次:
ssh -o PreferredAuthentications=password ops@192.168.1.100
# 应当显示:Permission denied (publickey).
看到 publickey 拒绝就对了——密码通道已经死路一条。
第四步:用 MoleSDN 让客户端能从外网直连服务器
到这里在公司局域网里已经一切顺手,但人不可能 7x24 趴在公司。家里、出差时也要能 SSH 上去——传统做法要么开放 22 端口到公网(极度危险),要么搭 VPN(成本高、配置麻烦)。MoleSDN 给你第三条路:把客户端电脑和 Linux 服务器拉进同一张虚拟内网。
服务器端安装 MoleSDN 客户端(Linux 版命令行运行即可),登录账号后进入 MoleSDN 控制台 → 创建服务域 linux-ops:

把这台 Linux 服务器绑定为「中心模式(Hub)」——它要对外提供 SSH 服务,所以是 Hub:

💡 不熟悉 Hub / Spock 概念?看 服务域与节点——一句话:提供服务的一端选「中心模式」,主动连入的一端选「接入模式」。
客户端电脑装 MoleSDN(下载客户端),用同一账号登录后接入服务域 linux-ops,工作模式选「接入模式(Spock)」。绑定完成后,控制台会显示服务器分配到一个 100.64.x.x 的虚拟 IP,比如 100.64.2.10。
整个流程在控制台点鼠标就完事,详细步骤参见 快速上手。
第五步:异地一行命令免密登录
回到客户端电脑,把原来的内网 IP 换成 MoleSDN 分配的虚拟 IP:
ssh ops@100.64.2.10
不论你这会儿在家里、咖啡馆还是高铁上——只要客户端能上网,连接立刻就建立。数据点对点直连,不经过 MoleSDN 中转服务器,延迟和本地局域网几乎一样。
💡 想偷个懒,在客户端
~/.ssh/config加一段:Host my-server HostName 100.64.2.10 User ops IdentityFile ~/.ssh/id_ed25519之后ssh my-server三个字直接进。
常见问题
问题 1:连接被拒,提示 Permission denied (publickey)
最常见的两种原因:
- 服务器
~/.ssh或authorized_keys权限太松。重新执行chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys - 客户端用了默认私钥之外的位置。用
ssh -i ~/.ssh/id_ed25519 ops@100.64.2.10显式指定,或在~/.ssh/config里配IdentityFile
排查神器:客户端跑 ssh -vvv ops@100.64.2.10,能看到三段握手细节,哪一步失败一目了然。
问题 2:reload sshd 后整个连不上了,密码也不行
说明 sshd_config 改错了,但你已经关了密码登录。处理顺序:
- 通过物理控制台 / 机房 KVM / 云厂商 VNC 登录到机器
sudo vim /etc/ssh/sshd_config,把PasswordAuthentication先恢复成yessudo systemctl restart sshd- 重新走一遍第三步,这次保留一个旧会话
❌ 千万别在没有物理控制台的云服务器上直接 disable 密码登录前就把密钥配错——这是新手最常见的"把自己锁在门外"。
问题 3:MoleSDN 节点显示绿色但 SSH 卡住
虚拟 IP 已经通了,但 SSH 卡在 debug1: Connecting to ... 不动,多半是服务器本地防火墙拦了。检查:
sudo ufw status # Ubuntu / Debian
sudo firewall-cmd --list-all # CentOS / Rocky
如果有规则,放行 22 端口对 100.64.0.0/10 的入站即可。
问题 4:节点环境标红,校园网/酒店网下连不上
学校宿舍、酒店网络属于多层 NAT,普通直连可能打不穿。在客户端节点上开启「超级鼹鼠」,强化穿透能力,能解决绝大多数严苛 NAT 场景;更多见 高级功能。
总结
走完上面五步,你拿到的是一套生产级的 Linux SSH 远程运维方案:
- 私钥认证 + 密码登录关闭:暴力破解直接没门,安全等级跨一个量级
- MoleSDN 异地组网:零月租、不限流量、点对点直连,从家里/酒店/高铁直接
ssh上服务器,体验等同于在公司 - 不需要公网 IP、不需要改路由器、不需要架 VPN 跳板机——给 Linux 服务器做异地访问,这是目前最轻量的方案
如果你管的不只一台 Linux 服务器,还涉及 NAS、内网网页、ERP/OA 系统等更复杂的远程访问场景,超级鼹鼠 / 智能路由 / 叶子路由 这类高级功能能在校园网、酒店、企业严苛网络下保住直连稳定性。
如果是混合场景——比如机房里还跑着 Windows 服务器要远程桌面、或者家里 OMV NAS 也要异地访问——这两篇可以一起看:Windows 异地远程桌面、OMV NAS 异地访问。
还没用过 MoleSDN?快速上手 全程 1 分钟,三步完成注册 → 装客户端 → 绑服务域。祝运维顺利。