news 2026/9/30 3:46:58

Windows与Linux之间SSH免密登录配置实战:公钥认证、权限排错与批量管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Windows与Linux之间SSH免密登录配置实战:公钥认证、权限排错与批量管理

每天在终端里敲ssh user@192.168.1.100,然后老老实实输密码,一天反复十几次,偶尔还得处理scp传到一半断掉重来的情况。后来开始写自动化脚本、用 Ansible 批量下发配置,密码认证彻底成了瓶颈——脚本一跑起来就卡在交互式输入那里,要么用 expect 蛋疼地匹配提示符,要么就得把密码硬编码进配置文件。无论哪种,体验都很糟糕。SSH 免密登录解决的就是这个问题:把"每次验证身份"变成"首次信任、之后畅通",同时安全性并不比密码登录差,甚至更好。这篇文章我基于自己在 win10 和多家 Linux 发行版上的实操经历,把两端配置、常见坑、批量管理的完整思路都铺开讲一遍,希望对正在折腾这件事的你有点帮助。

1. 折腾免密登录之前,先想清楚要解决什么

1.1 每天输密码的日子,到底输在哪了

在 Windows 10 上装个 OpenSSH 客户端非常简单,系统从 1809 版本开始就自带了ssh.exe,不需要额外安装任何东西。所以很多人的日常工作流是:打开 PowerShell 或 Windows Terminal,敲 ssh 命令连上 Linux 服务器,输入密码,开始干活。单次操作也就几秒钟,但一天下来,这些"几秒钟"会被无限放大。

更麻烦的是,当操作对象变成一批服务器时,密码认证的短板就极其明显。比如我临时要检查 10 台机器的磁盘空间,用脚本循环 ssh 过去执行df -h,密码认证就会让脚本卡死。你可能说可以用sshpass或者expect,但这类工具需要额外安装,而且把密码以明文形式写在脚本或命令行参数里,本身就是个安全隐患。免密登录的真正价值不是"少打几个字",而是让非交互式场景变得可用,让自动化工具链(Ansible、rsync、crontab 定时任务)不再受制于人工输密码。

1.2 免密登录不是无脑配置,它有自己的适用范围

这里要先泼一盆冷水:免密登录不是所有场景都该用。它的前提是"客户端身份可信"。你自己家里的电脑、公司的跳板机、云上的管理机,这类你能完全控制物理和系统安全的设备,非常适合做免密。但如果你在一台公共电脑上配置免密,那等于把进入服务器的钥匙留给了所有能登录这台公共电脑的人,风险很高。

适用场景包括:

  • 个人开发机到测试服务器,减少日常操作摩擦。
  • 跳板机到内网服务器,配合 SSH Agent 做转发。
  • CI/CD 流水线中,构建机到部署目标机的自动发布。
  • 定时脚本、rsync 备份、日志采集等无人值守任务。

需要谨慎的场景:

  • 公网暴露的高权限服务器,不建议设置免密,或者至少限制来源 IP。
  • 多人共用的机器、临时工位电脑、云桌面,不建议配置。
  • 跨安全域跳转时,需要评估私钥落入他人手里的可能性。

1.3 我这次配置所采用的环境约定

为了后面叙述不乱,先交代一下环境。客户端我以 Windows 10 专业版 22H2 为主,Linux 发行版覆盖了 Ubuntu 22.04 LTS、Debian 12、CentOS Stream 9、龙蜥 OS 8 这几种。win10 端的 OpenSSH 客户端版本是 8.x,Linux 端 sshd 版本有 OpenSSH 8.9p1 和 9.x 等。不同版本之间密钥算法兼容性有些差异,后面会专门提到。整体流程在多数主流发行版上通用,如果你用的是其他版本,操作基本一致,只是个别配置文件路径和命令包名会有差别。

2. 免密登录背后的公钥认证流程

2.1 用"锁和钥匙"来理解公私钥

很多第一次接触免密登录的人,容易把"公钥"和"私钥"搞混。换个角度讲:公钥是一把锁,私钥是这把锁唯一的钥匙。你把锁(公钥)装到服务器的门上,钥匙(私钥)留在自己的客户端手里。别人看到了你的锁也没用,因为他没有对应的钥匙;钥匙丢了就比较麻烦,捡到钥匙的人能打开所有装过这把锁的门。所以私钥文件的权限必须严格控制,这就是后文反复强调权限的原因。

服务器只保存公钥,客户端每次连接时证明自己持有私钥。这个设计的好处是:就算服务器被入侵,攻击者拿到的是公钥,无法反推出私钥;就算公钥在传输过程中被人截获,也一样没用。所以把公钥内容随便发给别人没问题,私钥则必须当作比密码更重要的秘密来保护。

2.2 握手过程里发生了什么

SSH 公钥认证的完整流程大致是:客户端发起连接后,服务器发送一个随机挑战值;客户端用私钥对这个挑战值做签名;服务器拿到签名后用自己保存的公钥去验签,验签成功就确认客户端持有对应私钥,建立会话。

整个过程不传输私钥本身,也不需要用密码登录。这也是为什么免密登录叫做"公钥认证"而不是"无认证"——它的认证强度通常高于密码。服务器端在验证签名通过后,还会检查是否存在~/.ssh/authorized_keys文件中的对应公钥条目,以及客户端 IP、用户等信息是否被允许。严格模式下,文件属主和权限也会被检查,这就为后面的权限坑埋下了伏笔。

2.3 免密不等于不安全,前提是管好私钥

说到底,密码认证和公钥认证的区别是:密码是"你知道什么"(something you know),私钥是"你拥有什么"(something you have)。公钥认证更接近物理世界的钥匙,不会因为某次通信被监听而泄露。但前提是私钥不能丢。为了提升安全性,可以在生成密钥时设置 passphrase(口令短语),相当于给私钥文件再加一道加密。这样即使别人拷走了你的私钥文件,没有 passphrase 也用不了。日常使用中,可以用 SSH Agent 把私钥加载进内存,这样每次连接时就不需要重复输入 passphrase 了。这个组合既方便又不牺牲安全,我强烈建议在生产环境使用。

3. win10 作为客户端:生成密钥、部署公钥到 Linux 的完整操作

3.1 先确认 win10 自带的 OpenSSH 是否可用

很多教程一上来就让人下载 Putty 或第三方工具,实际上 win10 自带的 OpenSSH 客户端已经很够用了。打开 PowerShell,输入:

ssh -V

能看到类似于OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2的输出就说明可用。如果提示找不到命令,可以去设置 → 应用 → 可选功能 → 添加可选功能,找到 OpenSSH 客户端安装。装了之后重启终端就行。

这里我推荐直接用 Windows Terminal 或者 PowerShell 7 来跑 ssh 相关命令,老款 conhost 对 SSH 交互式终端支持不是很好,遇到全屏程序(比如 vim、htop)时显示容易出问题。

3.2 生成密钥对:选 ed25519 还是 RSA

在 win10 的 PowerShell 中执行:

ssh-keygen -t ed25519 -C "win10-dev-key" -f $env:USERPROFILE\.ssh\id_ed25519

参数说明:

  • -t ed25519:指定密钥算法类型。Ed25519 是目前综合推荐的选择,密钥短、速度快、安全性高。但如果你的 Linux 服务器版本较老(比如 CentOS 7 早期、Ubuntu 16.04 之前),sshd 可能不支持 Ed25519,那就改用-t rsa -b 4096。
  • -C "win10-dev-key":添加注释,用于标识这枚密钥的来源或用途。建议写清楚是哪台机器、给谁用的,后面管理一堆公钥时会省很多事。
  • -f:指定保存路径。Windows 默认位置是C:\Users\你的用户名\.ssh\id_ed25519,我一般会显式指定,避免密钥放到默认之外的路径后 ssh 找不到。

执行后它会提示设置 passphrase。本地开发机建议直接留空(按两次回车)即可,因为日常使用输 passphrase 也很烦;生产环境或公司电脑,强烈建议设置一个 passphrase,然后用 ssh-agent 来记住它。

生成完成后,.ssh目录下会多出两个文件:id_ed25519(私钥)和id_ed25519.pub(公钥)。私钥文件在 Windows 资源管理器里可能看不到,因为它是隐藏文件。如果想快速查看公钥内容:

cat $env:USERPROFILE\.ssh\id_ed25519.pub

3.3 把公钥部署到 Linux 服务器的几种方式

这是整个流程里最容易让人懵的一步。win10 没有ssh-copy-id这个命令,不过有更好的替代方案。

第一种,直接在 PowerShell 里用管道把公钥内容追加到服务器的authorized_keys文件中:

type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh root@192.168.1.100 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

这条命令会让 ssh 先提示你输入一次密码,输入正确后,它会自动创建.ssh目录并把公钥追加进去。注意替换root@192.168.1.100为你的实际用户名和 IP。如果服务器上已经存在authorized_keys文件,上面命令会用>>追加而不是覆盖,不会影响已有公钥。

第二种,如果公钥内容比较多或不喜欢用管道,就手动复制。先在本地打印公钥内容,然后登录服务器用 vim 或 nano 编辑~/.ssh/authorized_keys,把内容粘贴到新的一行。这种方式的缺点是容易漏掉结尾换行,导致两行公钥粘在一起,后文排查会讲这个坑。

第三种,只适用于 Linux 客户端,但值得提一下:如果你手上已经有一台 Linux 管理机,也可以把公钥先传到那台机器上,然后用ssh-copy-id批量分发过去。win10 客户端本身没有这个命令,但可以通过 Git Bash 或 Cygwin 环境间接调用,我个人不太推荐为了一个命令去装全套模拟环境。

3.4 验证免密登录,注意 known_hosts 首次确认

部署完公钥后,在 win10 的 PowerShell 里执行:

ssh user@192.168.1.100

如果没有设置 passphrase,正常情况下会直接进入服务器的 shell,不再提示密码。如果服务器之前从未被连接过,会出现一段 host key 确认提示:

The authenticity of host '192.168.1.100' can't be established. ED25519 key fingerprint is SHA256:xxx. Are you sure you want to continue connecting (yes/no)?

这个提示是 SSH 客户端在确认你连接的是正确的服务器,防止中间人攻击。输入yes确认后会写入known_hosts文件,以后不会再提示。如果你不确定服务器的指纹是否真实,可以用ssh-keyscan或手动登录一次获取指纹进行比对,但日常内网环境下,第一次连接确认 host key 信息后也没太大问题。

如果到这里发现仍然要密码,别急着怀疑人生,八成问题出在 Linux 服务器端的文件权限上,进入下一章。

4. Linux 服务器端 authorized_keys:权限就是免密登录的命门

4.1 .ssh 目录和 authorized_keys 文件的权限要求

之前帮同事排查过一次,公钥明明已经写进authorized_keys了,还是一直提示密码认证。后来登录服务器一看,.ssh目录权限是755,authorized_keys文件权限是644。这就是典型的权限地狱。

OpenSSH 出于安全考虑,默认启用了 StrictModes,如果~/.ssh或~/.ssh/authorized_keys的权限过于宽松,sshd 会认为这些文件可能被其他用户篡改,直接拒绝使用它们做公钥认证,然后退回到密码认证。严格来说,要求的权限是:

  • 用户家目录本身不能是 group 或 others 可写的,通常是755或700。
  • ~/.ssh目录权限应为700,只有属主能读写执行。
  • ~/.ssh/authorized_keys文件权限应为600,只有属主能读写。

执行以下命令修复:

chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chown -R $(whoami):$(whoami) ~/.ssh

如果是用 root 用户配置,没有chown问题;但如果你是切换到某个普通用户,注意authorized_keys文件的属主必须是你登录时那个用户。比如你从 win10 用ubuntu用户登录,公钥就必须写在/home/ubuntu/.ssh/authorized_keys,不能写到 root 的目录下。

4.2 权限不对时,怎么从日志里看出原因

如果你配置完免密登录仍然要输密码,第一件事不是去改 sshd 配置,而是看服务端日志。在 Ubuntu/Debian 上:

sudo journalctl -u ssh -f

在 CentOS/RHEL/龙蜥 OS 8 上:

sudo tail -f /var/log/secure

然后从 win10 那边再发起一次 ssh 连接,观察服务端日志输出。如果权限有问题,日志里会出现:

Authentication refused: bad ownership or modes for file /home/ubuntu/.ssh/authorized_keys

看到这句话,基本就是权限问题,按上一节的方法修即可。日志里还可能出现Permission denied (publickey,password),这个表示客户端尝试过公钥但服务端拒绝了,常见原因包括公钥内容不对、权限有问题、sshd 配置禁止了 pubkey 认证。

4.3 sshd_config 里可能挡路的配置项

除了文件权限,/etc/ssh/sshd_config中的几个项目也需要确认:

sudo grep -E "PubkeyAuthentication|AuthorizedKeysFile|PasswordAuthentication|PermitRootLogin" /etc/ssh/sshd_config

常见情况:

  • PubkeyAuthentication yes必须启用,这是公钥认证的总开关。
  • AuthorizedKeysFile .ssh/authorized_keys保持默认即可,不要乱改成绝对路径,否则会到意想不到的地方找公钥。
  • PasswordAuthentication如果设置为no,则禁止密码登录。这个配置也是很多网站在配置完免密后为了安全而开的,但改之前一定要确认公钥认证已经能正常工作,否则一旦两边不匹配,你可能连服务器都进不去了。
  • PermitRootLogin如果设置为prohibit-password或yes,root 用户才能用公钥直接登录。默认很多发行版是prohibit-password,也就是 root 可以用公钥登录但不能用密码登录,这其实是个不错的配置。

修改完sshd_config后需要重启 sshd 服务:

sudo systemctl restart sshd

注意:重启服务不会断开现有连接,但如果你改错了配置导致 sshd 起不来,需要格外小心。远程操作时建议先执行sudo sshd -t检查配置语法,确认无误再重启。

4.4 SELinux 和 AppArmor 给免密登录设的额外关卡

CentOS、Rocky Linux、龙蜥 OS 这类基于 RHEL 的发行版,默认启用了 SELinux。即使文件权限正确,SELinux 也可能阻止 sshd 读取用户家目录中的 authorized_keys 文件。特别是当你把.ssh目录从一个地方复制过来,或者手动创建了目录但安全上下文不对时,会遇到奇奇怪怪的问题。

如果权限和配置都检查过了,仍然无法免密登录,可以在服务器上执行:

sudo restorecon -Rv ~/.ssh

这是恢复目录的 SELinux 安全上下文。如果之前把.ssh放到非正常路径(比如自定义 home 目录),还需要检查该目录的 SELinux 类型是否为ssh_home_t。用ls -Z ~/.ssh可以查看:

ls -Z ~/.ssh

正常输出应为unconfined_u:object_r:ssh_home_t:s0之类,如果显示var_t或其他类型,执行restorecon修正。

AppArmor 在 Ubuntu/Debian 上默认对 sshd 的限制相对宽松,一般不需要额外处理。但如果遇到报错无法读取公钥,也可以顺手查一下/etc/apparmor.d/usr.sbin.sshd规则,虽然这种情况很少。

4.5 一台服务器上放多个公钥,怎么管理不混乱

服务器上的authorized_keys文件支持一行一个公钥,也就是说可以同时放很多人的公钥。没必要给每个人都建单独的账户,除非需要区分权限。我个人的管理习惯是:

  • 公钥内容后面必须带注释,标明"哪台机器、哪个用户、什么时候加的"。
  • 定期清理不再使用的公钥。
  • 手动编辑 authorized_keys 时,使用编辑器写完后确认最后一行有换行。

如果一个用户的authorized_keys文件行数越来越多,可以考虑把不同用途的公钥按行组织,并在上方添加注释行。比如:

# desktop win10 dev ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... win10-dev-key # jump server ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... jump-key

注意:authorized_keys文件里不能识别#开头的注释行?实际上 OpenSSH 支持在authorized_keys中用#开头作为注释,但要注意别把整行公钥误注释掉。我自己偶尔会见到有人在文件里写了两个公钥但中间没有换行,结果两个公钥连成一行,导致两个都验证失败。遇到这种情况,把文件拆成两行即可。

5. 反过来:Linux 免密登录 win10 的配置,实现双向互通

5.1 在 win10 上安装并启动 OpenSSH Server

标题既然是"在 win10 和 Linux 上配置 SSH 免密登录",那么双向互通也是绕不开的需求。比如你有一台 Linux 服务器,想直接连到 win10 机器上执行 Windows 命令,或者在 win10 上跑自动化脚本,就需要在 win10 端装 OpenSSH Server。

安装路径:设置 → 应用 → 可选功能 → 添加可选功能,找到"OpenSSH 服务器",点击安装。安装完成后,用管理员身份打开 PowerShell,执行:

Start-Service sshd Set-Service -Name sshd -StartupType Automatic

第一条命令启动 sshd 服务,第二条设置开机自启。然后再查一下防火墙规则:

Get-NetFirewallRule -Name *ssh*

正常情况下安装 OpenSSH Server 时会自动创建两条防火墙入站规则,允许 22 端口访问。如果没有,手动添加:

New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

5.2 把 Linux 的公钥部署到 win10 的 authorized_keys

win10 的 OpenSSH Server 是基于 OpenSSH for Windows 的移植版本,认证逻辑和 Linux 基本一致。因此,在 Linux 上生成密钥对:

ssh-keygen -t ed25519 -C "linux-manage"

然后查看公钥:

cat ~/.ssh/id_ed25519.pub

接下来把公钥放到 win10 上。这一步有个大坑:win10 的 OpenSSH Server 默认配置中,管理员组成员的公钥文件路径不是%USERPROFILE%\.ssh\authorized_keys,而是C:\ProgramData\ssh\administrators_authorized_keys。这个文件需要手动创建,并且权限必须设置为只允许 Administrators 组和 SYSTEM 访问,否则 sshd 会拒绝使用这个文件。

我在第一次配置时就踩了这个坑:把公钥写到了C:\Users\admin\.ssh\authorized_keys,结果 Linux 连过来一直提示Permission denied (publickey)。后来看了官方文档才明白,win10 的 sshd_config 里面有这么一段:

Match Group administrators AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

也就是说,管理员用户登录时,sshd 不会去用户目录下找 authorized_keys,而是去C:\ProgramData\ssh\administrators_authorized_keys找。

所以配置步骤是:

  1. 在 win10 上以管理员身份打开 PowerShell,创建目录和文件:
mkdir $env:ProgramData\ssh notepad $env:ProgramData\ssh\administrators_authorized_keys
  1. 把 Linux 的公钥粘贴进去,保存。
  2. 修正文件权限,让 sshd 能读取。注意不要使用普通方式直接赋予 Everyone 权限,否则 sshd 也会因为权限过宽拒绝。建议用 icacls:
icacls $env:ProgramData\ssh\administrators_authorized_keys /inheritance:r icacls $env:ProgramData\ssh\administrators_authorized_keys /grant "SYSTEM":F icacls $env:ProgramData\ssh\administrators_authorized_keys /grant "Administrators":F

如果你登录 win10 用的是非管理员组的普通用户,那么公钥就放到C:\Users\用户名\.ssh\authorized_keys,权限要求相对宽松一些,但ssh的日志会告诉你具体去哪里找。

  1. 重启 sshd:
Restart-Service sshd

然后回到 Linux 上测试:

ssh administrator@192.168.1.50

如果没提示密码就进去了,说明双向免密配置成功。

5.3 win10 OpenSSH Server 的默认 Shell 设置

连上 win10 之后默认打开的是 Windows CMD,不是 PowerShell。如果你更习惯 PowerShell,可以在 win10 上修改注册表或者用New-ItemProperty设置默认 shell:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

修改后需要重启 sshd。如果不设置,默认 CMD 也能用,只是部分命令不熟悉的话容易蒙。

5.4 Linux 连 win10 时的文件编码与路径坑

Linux 下的scp可以直接拷贝文件到 win10,但注意 Windows 路径分隔符和权限。比如:

scp ./test.txt administrator@192.168.1.50:C:/Users/administrator/Desktop/

路径中尽量使用正斜杠,避免反斜杠被 shell 转义。另外,win10 的 OpenSSH 默认是 OpenSSH for Windows,和原生 OpenSSH 行为有一定区别,有些配置文件里的指令不支持(比如AuthorizedKeysCommand),遇到报错时留意一下版本兼容性。

6. 排错实战:从一条连接失败到定位根因的完整链路

6.1 先判断问题出在客户端还是服务端

免密登录失败时,先不要一股脑去改配置。我的排查顺序是:

  1. 在客户端执行ssh -vvv user@host看详细输出。
  2. 观察输出中的关键阶段:网络连接是否成功、是否尝试了公钥认证、服务端是否接受公钥、是否退回了密码。
  3. 根据输出定位是客户端问题还是服务端问题。

-vvv输出非常啰嗦,但里面藏着关键信息。比如:

debug1: Authentications that can continue: publickey,password debug1: Next authentication method: publickey debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxx debug1: Server accepts key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxx

看到Server accepts key之后仍然让你输密码,那大概率是服务端在公钥验证之外还有额外限制(比如权限、用户限制、Match 块)。如果输出里压根没有Offering public key这一行,就说明客户端没有找到合适的私钥,需要检查-i参数或默认密钥路径。

6.2 服务端日志是最终裁判

在服务器上开一个终端,实时跟踪日志,然后从客户端再试一次连接。Ubuntu/Debian 用:

sudo journalctl -u ssh -f

CentOS/RHEL 用:

sudo tail -f /var/log/secure

日志里如果有Authentication refused: bad ownership or modes,这是权限问题;如果有Failed publickey for user from 192.168.1.20 port 50000 ssh2: RSA SHA256:xxx,说明公钥验证失败,可能是公钥内容不匹配;如果有Connection closed by authenticating user,可能要检查 sshd 是否因为次数过多临时断开了连接。

另外,很多发行版默认开启了MaxAuthTries 6,反复输错或公钥尝试次数过多会被断开。如果客户端配了多个密钥文件,可能触发这个限制。

6.3 高频问题对照表

我在不同环境里遇到并解决过的问题,整理如下:

现象可能原因解决方式
连接被拒绝sshd 服务未启动、防火墙拦截、端口不对Windows 上检查自启动;Linux 用 systemctl status sshd
总是提示密码客户端没提供私钥,或服务端拒绝了公钥排查公钥是否部署、权限是否正确、客户端是否用了正确密钥
Permission denied (publickey)服务端关闭了密码认证,公钥又不过从控制台登录检查公钥和权限
Bad owner or permissions.ssh 或 authorized_keys 权限过宽设置 .ssh 为 700、authorized_keys 为 600,修正属主
no matching key exchange method客户端算法与服务端不匹配升级客户端或修改 sshd_config 添加算法
Server accepts key 但还是要密码用户锁了密码,或账户被禁止登录检查 /etc/passwd 中 shell 是否正常,是否被锁定
第一次连接确认 host key 后仍失败known_hosts 记录与实际 host key 冲突用ssh-keygen -R 主机IP清除旧记录
win10 管理员无法公钥登录公钥写入位置不对放到 C:\ProgramData\ssh\administrators_authorized_keys

6.4 客户端多密钥和 known_hosts 的诡异问题

很多人在同一台 win10 上拥有多个 SSH 密钥:一个连 GitHub,一个连工作服务器,一个连云主机。SSH 客户端默认只会尝试按顺序使用默认路径下的私钥,如果你的私钥不叫id_rsa、id_ed25519,或者不在默认目录,客户端可能压根不会去尝试。这时可以显式指定:

ssh -i C:\Users\me\.ssh\my_custom_key user@192.168.1.100

或者更优雅的做法是创建 SSH config 文件,在C:\Users\me\.ssh\config中配置:

Host myserver HostName 192.168.1.100 User ubuntu Port 22 IdentityFile C:\Users\me\.ssh\my_custom_key

配置之后,直接ssh myserver就能连接。SSH config 对多主机管理非常有用,后面章节会详细展开。

known_hosts的坑也很常见。当你重装了一次服务器系统,或者服务器换了 host key,客户端会因为 known_hosts 里保存的旧 host key 与当前服务器的 host key 不匹配而拒绝连接,提示类似:

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

解决方法是清除旧记录:

ssh-keygen -R 192.168.1.100

注意,这个命令清除的是 known_hosts 中该主机的记录,不会影响其他主机。重新连接后按提示接受新的 host key 即可。

7. 免密登录进阶:多主机批量管理与自动化

7.1 用 SSH config 把免密登录变成"一键直达"

公钥配置好了之后,免密登录已经能用,但每次都要敲ssh user@192.168.1.100 -p 2222这种长命令还是不够爽。在客户端配置 SSH config 可以解决这个问题。win10 上文件位于C:\Users\你的用户名\.ssh\config,Linux 上位于~/.ssh/config。

一个典型的配置示例:

Host dev-ubuntu HostName 192.168.1.100 User ubuntu Port 22 IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 Host prod-centos HostName 10.0.0.5 User root Port 2222 IdentityFile ~/.ssh/id_rsa_prod

第一列Host后面的别名可以随便取,ssh dev-ubuntu就能免密登录到对应主机。ServerAliveInterval是发送心跳包的时间间隔,防止远程会话因为长时间无操作被防火墙断开,我这个参数基本每次都会配。

7.2 批量分发公钥到多台 Linux 服务器

当你手里有几十台服务器,逐台手动粘贴公钥显然不现实。最常见的方式是在一台 Linux 管理机上写好循环脚本,用sshpass提供密码,或者先用密码登录一台,再借助信任关系扩散。

假设你已经在管理机上生成了密钥,现在有一个hosts.txt文件,每行一个 IP,账号统一为root,用sshpass批量执行:

#!/bin/bash while read host; do sshpass -p '你的临时密码' ssh-copy-id -o StrictHostKeyChecking=no root@$host done < hosts.txt

注意,sshpass需要单独安装,而且临时密码会暴露在脚本中。更好的做法是先把所有服务器都设置成一个临时密码,然后批量执行完成后立即修改密码,或者配合 CMDB 来传参。如果你已经配好了其中一台服务器的免密,也可以通过ProxyJump跳转来间接管理其他内网机器。

如果你的环境里有 Ansible,那更方便。在 Ansible 的 hosts 清单里配置好所有服务器,然后执行一个 ad-hoc 命令分发公钥:

ansible all -m authorized_key -a "user=root key='{{ lookup('file', '/root/.ssh/id_ed25519.pub') }}'" -k

-k会提示输入 SSH 密码,一次性把公钥推送到所有目标机器。这种方式比写循环脚本更规范,也便于后续维护。

7.3 免密登录和 cron 定时任务配合的注意事项

免密登录最常见的一个实际用途就是定时任务。比如每天早上从数据库服务器拉取备份文件到本地:

30 2 * * * rsync -avz --delete backupuser@db-server:/backup/ /local/backup/

因为配置了免密登录,rsync 不需要人工干预就能执行。但这里有几个细节:

  • 定时任务执行时用的用户是谁,取决于 crontab 所属用户。不要在 root 的 crontab 里使用某个普通用户的私钥,反之亦然。
  • 如果私钥设置了 passphrase,cron 环境无法输入,需要先把私钥添加到ssh-agent,再通过SSH_AUTH_SOCK让子进程继承。这个配置比较麻烦,建议对自动化用的密钥单独生成一对,不设置 passphrase,并严格限制其在服务器上的权限。
  • 服务器端可以对特定用户做限制,比如只允许 rsync 或特定命令,防止密钥泄露后造成更大危害。可以在~/.ssh/authorized_keys中给某个公钥前面加command="/usr/bin/rsync --server ..."前缀,这是另一个进阶话题。

7.4 撤销免密权限,比配置更重要

免密登录的生命周期管理最容易被忽视。员工离职、设备重装、密钥泄露,都需要及时撤销某个公钥的访问权限。在 Linux 服务器上,撤销就是把authorized_keys文件中对应的行删除;在 win10 上,就是删除administrators_authorized_keys或用户目录下authorized_keys中对应的行。

如果你管理的机器多了,手动删除太慢,可以用脚本批量处理。还是 Ansible 最方便:

ansible all -m lineinfile -a "path=/root/.ssh/authorized_keys regexp='my_old_public_key' state=absent"

此外,建议定期审计所有服务器上的authorized_keys文件,列出每台机器允许哪些公钥登录。用脚本从所有服务器拉取 authorized_keys 汇总到管理机,和 CMDB 里的备案信息比对,发现陌生公钥就及时清理。

8. 我踩过的一些真实教训,写出来帮你避坑

8.1 别把公钥追加到错误用户的 authorized_keys

有一次我帮同事配置免密,他明明粘贴的公钥没问题,但始终连不上。后来我发现他把公钥追加到了/home/ubuntu/.ssh/authorized_keys,但登录时用的用户名是ec2-user。SSH 认证时使用哪个用户名登录,就去哪个用户的家目录下找 authorized_keys,这个最基本的逻辑很多人会忽略。排查时先确认登录用户名和公钥所在目录是一一对应的。

8.2 换行符和编码问题,在 win10 下格外容易踩

win10 上记事本默认使用 CRLF 换行和 ANSI 编码。如果你在 win10 上编辑公钥文件,然后再手动复制内容到 Linux,可能出现公钥末尾带着\r的情况,导致服务器验签失败。我在 win10 上查看公钥后,复制粘贴到 Linux 的 authorized_keys 时也中过招。解决方法是:在 PowerShell 里用cat输出公钥,然后复制到 Linux 用 vim 编辑时确认没有多余字符;或者直接用上面提到的管道方式,让公钥内容原样传入,避免手动复制引起的换行符问题。

对于authorized_keys文件的末尾换行,也要注意。如果上一个公钥后面没有换行,下一个公钥紧接着追加,两行会连在一起,服务端会把它们当做一个无效的公钥,导致两个公钥都无法认证。每次追加公钥后,用cat -A ~/.ssh/authorized_keys查看文件,行尾应显示$,确保每行完整独立。

8.3 修改 sshd_config 时,永远留一条后路

这是远程管理服务器最重要的一条建议。编辑sshd_config之前,先用sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak做个备份。修改完成之后,先执行sudo sshd -t检查语法,再systemctl reload sshd或者service sshd reload,而不是 restart。虽然两者差异不大,但 reload 更平滑,不会瞬间断开所有连接。

更保险的做法是:在修改密码认证和公钥认证相关的配置时,先保持当前 SSH 会话不断开,另开一个新的终端测试是否能正常连接。如果新连接失败,还能从旧会话里改回配置。这个习惯帮我避免过至少三次把自己锁在服务器外面的尴尬局面。

8.4 密钥轮换要当成定期任务

公钥认证的安全性高度依赖私钥的保密性。长时间不轮换密钥,意味着一旦私钥泄露,攻击者有足够长的利用时间。建议半年或一年轮换一次,尤其在人员变动、设备转交时立即轮换。轮换过程不必太复杂:客户端生成新密钥对,把新公钥追加到服务器 authorized_keys,确认能登录后再删除旧公钥。Ansible 可以同时做这两步,降低操作风险。

我个人在实际操作中的体会是:SSH 免密登录的配置本身并不难,难的是把"信任边界"管理好。凡是配置成免密的机器,都意味着你默认信任持有对应私钥的人。所以在服务器端,尽量不要把所有机器都向同一把私钥开放;可以根据用途拆分成多对密钥,工作电脑一把、自动化任务一把、应急备份一把,互不干扰。这样即使某一把私钥泄露,影响面也可控。希望这篇基于实操的内容能帮你少走一些弯路,真正把 win10 和 Linux 之间的连接变成顺手的事。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 3:46:48

agent记忆工程原理和实战落地解析

简介随着 Agent 从“问答机器人”逐渐走向真正执行任务&#xff0c;Memory&#xff08;记忆&#xff09;开始成为 Agent 系统的基础能力。传统 RAG 解决的是&#xff1a;“系统能从知识库里找到什么&#xff1f;”而 Agent Memory 解决的是&#xff1a;“系统应该记住谁的什么信…

作者头像 李华
网站建设 2026/9/30 3:46:25

MySQL慢SQL定位:用EXPLAIN读懂执行计划,告别低效索引

开门见山说一句&#xff1a;我见过太多人&#xff0c;SQL写得花里胡哨&#xff0c;一慢下来就直接扔给DBA&#xff0c;自己对着EXPLAIN的输出一脸懵。其实在MySQL里定位低效SQL&#xff0c;explain就是那个最趁手的放大镜。你不需要读几十页官方文档&#xff0c;只要把explain输…

作者头像 李华
网站建设 2026/9/30 3:46:03

快而不完美的过程建模:用灰度交付思路绘制可迭代的业务流程图

我参加过一次流程梳理会&#xff0c;90分钟的会议有一半时间花在一个争论上&#xff1a;这条连接线该不该从采购模块的出口画到库存模块的入口&#xff0c;方框底色用不用统一成浅灰。会后所有人都在点头&#xff0c;但没有人能说清楚下一步要做什么。这种场面我在项目里见过太…

作者头像 李华
网站建设 2026/9/30 3:45:13

DeepSeek法律文档智能摘要:抽象式生成与法律效力校验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 3:45:03

MySQL 5.5 Windows安装配置全攻略:从下载到排查1067错误

MySQL 实验1&#xff1a;Windows 环境下 MySQL5.5 安装与配置&#xff0c;这个标题放在现在看确实有点复古&#xff0c;但恰恰是很多人的第一堂数据库实验课。这几年我在实验室和公司里帮人处理过不少次 MySQL 在 Windows 上的安装配置问题&#xff0c;5.5 版本又特别容易在服务…

作者头像 李华
网站建设 2026/9/30 3:44:09

CMPP2.0短信网关协议实战:从组包到状态报告处理

简介&#xff1a;这份PDF文档是中国移动短信网关通讯协议CMPP2.0的完整技术规范&#xff0c;面向从事短信业务开发的工程师、SP服务商技术人员及通信协议学习者&#xff0c;用于解决第三方平台接入中国移动短信网络时的接口对接与消息交互问题。文档系统梳理了协议的范围、缩略…

作者头像 李华