在 Mac 下用 iTerm 管理服务器,最烦的就是每次 SSH 登录都要敲密码。特别是手上有三五台服务器,或者经常要上跳板机再转内网机器的时候,来回输密码简直就是折磨。折腾过密钥登录、自动登录脚本、Profile 配置之后,我现在的日常就是双击一个 iTerm Profile,秒进服务器,全程无感。
这篇就聊聊我实际配置下来的完整流程和踩过的坑,从生成密钥到 iTerm 侧怎么写配置,再到排查免密失效的各种原因,一次讲透。
1. 免密登录方案怎么选
先理清一个概念:SSH 免密不是“不需要认证”,而是把认证方式从密码换成了密钥对。你的 Mac 上放私钥,服务器上放公钥。连接的时候客户端用私钥签名一段挑战数据,服务器用公钥验证签名。只要能对上,连接就建立,不需要你手动输密码。
这个机制有几个基本逻辑比密码登录合理得多:
- 密码每次都要手动输入,还怕被暴力破解。密钥是一串 2048 位甚至 4096 位的随机数,暴力破解的难度不在一个数量级。
- 密钥可以设置 passphrase,即使私钥文件被拷走,没 passphrase 也用不了。
- 服务器上可以针对不同来源 IP、不同用户、不同密钥做精细控制,运维上的可管理性很强。
在 iTerm 上实现免密登录,常见的做法有这么几种:
一是直接把ssh user@host写进 Profile 的 Command,配合密钥自动登录。这是最干净、最常用的方式。前提是把密钥配置到位。
二是用expect脚本自动填密码。这个方案本质还是用密码,只不过脚本帮你敲。好处是密钥没配好时能应急,缺点是密码明晃晃写在脚本里,安全上不太讲究。
三是用 iTerm 的 Trigger 功能,检测到 "password:" 关键词后自动发送密码。这个更 hack,只适合临时用,但不推荐作为长期方案,而且 iTerm 的 Trigger 对输出内容敏感,网络慢或服务器 banner 变化时容易失效。
我的建议很简单:正常场景,优先把密钥配好,然后用 Profile 直接拉起 SSH。只有密钥配置不上、又急着连服务器排查问题时,才用 expect 脚本兜底。
2. 本地生成密钥对
大部分 macOS 自带的 OpenSSH 版本都比较新,直接用ssh-keygen生成密钥即可。我习惯用 Ed25519,签名短、性能好、安全性足够。如果碰到老服务器,比如 OpenSSH 版本很旧,可能只支持 RSA,那时再用 RSA 2048/4096 也不迟。
打开终端执行:
ssh-keygen -t ed25519 -C "macbook-air"-C参数通常填一个备注,作用是当你一台 Mac 有多个密钥时,能看出哪个是哪个。比如 "macbook-pro-2023"、"office-desktop" 这种。
执行后会有几个交互问题:
Generating public/private ed25519 key pair. Enter file in which to save the key (/Users/你的用户名/.ssh/id_ed25519): Enter passphrase (empty for no passphrase):默认保存路径直接回车即可。接下来会让你输 passphrase,这个可以理解为私钥的使用密码。
这里我建议填一个,别留空。理由很实际:私钥文件本身是可被拷贝的。有人拿到你的私钥文件,没有 passphrase 的话在其他机器上直接就能用;有 passphrase 的话,无论如何都要多一道保护。缺点是每次 SSH 都要输 passphrase,体验会打折。解决办法后面说。
生成完成后目录里会多两个文件:
id_ed25519:私钥,留在本地。id_ed25519.pub:公钥,要传到服务器上。
私钥的权限必须是只有自己可读写,macOS 下 SSH 对此非常严格。权限不对会直接拒绝使用。补一道检查:
ls -l ~/.ssh/id_ed25519正常输出应为-rw-------,用户名是你自己。如果不对,执行:
chmod 600 ~/.ssh/id_ed25519有一个很典型的问题:有人会在服务器上生成密钥对,然后把私钥下载回 Mac。这是反向搞法,风险是私钥留在服务器上,而服务器的安全可控性通常不如本地。正确姿势永远是本地生成,本地留私钥,服务器只放公钥。
3. 公钥上传到服务器
密钥生成完,公钥要追加到服务器上目标用户家目录的~/.ssh/authorized_keys文件里。
首选方式是ssh-copy-id,macOS 默认自带这个命令。用法:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip执行后按提示输入服务器密码。验证成功后,公钥内容会被自动追加到服务器上对应用户的authorized_keys文件末尾,并自动创建、修正目录权限。
ssh-copy-id做的事情其实很简单,但它能避免很多权限坑。它会把~/.ssh目录权限设为 700,authorized_keys文件权限设为 600。这两个权限不对,SSH 服务器会拒绝使用密钥登录。
如果你不想用ssh-copy-id,手动操作也完全可以。先打印公钥内容:
cat ~/.ssh/id_ed25519.pub得到一个长字符串,大概长这样:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... macbook-air把它复制到剪贴板,然后登录服务器,编辑~/.ssh/authorized_keys:
mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... macbook-air" >> ~/.ssh/authorized_keys这里要提醒一句:追加用两个大于号>>,千万别写成一个大于号>,一个大于号会把整个文件覆盖掉。如果服务器上已经配置过其他人的公钥,一覆盖全没了。
上传完成后,本地先测试一下:
ssh -i ~/.ssh/id_ed25519 user@server-ip如果顺利,直接进入系统,不需要密码。如果不顺利,大概率是权限问题或者服务配置问题,下面第 5 节细讲。
4. iTerm 侧配置实战
密钥通了之后,免密登录已经能用,接下来把它固化到 iTerm 的 Profile 里,让每次打开一个 Tab 就自动进服务器。
打开 iTerm 的设置界面,路径是Preferences->Profiles。点击左下角的加号新建一个 Profile,或者复制默认 Profile 后单独改。
在General标签下找到Command一栏。默认是Login Shell,也就是普通登录你的 Mac shell。要变成自动 SSH,就改为Command,然后在输入框里写:
ssh -i ~/.ssh/id_ed25519 user@server-ip如果密钥文件名就是默认的id_ed25519,可以不用显式加-i,因为 SSH 会默认寻找这个文件。但有时候你有多把密钥,或密钥文件名不标准,显式指定更稳妥。
Profile 的名称改成服务器用途,比如web-prod、db-backup、jump-host。这样在 iTerm 的Profiles下拉菜单里一眼能认出对应哪台机器。
日常使用中,我还会在Keys标签里配置快捷键,直接一键开新 Tab 连指定服务器。比如 Ctrl+Cmd+1 连 web 服务器,Ctrl+Cmd+2 连数据库服务器。这个看个人习惯,配置好后挺省事的。
如果你设置了 passphrase,直接启动 Profile 会卡在 passphrase 输入。有两个解决办法。
一是把 passphrase 加进 macOS 的钥匙串。macOS 可以自动记住私钥的 passphrase,具体需要用到ssh-add配合密钥,配合系统钥匙串机制。方法是这样:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519这条命令会把私钥加载进系统的 SSH Agent,并把 passphrase 存入钥匙串。第一次加载时还是会问一次 passphrase,之后重启电脑再 SSH,系统会直接从钥匙串读取,不再手动输入。
如果你用的是 zsh 或 bash,可以配合加载本地 Agent 的辅助脚本,但默认场景下直接执行ssh-add --apple-use-keychain就够了。
二是干脆不用 passphrase。体验最好,安全隐患稍微大一点点。自己权衡,我不评价,只提示风险。
比较实用的做法是:个人电脑日常登录不设 passphrase,方便为主;公司或敏感服务器相关的密钥设置 passphrase,并用钥匙串管理。
还需要注意一个细节:默认 Profile 里的Login Shell如果被改成 Command,那这个 Tab 就不再有本地 shell 了,只有远程 shell。如果你有时候想在同一窗口先待本地环境,而不是直接进服务器,就不适合把默认 Profile 改成 SSH。我习惯新建专用 Profile,保留默认 Profile 作为本地环境。这样互不干扰。
iTerm 的配色和字体也可以针对不同 Profile 单独设置。比如生产服务器用红色提醒,测试环境用绿色。看多了就不容易搞混,虽然这属于锦上添花,但确实影响了日常操作体验。
5. 免密登录失效排查手册
密钥配好了,iTerm 也写好 Command 了,结果一打开还是跳密码,或者直接报 Permission denied,这种时候要快速定位问题。按下面几条挨个查,基本都能解决。
5.1 本地私钥身份没加载
如果启动 Profile 后提示:
Enter passphrase for key '/Users/xxx/.ssh/id_ed25519':说明 SSH 在问 passphrase,但系统里没有缓存。确认刚才的ssh-add --apple-use-keychain是否执行过。也可以手动确认 Agent 里有哪些密钥:
ssh-add -L如果列表为空,说明 Agent 没加载。重新执行ssh-add --apple-use-keychain ~/.ssh/id_ed25519再试。
5.2 服务器端 authorized_keys 内容不对
最常见的原因是公钥内容拷贝不全、格式不对、文件换行符问题。
确认方法是去服务器上看文件内容:
cat ~/.ssh/authorized_keys期望每行是一条公钥,以ssh-ed25519或ssh-rsa开头,后面一大串字符,最后跟备注。如果看到公钥被截断,或者被粘贴成了多行,就会认证失败。
还有个容易踩的坑:有些人为了“好看”会在公钥里手动加换行、加空格,结果就是密钥无法匹配。公钥是一个完整的字符串,不能格式化。
5.3 权限问题
服务器上.ssh目录和文件权限不对,即使公钥内容正确,SSH 服务也拒绝。
检查三处:
ls -ld ~/.ssh ls -l ~/.ssh/authorized_keys ls -ld ~正常值如下:
~不能是其他人可写~/.ssh权限 700~/.ssh/authorized_keys权限 600
如果权限过松,直接修正:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys5.4 sshd 配置限制
如果服务器上 sshd 配置了禁用了公钥登录,或者禁用了 root 登录,密钥再正确也没用。
从本地查服务器 sshd 配置:
ssh -vv user@server-ip如果调试输出里出现Authentications that can continue: password而没有publickey,极大概率是服务端关闭了公钥认证。需要登录服务器后检查/etc/ssh/sshd_config:
PubkeyAuthentication yes修改后重启 sshd。这个操作要有服务器管理权限,注意修改前备份配置。
5.5 连错用户或地址
有时候问题很简单:iTerm Profile 里写的是root@host,但公钥其实是放到deploy用户下的。SSH 对用户是隔离的,root 用户下的authorized_keys里没你的公钥,就会失败。
排查时用ssh -v或-vv模式确认实际连接的用户和目标端口。
5.6 多密钥导致的选择错误
服务器上装了多把公钥,本地也放了多个私钥,SSH 默认会尝试多个私钥。如果本地私钥太多,认证顺序可能会出问题。这里建议在 Profile 里显式指定-i参数,并且在~/.ssh/config里配置规则。
~/.ssh/config是管理多服务器和密钥很趁手的工具。我贴一个常用配置示例:
Host web-prod HostName 192.168.1.101 User deploy IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 Host jump HostName jumphost.example.com User admin IdentityFile ~/.ssh/id_rsa_office配置完,iTerm Profile 的 Command 简化为:
ssh web-prod维护起来比在 Profile 里写完整 IP 和用户名方便太多。
6. 多台服务器与跳板机的实战配置
实际场景中,很多人不是只连一台机器。可能有一台云主机做应用,一台内网机器做数据库,还可能先要登录跳板机再 SSH 到内网机器。iTerm + SSH 的这套玩法要能顺畅工作,还得处理好这几个问题。
6.1 多 Profile 方案
我推荐一个 Profile 对应一个目标环境。一台服务器建一个 Profile,甚至一个“通过跳板机转发”的连接也可以单独建 Profile。这样服务器启动时直接连接对应的别名的命令即可。
比如:
- Profile
web-prod执行ssh web-prod - Profile
db-prod执行ssh db-prod,但在~/.ssh/config里db-prod配置为通过跳板机转发
iTerm 支持把多个 Profile 放在不同文件夹里,比如开发环境、测试环境、生产环境分开。这一步在Profiles设置左侧直接拖动即可管理,很方便。
6.2 简化跳板机登录
从 Mac 连跳板机,再从跳板机连内网机器,SSH 有一个叫ProxyJump的功能,不用手动登录跳板机再敲命令。
~/.ssh/config里这样写:
Host jump HostName 203.0.113.10 User admin IdentityFile ~/.ssh/id_ed25519 Host internal-db HostName 10.0.0.5 User deploy ProxyJump jump IdentityFile ~/.ssh/id_ed25519然后 iTerm Profile 里直接ssh internal-db,SSH 会自动先连jump,再通过跳板机转发到10.0.0.5。整个过程不额外输密码(前提是跳板机上也有你的公钥)。
本地如果设置过 passphrase 并加入了钥匙串,这个多跳过程也会自动完成。体验非常顺。
这个 ProxJump 比旧式的-t ssh ...嵌套命令要干净得多,不会出现终端里多出交互 shell 的混乱状态。能直接用ProxyJump的地方就别用老式转发。
6.3 配合传文件
密钥登录打通后,scp和sftp也一并免密了。比如把本地目录传到服务器:
scp -r ./dist user@server:/data/web/用 iTerm 的新 Tab 拉起来,命令行直接执行即可,不需要额外的 FTP 客户端。密钥对 iTerm 下所有 SSH 系命令都生效,这是公钥免密带来的附加收益。
7. 安全和维护建议
免密方便是方便,但安全底线不能丢。提几个维护建议。
第一,私钥就是你的身份凭证。私钥文件不要放到网盘、邮箱、聊天工具里传。id_ed25519这类文件拷贝到其他机器时,一定要确保目标环境可信。
第二,定期更新服务器上的authorized_keys,移除离职同事或者不再使用的密钥。服务器上公钥一多,管理就乱了,最好有一个统一的追加和清理流程。
第三,修改服务器端口、限制 SSH 来源 IP、配置 Fail2Ban,这些和密钥免密并不冲突。密钥解决的是认证强度,IP 限制解决的是暴露面。两者结合起来才靠谱。
第四,多台服务器之间如果跳转频繁,设置好ServerAliveInterval(比如 60 秒),能避免 SSH 连接因为长时间空闲被服务端断开。在~/.ssh/config的通用配置里加一行:
Host * ServerAliveInterval 60 ServerAliveCountMax 3这样连接保持得更稳定,尤其在 iTerm 里长时间挂着一个 Tab 的场景,很实用。
第五,如果对安全性有更高要求,可以考虑把 4096 位 RSA 或 Ed25519 密钥存到 YubiKey 之类的硬件令牌上。不过这属于进阶玩法,日常用不上,知道有这层方案就行。
8. 几个强迫症级别的提升技巧
配置到这一步,基本够用了。再补充几个提升体验的点,适合日常重度使用终端的人。
一是 iTerm 的Trigger。在某些特殊场景下,比如密钥认证失败降级到密码登录时,服务端会打印password:,这时可以加一条 Trigger 规则,自动输入密码。但说实话,我实际用下来发现这个方案不稳定,因为触发时机和输出匹配很难控制。建议还是把密钥配置本分做好。
二是 Profile 的标签颜色和图标。给不同环境添加颜色以后,瞟一眼标签页背景色就知道是开发机还是生产机。比如生产环境设置红色标签,内网测试机用灰色。这种配置在Preferences->Profiles->Colors里调整即可。
三是窗口还原和布局。Arrangements功能可以保存一整组 Tab 或窗格。我习惯开机后直接还原一套工作区:左上是 web 服务器的 SSH,左下是数据库服务器的 SSH,右边是本地 shell。配合密钥免密,还原后所有 SSH Tab 都自动连上,直接开工。
四是定期检查已认证的密钥列表。用ssh-add -L确认当前 Agent 里加载了哪些私钥,防止误加载了不该用的密钥。
我在实际折腾这套东西的过程中,最大的感悟是:密钥免密本身不算难,难的是把它打磨成一套“无感”的日常流程。生成密钥、上传公钥、配置 iTerm Profile 这三步搞定后,后面的价值是把~/.ssh/config和 iTerm 的 Profile 结合好,让连接目标变成一个个可信的别名,而不是一长串地址和用户名。最后再分享一个小技巧:如果你经常在同一个 iTerm 窗口里开多个连接,可以按住 Cmd 点击 Profile 或使用键盘快捷键,新连接会在新 Tab 中打开,原标签页不会被覆盖。用顺手之后,终端就是你的主力工作台,效率提升不是一点半点。