☰
SSH公钥认证与iTerm2配置:实现服务器免密登录的完整指南
2026/10/16 1:21:01 网站建设 项目流程

如果你和我一样,每天要在终端里敲几十次ssh user@server然后机械地输密码,这个标题大概率会直接戳中你的痛点。我当初被逼到研究免密登录,是因为连续几天在十几台服务器之间切换部署,每次都要翻密码本、复制粘贴、等认证,效率低到怀疑人生。后来花了半小时把公钥认证和 iTerm2 的 Profile 配合起来,从此打开终端、点一下、直接进服务器,密码彻底退出了我的日常操作。

这篇文章就是完整记录我在这套方案里的全部操作和踩坑过程。我会从最基础的公钥认证原理讲起,覆盖密钥生成、公钥部署、iTerm2 配置、常见报错排查,最后再补充几个让我实际体验提升一大截的进阶技巧。无论你是刚接触服务器运维的新手,还是已经用密码登录了好几年但一直懒得改造的老手,照着这篇文章走一遍,基本都能一次搞定。

1. 整体思路拆解:为什么用公钥而不是密码

1.1 密码登录的日常痛点

在讲方案之前,先聊聊我们为什么要折腾免密登录。密码登录本身不是不能用,但当你管理的服务器数量超过三台,或者有频繁的发布、日志查看、配置修改需求时,密码登录的体验会变得非常糟糕。

第一,密码本身是安全隐患。你在终端里输入的每一个字符,都有被键盘记录器、中间人攻击或者日志系统捕获的风险。很多人为了方便,还把密码直接写进便签、文档甚至聊天记录里,这就等于把服务器的钥匙贴在了门框上。第二,密码登录无法实现自动化。不管是写脚本批量执行命令,还是配合 CI/CD 工具做远程部署,密码交互都是最大的拦路虎——脚本一旦跑起来,可没法停下来等你输密码。第三,密码不好记。为了安全你不能用弱密码,为了省事你又不想记一大串复杂字符,于是很多人沦落到每台服务器一套密码,最后全忘了,只能反复重置。

1.2 公钥认证的核心原理

公钥认证的原理其实用一句话就能说清:你生成一对密钥——一把私钥自己保管,一把公钥放到服务器上。登录时服务器用公钥出一道只有私钥才能正确回答的题,你答对了,就放你进去。整个过程私钥永远不会在网络上传输,安全等级比密码高一个量级。

为了让完全没接触过的读者也有体感,我给个生活化类比。公钥和私钥的关系类似于印章和印泥:公钥是公开的印泥样张,任何人拿着它都没法伪造你的印章;私钥是你口袋里那枚独一无二的印章,只有盖出来的印记能和你留给服务器的样张对应上。服务器验证的东西不是"你知道某个秘密",而是"你持有一份能匹配的凭证",这个凭证本身就是数学上无法伪造的。

这种机制还有个额外好处:一旦服务器被入侵,攻击者拿到的也仅仅是公钥,他没法用公钥反向推导出你的私钥,更没法拿着公钥去别的服务器碰运气。这意味着你可以把同一把公钥放到多台服务器上,而不必担心密钥泄露导致所有机器同时失守。

1.3 为什么用 iTerm2 做载体

选 iTerm2 作为这套方案的落地载体,纯粹是因为它是 macOS 平台上最成熟、可定制性最高的终端模拟器。原生终端本身也能完成密钥登录,但它缺一个关键能力:Profile——你可以把一台服务器的登录信息、密钥路径、标签页样式全部固化成一个配置项,下次打开终端点一下就能直连。

这种"一键直达"的体验有多爽,用了才知道。我把常用的开发服务器、测试服务器、生产服务器全部配置成了不同的 Profile,每个 Profile 定义好了主机地址、用户名、私钥路径、初始目录,甚至标签页的颜色都不一样。我打开 iTerm2 只需要按一个快捷键呼出窗口,找到对应 Profile 双击,直接就是已登录的会话。中途断开重连也只是重新点一次的事,完全不用回忆 IP、不用搜密码、不用敲回车等认证。

2. 密钥生成:选对算法和参数,未来少踩坑

2.1 生成密钥的第一步准备

开始生成密钥之前,先检查你的 Mac 上有没有可用的命令行工具。macOS 自带的 OpenSSH 版本已经非常够用,不需要额外安装任何东西。你在终端里输入ssh -V能看到版本号,只要不是古董版本,后面的操作都没问题。

我习惯先创建一个专门的.ssh目录,虽然ssh-keygen会自动创建,但手动确认一下权限更稳妥:

mkdir -p ~/.ssh chmod 700 ~/.ssh cd ~/.ssh

.ssh目录的权限必须是700,也就是只有你自己能读写和执行。如果权限过于开放,SSH 客户端会直接拒绝使用里面的密钥文件,这在很多新手配置免密失败的原因里排第一。

2.2 选择密钥算法:推荐 ed25519

密钥算法选择是我特别想强调的一点。很多人一搜教程,看到的全是ssh-keygen -t rsa -b 4096,然后想都不想就照抄。这个选择不能说错,但放在 2025 年看,有更好的方案。

我目前所有新生成的密钥都用 ed25519 算法:

ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519

-t指定算法,-C是注释信息,通常写你的邮箱或用途,方便日后一眼认出是哪台机器、谁生成的公钥,-f指定密钥文件的保存路径。如果不指定-f,它会默认存成~/.ssh/id_ed25519并交互式地询问确认,指定之后可以完全跳过确认这一步。

为什么选 ed25519?首先它的密钥长度只有 256 位,但安全强度超过 RSA 4096。其次是生成和验证速度非常快,在你批量登录多台服务器时体感差异明显。第三是签名过程是确定性的,不像 RSA 那样依赖随机数生成器。如果你的服务器 OpenSSH 版本足够新(基本所有主流 Linux 发行版都支持),直接上 ed25519 没有任何问题。

那什么时候还用 RSA?我个人的判断标准是:如果服务器是那种用了十年没升级的老系统,或者网络设备、嵌入式 Linux 的 SSH 实现比较旧,才考虑生成 RSA 密钥兜底。但这种情况在 2025 年真的非常少见了。如果你非要生成 RSA,记得加-b 4096:

ssh-keygen -t rsa -b 4096 -C "your_email@example.com" -f ~/.ssh/id_rsa

2.3 关于 passphrase 的取舍

执行上面的命令后,终端会提示你设置 passphrase。很多教程会说直接留空,方便是方便了,但私钥文件本身是以明文存储在硬盘上的。如果 Mac 被拿到,攻击者拷走id_ed25519文件就能直接冒充你登录所有配置了公钥的服务器——想想都后背发凉。

我的建议是设置一个 passphrase,同时配合 macOS 的钥匙串(Keychain)把它记住。这样既不用每次登录都输一遍 passphrase,又能保证私钥在静止状态下是加密的。具体实现方式后面章节会详细说。

设置 passphrase 时的命令交互大致如下:

Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): ****** Enter same passphrase again: ******

2.4 生成后的文件检查

生成完成后,在.ssh目录下会多出两个文件:id_ed25519(私钥) 和id_ed25519.pub(公钥)。你可以用ls -l查看权限,私钥文件权限应该是600,也就是只有 owner 可读写。如果权限不对,立刻修正:

chmod 600 ~/.ssh/id_ed25519

公钥文件权限是644就正常。把公钥的内容打开看看,它长这样:

cat ~/.ssh/id_ed25519.pub # 输出类似于: # ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxxxxx your_email@example.com

这串内容就是你接下来要放到服务器上的全部东西。

3. 公钥部署:把公钥安全地放到服务器上

3.1 用 ssh-copy-id 一键部署

公钥生成好了,接下来就是把它放到服务器上。最省事的方式是用 macOS 自带的ssh-copy-id命令:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip

执行后,它会提示你输入服务器的登录密码。输对之后,它会自动完成三件事:在服务器的用户主目录下创建~/.ssh目录(如果不存在的话)、把公钥追加到~/.ssh/authorized_keys文件末尾、设置好应有的权限。

authorized_keys文件里每行对应一把公钥,所以你可以多次执行ssh-copy-id把多个设备的公钥都加进去。比如你在 Mac 和另一台笔记本上各生成了一对密钥,两把公钥都在这个文件里,两台设备都能免密登录这台服务器。

这个过程我第一次跑的时候觉得特别神奇——明明只是把一个文本字符串拷贝到远端某个文件里,但就是这短短一行字符,彻底取代了密码认证的整个逻辑。

3.2 手动部署公钥的方法

如果你的服务器是高安全要求的环境,禁用了密码登录,或者压根没装ssh-copy-id,那也没关系,手动三步就能搞定。

先把本地公钥内容复制到剪贴板:

pbcopy < ~/.ssh/id_ed25519.pub

然后用现有的可用会话登录服务器(哪怕是另一台允许密码登录的跳板机):

ssh user@server_ip

登录后在服务器上执行:

mkdir -p ~/.ssh chmod 700 ~/.ssh echo "粘贴你刚才复制的公钥内容" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys exit

有几个细节要注意。第一,>>是追加而不是覆盖,如果你在这台服务器上有多个设备的公钥,追加模式才不会把旧的搞没。第二,chmod 700 ~/.ssh和chmod 600 ~/.ssh/authorized_keys这两步必须做。OpenSSH 在认证时会严格检查这些文件的属主和权限,只要发现 group 或 others 有写权限,它就会拒绝使用这份公钥文件,宁可让你密码登录失败也不冒安全风险。第三,如果你在服务器上的 shell 不是 bash,注意~的展开是否正常,建议写成绝对路径/home/username/.ssh/authorized_keys更保险。

3.3 部署后的免密验证

公钥部署完成后,退出当前会话,重新尝试登录:

ssh user@server_ip

如果前面的操作没问题,现在应该直接进入服务器,不再询问密码。初次连接时如果碰到 "Are you sure you want to continue connecting (yes/no)?" 的提示,输入 yes 回车即可。这个提示是在询问你是否信任这台主机的指纹,确认一次后会写进~/.ssh/known_hosts,以后再连就不会再问了。

如果这一步已经免密成功,说明核心方案已经通了。接下来的 iTerm2 配置只是把这个过程固化成一个点击动作,属于体验层面的巨大提升。

4. iTerm2 Profile 配置:把免密登录变成一键直达

4.1 创建服务器专属 Profile

iTerm2 有个重要的功能叫 Profile,每个 Profile 可以保存一套完整的终端启动配置。我们为每台常用服务器建一个 Profile,把登录细节全部固化进去。

打开 iTerm2 后,按快捷键Cmd + ,进入 Preferences(偏好设置),切到 Profiles 标签页。点击左下角的加号新建 Profile,然后按下面的清单配置。

Name(名称):

  • 填写一个你能快速识别的名字,比如生产服务器-Web01或者直接写服务器用途。这个名称会出现在 Profile 列表里,所以别用难以分辨的 IP。

Command(启动命令):

  • 在 General 标签下找到 "Command" 这一行,默认是 "Login Shell",改成 "Command" 并填入:
ssh -i ~/.ssh/id_ed25519 user@server_ip

这里-i参数指定了私钥路径。如果你有多个密钥文件,或者服务器不是默认的 22 端口,适当扩展一下:

ssh -i ~/.ssh/id_ed25519 -p 22022 user@server_ip

Working Directory(工作目录):

  • 填/就行,反正登录后会切到服务器上自己的主目录,这个值在远程场景下基本没影响。

如果你希望打开这个 Profile 后直接执行某条远程命令,比如查看日志或者重启服务,可以在 ssh 命令后面接上命令:

ssh -i ~/.ssh/id_ed25519 user@server_ip -t "tail -f /var/log/nginx/access.log"

-t参数为了强制分配伪终端,否则在登录后直接执行命令时,某些交互式命令可能表现异常。

4.2 绑定快捷键实现真·一键登录

Profile 配置好之后,从菜单栏的 Profiles 列表里点击即可登录。但既然是资深摸鱼人,能少一步算一步。iTerm2 允许给每个 Profile 绑定一个快捷键。

在 Profile 的 General 标签里找到 "Shortcut Key" 选项,点一下然后按下你想要的组合键,比如Cmd+Shift+1对应第一台服务器,Cmd+Shift+2对应第二台。设置完成后,不管你在 iTerm2 的哪个界面,按一下快捷键,立刻打开新标签页并直连对应服务器。

这个体验我用了之后再也没回去过。以前开新终端窗口还要想一下"我这次要连哪个 IP来着",现在肌肉记忆直接按快捷键,窗口弹出时已经在服务器命令行界面了,那叫一个行云流水。

4.3 用颜色区分不同环境

如果你和我一样同时维护着开发、测试、生产多套环境,强烈建议给不同环境的 Profile 设置不同的标签页颜色,这能有效防止在错误的环境里执行命令。

还是在这个 Profile 的配置里,切到 Colors 标签,把 "Color Presets" 选一个你能区分的配色方案。比如我把生产环境配成红色系的主题,开发环境配成绿色,测试环境配成黄色。每次打开新标签页,瞄一眼颜色就知道自己在哪个环境里,不需要费力看 prompt 上的主机名。这个习惯在深夜操作的时候尤其救命——人的注意力在昏暗光线下容易下滑,清晰的视觉信号能大幅降低误操作概率。

4.4 利用命令别名把新服务器也收编

有时候你需要临时登录一台还没配 Profile 的机器,或者只想快速执行一个命令。这种情况下传统做法是敲完整的ssh user@ip,倒也不慢,但如果能配合 shell 别名会更顺手。

在~/.zshrc(macOS 现在默认 zsh)里加几行:

alias s1="ssh -i ~/.ssh/id_ed25519 user@192.168.1.10" alias s2="ssh -i ~/.ssh/id_ed25519 user@192.168.1.11" alias deploy="sh /path/to/deploy.sh"

这样在终端里输入s1就能直接进第一台服务器。搭配 iTerm2 的 Profile,基本上所有的高频操作都覆盖了。

4.5 把 passphrase 交给钥匙串

前面提到过生成密钥时设置了 passphrase,如果现在每次 ssh 登录都要输入一次 passphrase,那免密登录的意义就少了一半。解决方法是把私钥加进 ssh-agent,同时让 macOS 的钥匙串帮你记住 passphrase。

在~/.ssh/config里加上这一段:

Host * UseKeychain yes AddKeysToAgent yes IdentityFile ~/.ssh/id_ed25519

UseKeychain yes是 macOS 专属的选项,意思是:第一次使用这把私钥输入 passphrase 时,把 passphrase 存进系统钥匙串,以后自动解锁。AddKeysToAgent yes则会在每次成功解锁后把私钥加进 ssh-agent,使得后续连接不需要再反复验证 passphrase。

配置好之后,重启终端,重新 ssh 一次,输入一次 passphrase,勾选记住。之后所有免密连接的体验就完全丝滑了——不用输服务器密码,也不用输 passphrase。

5. 常见问题与排查技巧实录

5.1 免密不生效:Permission denied (publickey)

这是最常见的报错,看到它说明服务器拒绝了你的公钥认证请求,然后回退到密码认证阶段(如果你能看到密码提示的话)或者直接拒绝访问。排查顺序我建议这样来。

先确认你用的是不是正确的私钥。命令里显式加上-i参数:

ssh -i ~/.ssh/id_ed25519 -v user@server_ip

-v参数会输出详细的调试日志,里面有一行非常关键:Offering public key: ...后面跟着你正在使用的公钥路径。如果这里的路径不是你预期的那把密钥,大概率就是用了默认的id_rsa之类的过期密钥。

然后登录服务器检查authorized_keys文件的内容和权限:

ls -l ~/.ssh/authorized_keys cat ~/.ssh/authorized_keys

确认文件里确实有你的公钥,而且一行没有被意外截断。权限方面,~/.ssh必须是 700,authorized_keys必须是 600。

还有一个很多人忽略的问题:你连接服务器时用的用户名是否和公钥所属用户一致。比如你把公钥部署到了root用户的authorized_keys,但你登录时用的是普通用户deploy,那认证肯定失败。这不是配置问题,而是公钥和用户绑定的问题。

5.2 ssh-copy-id 卡在输密码环节反复失败

ssh-copy-id本质上是一次密码登录加一次公钥追加操作,所以如果密码登录本身被服务器禁止,这个命令必然失败。另外一点是ssh-copy-id默认复制的是~/.ssh/id_rsa.pub,但你的密钥可能是 ed25519,需要显式指定:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip

还有一个比较隐蔽的问题:如果服务器上已有的~/.ssh目录属主不是当前用户,甚至是被 root 占用的,ssh-copy-id会因为没有写权限而失败。这时需要登录服务器,手动修正属主:

sudo chown -R user:user ~/.ssh

5.3 免密之前都正常,突然某天失效了

这种"曾经能用,后来不行"的问题,九成出在服务器端的authorized_keys被动过。比如有人手动编辑过文件导致格式错误,或者做系统迁移时漏掉了这个文件。

还有一种可能:服务器开启了StrictModes,而你主目录或.ssh目录的权限被其他操作改松了。任何 group 或 others 的写权限都会导致公钥被拒。用下面的命令重置:

chmod 755 ~ chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys

另外,如果你改过本地known_hosts或者服务器的 host key 变了(比如重装了系统),也会出现 host key 不匹配的警告。这种情况 SSH 会拒绝连接以防范中间人攻击,解决方法是从本地known_hosts中删掉对应旧条目:

ssh-keygen -R server_ip

然后重新连接,接受新的 host key。

5.4 多台服务器共用一个 Profile 的管理思路

如果你的服务器数量很多,每台都建一个 Profile 可能让 Profiles 列表变得很长。我的经验是:高频操作的服务器用 Profile 精确定制,低频操作的统一走一个"默认" Profile,里面只写好默认用户和默认私钥路径,服务器 IP 留空,登录时手动补上。

另外,可以借助~/.ssh/config文件给服务器定义别名和连接参数,把 iTerm2 的 Profile 命令简化为:

ssh web1

~/.ssh/config的配置方式:

Host web1 HostName 192.168.1.10 User deploy IdentityFile ~/.ssh/id_ed25519 Port 22

这样本地 ssh 命令直接支持ssh web1,iTerm2 Profile 里的 Command 也只需要填ssh web1。服务器信息统一集中在config文件里管理,Profile 只负责固化这些快捷入口。这套组合对大批量服务器管理非常受用。

5.5 使用控制主连接加速批量操作

如果你经常在本地执行远程批量命令,比如同时给几十台服务器推送配置,每次建立新连接都会经历 TCP 握手、版本协商、密钥交换,速度慢且开销大。SSH 有个很实用的特性叫 ControlMaster,它让多路连接复用一个主连接,后建立的通道直接走已有的加密隧道。

在~/.ssh/config里配置:

Host * ControlMaster auto ControlPath ~/.ssh/controlmasters/%r@%h:%p ControlPersist 10m

然后创建控制目录:

mkdir -p ~/.ssh/controlmasters

第一台服务器连接建立后,接下来的连接几乎零延迟,因为这个连接直接复用前面已建立的。这个方案特别适合在循环脚本里反复 ssh 的场景,时间可以从几分钟压缩到几秒。

6. 进阶技巧:把终端体验再拉高一个台阶

6.1 用 Expect 脚本临时处理无密钥的老服务器

不是所有服务器都能立刻接受公钥认证的。有些老服务器上的 OpenSSH 版本太低,不支持 ed25519;有些是网络设备,公钥认证的配置方式完全不同。遇到这种场景,如果实在需要频繁登录,可以临时用脚本处理密码输入。

macOS 上一般没有expect,需要通过包管理工具安装。装好之后写一个最简单的脚本,把用户、密码、IP 三个变量填进去,然后expect会自动完成密码的交互输入。但我要提醒一句:脚本里明文保存密码有风险,这个方案只适合零时救急,不适合日常依赖。

6.2 配合跳板机的免密登录

当网络环境不允许直连目标服务器,必须通过跳板机中转时,公钥认证同样能发挥作用。最简单的做法是把你的公钥同时部署到跳板机和目标机上,然后手动先登录跳板机,再从跳板机登录目标机。但这样每次都要敲两条命令,比较繁琐。

更好的做法是利用ProxyJump。在~/.ssh/config中配置:

Host target HostName 10.0.0.5 User deploy ProxyJump jump_user@jump_ip

然后直接ssh target,SSH 会先连跳板机,再通过跳板机转发到目标机。两段连接都可以走公钥认证,全程无密码、无额外操作。这在管理内网机器时是大杀器。

6.3 为每次登录自动执行初始化命令

登录服务器后,我通常希望它自动切到项目目录、加载环境变量、显示最近日志。这可以用 Profile 的 Command 配合远程命令实现:

ssh -t user@server_ip "cd /var/www/project && ls -la && exec bash"

-t强制分配伪终端,exec bash保证远程命令执行完不会立即断开会话,而是保留在服务器上继续操作。这种方式比登录后手动敲cd高效得多,而且可以让每个 Profile 定制不同的初始化动作。

6.4 定期轮换密钥的习惯

公钥认证方便归方便,但也带来一个问题:一旦私钥泄露,影响范围是所有配置了这把公钥的服务器。所以我养成了定期轮换密钥的习惯,半年到一年换一次,或者一发现有可疑行为立刻换。

轮换流程很简单:生成新密钥、把新公钥部署到服务器、移除旧公钥。如果服务器数量多,逐个改确实辛苦,但这是安全底线。另一个更稳妥的做法是给每台服务器用不同的密钥对,这样单把私钥泄露最多影响一台机器。缺点是管理成本变高,适合高安全要求的场景。

7. 安全和备份建议

7.1 私钥的备份与恢复

我在前面说过私钥文件是明文存储的(除非配置了 passphrase)。所以私钥的备份一定要加密。我的习惯是把~/.ssh目录整体打包,放进加密的离线存储里,比如冷备份硬盘或者专门的加密容器。备份内容包括私钥、公钥、known_hosts和config。这样即使 Mac 完全损坏,新机器上解压备份、改好权限就能无缝恢复所有 SSH 配置。

恢复后记得检查密钥文件的权限,尤其是私钥文件,必须600。

7.2 生产环境的最小权限原则

生产服务器上,建议不要用 root 账号做日常登录。更好的实践是创建一个专用部署用户,把公钥部署到这个用户下,然后通过sudo命令临时提权。这样可以在审计日志里看到每个操作的执行者,出事之后有据可查。AllowUsers和PermitRootLogin等配置项按需收紧,不给无关账号留入口。

7.3 定期检查 authorized_keys

服务器上authorized_keys应该不定期检查一下,看看里面有没有你不知道的公钥。如果发现异常,立刻删除对应行并排查来源。很多服务器被入侵后,攻击者做的第一件事就是写入自己的公钥,为以后随时进入留后门。这个检查操作不复杂,但价值非常大:

cat ~/.ssh/authorized_keys

对照每行公钥末尾的注释信息,确认是不是自己放的。发现可疑公钥后先移除,再查登录日志:

last -f /var/log/wtmp

看看有没有可疑 IP 的登录记录。这套"日志 + 密钥审计"的组合,建议每月至少做一次。

8. 最后再分享一点我的个人体会

做完整套配置之后,我最大的感受是:以前服务器登录这件事是在"消耗专注力",现在变成了"无意识动作"。我不再需要把 IP 和密码从文档里翻出来,也不需要在登录过程中被安全警告打断思路。专注力这种东西,在运维和开发工作中比什么都宝贵,省下那些碎片化的等待和输入,一年累积下来是很可观的。

如果你还没动手,我建议不要一次性想搞清楚所有原理再操作。直接照着第 2 步和第 3 步生成密钥、部署公钥,先跑通免密登录,然后再花十分钟配置 iTerm2 的 Profile。这套组合拳下来,以后再登录服务器,基本就是打开终端、连上、干活,干净利落。

我第一次配置的时候也踩过不少坑,比如生成密钥时忘了设置 passphrase、公钥复制到服务器时多复制了一个换行符、iTerm2 的 Command 里没写-i导致用了错误的私钥……这些坑我在文章里已经尽量帮大家标清楚了。如果你照着做还是遇到问题,优先看第 5 节的排查思路,多试几次,慢慢就会有自己的手感。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询