GitHub 配置 SSH key 这件事,听起来简单,网上一搜一大把教程,无非就是ssh-keygen一路回车,把公钥粘到网页上,完事。但真到了实际开发里,各种问题就会冒出来:连接报Permission denied、换电脑后密钥失效、一台机器要同时用 GitHub 和公司 GitLab、甚至同一台电脑上要管理多个 GitHub 账号。我当初第一次配的时候也踩过不少坑,所以干脆把整个流程——从原理、实操到排查——完整梳理一遍。这篇东西聚焦于 GitHub 配置 SSH key 的核心技术和完整流程,既适合第一次接触 SSH 的新手照着一步步操作,也适合已经配过但遇到问题、想弄明白背后原理的同学。
1. 为什么要配 SSH key:先搞懂认证这件事
1.1 SSH 协议与密钥认证的基本原理
很多人把 SSH key 当成一种"登录凭证",这个说法方向对,但不够准确。SSH key 本质上是一对非对称加密密钥:一把私钥(id_ed25519)和一把公钥(id_ed25519.pub)。私钥保存在你自己电脑上,永远不要给别人;公钥则可以公开,你可以把它放到 GitHub、GitLab、服务器上,随便放。
整个认证过程可以打个比方:你把一把锁(公钥)挂在门口,用你自己的钥匙(私钥)开门。服务器端只存了你的公钥,当你用私钥和服务器握手时,服务器会验证"这把钥匙能不能打开这把锁",能打开就放行。因为私钥从不离开你的电脑,所以整个过程不需要输入密码,也不需要把敏感信息在网络上传送。
具体的握手流程比这个类比略复杂:客户端发起连接后,服务器会生成一个随机挑战,用你存的公钥加密,客户端收到后用私钥解密并返回结果,服务器验证通过就完成认证。期间还会涉及主机密钥验证(known_hosts)来确认服务器身份,防止中间人攻击。这部分不用背下来,但理解它有助于你后续排查问题,尤其是后面要讲的Host key verification failed报错,以及"为什么要验证 host key"这种疑问。
1.2 为什么推荐用 SSH 而不是 HTTPS
GitHub 提供了两种主要协议来拉取和推送代码:HTTPS 和 SSH。早期大家习惯用 HTTPS,因为简单,clone 下来直接输账号密码就行。但 2021 年 8 月之后,GitHub 完全停止了在 HTTPS 推送时对密码的支持,改成了个人访问令牌(Personal Access Token)——说白了,你 push 的时候还是要输一串很长的 token,而且 token 有过期时间,过期后又得重新生成。
SSH 相比之下有明显的优势:一次性配置,永久免密。公钥加到 GitHub 之后,你日常的 clone、push、pull 都不需要再输入任何密码,体验非常顺滑。安全性上也更稳:HTTPS 传输的是 token,每次都要经过网络,一旦终端被记录键盘输入或抓包,token 就有泄露风险;而 SSH 的私钥不出本地,认证过程由加密协议保证,安全性高出一截。
从实际体验来说,如果你经常用git clone拉项目、频繁 push 代码,配好 SSH 之后那种"不用再输 token"的爽快感是非常直接的。这也是 GitHub 官方文档把 SSH 作为推荐方式的原因之一。
2. 动手生成密钥:一条命令背后的参数含义
2.1 先选密钥类型:Ed25519 还是 RSA
现在生成 SSH key,第一步不是直接敲命令,而是想清楚用什么算法。很多旧教程还在教大家用ssh-keygen -t rsa -b 4096,这确实是通用方案,兼容性极好,那些还在跑老版本 OpenSSH 的老服务器基本都能认。如果你是给公司内部很老旧的 GitLab 或服务器配,用 RSA 4096 是稳妥的选择。
但如果是面向 GitHub 这类主流平台,我更推荐用ed25519。理由很直接:密钥更短、生成速度更快、安全性更高,而且 GitHub 早就完整支持了。你不用担心ed25519不兼容的问题,现在所有主流系统自带的 OpenSSH(7.0 以上)都内置了支持,除非你用的是一个九十年代的老系统。
我自己目前所有新密钥都统一用 ed25519,只有在连接某些老设备时才会单独生成 RSA 4096 作为备用。这里也顺带提一句:-b参数代表密钥位数,RSA 至少要用 4096,1024 已经被证明不安全了,2048 算是底线,但找谁可靠?直接 4096。ed25519 的位数是固定的,不用指定-b。
2.2 完整生成步骤与指纹验证
生成命令很简单:
ssh-keygen -t ed25519 -C "你的注释信息"-C参数是注释(Comment),通常填邮箱地址,方便你在 GitHub 上辨认这把密钥是给哪台电脑、哪个平台用的。不填也行,默认会加上"用户名@主机名"。
执行后系统会问你保存路径,默认是~/.ssh/id_ed25519。如果你本机之前没生成过密钥,直接回车用默认路径最省事。后面如果有多密钥需求,再考虑自定义文件名。
接着它会问你是否设置 passphrase(口令)。这个点我多说两句:passphrase 不等于密码,它是私钥文件本身的加密口令。你设置之后,每次使用私钥都要输入这个口令。现在 macOS 和 Windows 都支持把私钥保存到系统钥匙串里,配合 ssh-agent 后,设置为空或填入系统钥匙串都是不错的选择。如果你是安全敏感场景(比如笔记本可能丢失),建议设置一个,否则私钥文件本身暴露出去就危险了。
生成完后,目录下会多出两个文件:id_ed25519和id_ed25519.pub。前者是私钥,后者是公钥。你可以用下面命令查看公钥内容:
cat ~/.ssh/id_ed25519.pub输出的内容以ssh-ed25519开头,一长串 base64 编码字符,最后是你刚才填的注释,整体看起来像这样:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBo........(省略) your_email@example.com如果你想验证刚刚生成的密钥到底对不对,可以查看指纹(fingerprint):
ssh-keygen -lf ~/.ssh/id_ed25519.pub它输出一串SHA256:...格式的指纹,这串指纹在你后续把公钥添加到 GitHub,第一次连接确认主机时会看到,可以用来比对是否一致。
3. 把公钥交给 GitHub:添加与验证全流程
3.1 复制公钥的三种方式
公钥生成好了,接下来要把它放到 GitHub 账号里。第一步是把公钥内容复制出来。这里有几种常见方式,按你当前使用的系统选即可:
- 在终端直接
cat ~/.ssh/id_ed25519.pub,然后用鼠标选中复制。好处是所见即所得,坏处是长字符串容易漏掉几个字符。 - 用
pbcopy < ~/.ssh/id_ed25519.pub(macOS 专用)直接复制到剪贴板,省去手动选中的麻烦。 - Windows 下用
clip < ~/.ssh/id_ed25519.pub(需要 PowerShell 或 CMD 环境),效果一样。
我个人的习惯是:复制完公钥后不要马上粘贴到网页,先在文本编辑器里看一眼,确认它是以ssh-ed25519或ssh-rsa开头,再结尾那串注释也别删,没影响。因为公钥里有换行符的话,粘贴后 GitHub 会当作格式错误,提示 "Key is invalid"。
3.2 在 GitHub 网页端配置与连接测试
复制好公钥后,登录 GitHub,按以下路径操作:
- 点击右上角头像,选择Settings。
- 在左侧菜单中找到SSH and GPG keys。
- 点击New SSH key(新建 SSH 密钥)按钮。
- Title 字段填一个你自己好记的名字,比如
MacBook Pro 2024或Home Desktop,本质就是一个备注,帮助你之后知道这把公钥放在哪些设备上。 - Key 字段粘贴刚才复制的整行公钥内容,注意不要有多余空格或换行。
- 点击Add SSH key,提示可能需要输入一次 GitHub 密码确认操作。
完成后,就可以在终端里测试连接了。GitHub 官方提供了一个专门的测试命令:
ssh -T git@github.com第一次连接时,SSH 会询问你是否信任这台主机,问你Are you sure you want to continue connecting (yes/no)之类的问题。输入yes回车,它会将 GitHub 的主机指纹写入~/.ssh/known_hosts,以后不会再问。
如果密钥配置正常,你会收到类似这样的输出:
Hi your_username! You've successfully authenticated, but GitHub does not provide shell access.看到这行字就说明认证成功了。这里有个小细节:GitHub 不允许通过 SSH 获得 shell 登录权限,所以即使认证成功也不会给你一个终端。这个提示是正常现象,不是报错。
如果你配置了多个密钥,这里 SSH 会逐个尝试身份文件,直到通过验证。如果测试连接时输出的用户名不是你预期的那个账号,说明 SSH 可能用了另一把密钥,这时就要用到后面讲的配置文件了。
4. 多账号、多平台下的密钥管理实战
4.1 什么时候需要多把密钥
很多人觉得"一把密钥走天下"最方便,实际场景中完全不是这样。最常见的需求有几种:
第一种,同时使用 GitHub 和公司 GitLab。部分公司会要求统一使用公司发的密钥,或者你不想把个人密钥带到公司电脑上,这时候就需要给 GitHub 和 GitLab 分别生成独立的密钥。
第二种,同一台电脑上有多个 GitHub 账号。比如一个私人账号,一个接外包或公司用的账号。如果把两把公钥加到同一个电脑的默认位置(~/.ssh/id_ed25519),后加的那把会覆盖之前的默认密钥,导致其中一边失效。
第三种,不同安全等级的密钥分开管理。比如对内对外用不同密钥,或为了实验方便把旧密钥单独建档。虽然这种情况不多,但多密钥管理的技能是通用的。
我的建议是:不要长期依赖一把通用密钥,至少学会用~/.ssh/config来区分不同主机。这个文件就是 SSH 客户端的"路由表",告诉它连接哪个地址时用哪把密钥。
4.2 用 ~/.ssh/config 管理多密钥的完整写法
~/.ssh/config文件默认不存在,需要你自己创建。创建前先确保~/.ssh目录存在:
mkdir -p ~/.ssh chmod 700 ~/.ssh然后编辑~/.ssh/config,常见配置如下:
# 默认 GitHub 个人账号 Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_personal # 公司 GitLab Host gitlab.company.com HostName gitlab.company.com User git IdentityFile ~/.ssh/id_ed25519_company # 另一个 GitHub 账号(通过别名访问) Host github-work HostName github.com User git IdentityFile ~/.ssh/id_ed25519_work关键点在于IdentityFile指向你为特定场景生成的私钥文件。Host这个名字很关键,它会成为你在 clone 时使用的别名。
举个例子,当你想 clone 一个使用github-work别名的 GitHub 仓库时,命令要写成:
git clone git@github-work:your_work_username/repo.git如果你直接用默认的git@github.com,SSH 会按第一条规则匹配,使用个人账号的密钥,而不会自动切换到工作账号。
还有一点值得注意:同一把公钥可以同时添加到 GitHub 和 GitLab。也就是说你不一定需要每加一个平台就生成一把新密钥。我自己的做法是:个人电脑的核心密钥就一把,用于个人 GitHub 和部分自建服务器;公司电脑另生成一把,专门用于公司 GitLab 和对应 GitHub 工作账号。互不交叉,丢了也不影响另一边。
4.3 让 ssh-agent 帮你记住密钥
如果你给私钥设置了 passphrase,那每次 push 和 pull 都会要求输入口令,这就有点烦人了。解决办法是使用ssh-agent,它是 OpenSSH 自带的一个后台服务,专门帮忙管理私钥,把解密后的密钥存在内存里,后续连接直接使用,不用反复输入 passphrase。
启动和添加密钥的操作:
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519macOS 还支持把 passphrase 存进钥匙串,之后 app 或终端调用时就不再询问:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519Windows 的话,如果你用的是 Git Bash 或 PowerShell,也可以使用ssh-add,但需要先确认ssh-agent服务已开启。在管理员的 PowerShell 里执行:
Get-Service ssh-agent Set-Service ssh-agent -StartupType Automatic Start-Service ssh-agent设置好后,终端里当前用户会话内 SSH 连接都不需要重复输入 passphrase,体验和完全无口令差不多。安全上也有个提醒:ssh-agent会一直在后台跑,如果你在多用户共用的机器上使用,记得用完ssh-add -D清空代理里的密钥。
5. 常见问题与排查技巧
5.1 高频报错速查表
配 SSH key 的过程中,最打击新人的通常是那几个看起来莫名其妙的报错。我整理一下我遇到过的和群里朋友遇到过的常见问题,直接做成速查表格:
| 报错信息及场景 | 可能原因 | 解决方法 |
|---|---|---|
Permission denied (publickey) | 服务器端没有对应公钥,或本地用了错误的私钥 | 检查公钥是否已正确粘贴到 GitHub;用ssh -vT git@github.com看详细日志,确认使用了哪把私钥 |
Host key verification failed | 本地 known_hosts 里没有 GitHub 的主机指纹,或指纹不匹配 | 如果是首次连接,输入yes接受即可;如果提示不匹配,可能是中间人风险或 known_hosts 被篡改,删掉对应行后重新连接 |
Bad owner or permissions on ~/.ssh/config | OpenSSH 拒绝加载权限过宽的文件 | 设置正确权限:chmod 600 ~/.ssh/config,目录保持 700 |
git@github.com: Permission denied (publickey)且用户名是另一个账号 | 当前本机默认密钥是另一把 | 参照上文~/.ssh/config配多密钥,使用正确的 Host 别名连接 |
连接超时(Connection timed out) | 网络环境受限,22 端口访问 GitHub 不稳定 | 可以尝试使用 SSH over HTTPS 443 端口,配置HostName ssh.github.com和Port 443 |
Load key "...": invalid format | 私钥文件损坏或格式不对 | 重新生成密钥;如果是从老服务器拷贝来的,确认没有复制多余内容 |
上面列的连接超时问题,我多说一句。GitHub 本身在大多数网络环境下 22 端口是正常的,但确实存在某些宽带运营商或企业网络把 22 端口拦掉的情况。官方提供了替代方案:使用 SSH over HTTPS 端口,在~/.ssh/config里做如下配置:
Host github.com HostName ssh.github.com Port 443 User git IdentityFile ~/.ssh/id_ed25519这种方式不改变你日常的使用习惯,git clone git@github.com:xxx/repo.git照常可用,只是底层的传输端口从 22 变成了 443。这个配置在人人在用的国内网络环境里也经常能生效,原理就是 443 端口一般不会被粗暴屏蔽,这是官方文档明确支持的方案,不是旁门左道。
5.2 我踩过的坑与想分享的三个经验
配置 SSH key 这么多年,有些教训是网上教程很少提到的,我在这里一并说出来,希望能帮你少走弯路。
第一个经验:不要嫌麻烦,每次都检查公钥和私钥文件权限。OpenSSH 对私钥文件权限有强制要求,只要权限过宽,它就会直接拒绝加载。我自己有次在 Windows 和 WSL 之间拷贝密钥,文件权限变得混乱,导致Permission denied排查了很久。正确设置是:
chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519 chmod 644 ~/.ssh/id_ed25519.pub公钥权限稍宽没问题,但私钥一定要收紧。
第二个经验:用ssh -vT git@github.com代替默认测试命令。普通-T只告诉你认证成功还是失败,但-v参数会输出详细日志,包括当前尝试了哪些私钥、哪个文件加载失败、服务器拒绝了哪条认证请求。排查问题时,看到 "Offering public key: /home/user/.ssh/id_ed25519" 这一行就明白到底用了哪把钥匙。如果日志里没出现预期密钥,多半是~/.ssh/config配置没生效,或者私钥路径拼错了。
第三个经验:配置好后记得把~/.ssh/config纳入你自己的环境管理工具,比如 dotfiles 仓库或者同步脚本。换电脑时,配置文件和密钥本身是可以整体迁移的(私钥也可以通过安全通道转移),但很多人忘了这个配置,导致新电脑上多出了一堆难以管理的密钥路径问题。把配置文件纳入版本管理,换机后直接复制回去,加上 identity 文件,几分钟就恢复开发环境。
最后再分享一个小技巧:GitHub 官方还提供了查看账号内所有已注册公钥的 API,如果你忘了自己往 GitHub 上贴过哪些公钥,可以用管理员权限在 GitHub 网页端随时查看和管理。另外,不要在同一台机器上把同一把私钥复制给多个完全不相关的服务器。私钥一旦泄露,所有配置了对应公钥的主机都会被影响,这比 HTTPS token 泄露的波及面还要大。基于密钥的管理确实能带来极大便利,但前提是你真的管好你的私钥。希望这篇 GitHub 配置 SSH key 的完整指南能帮你一次把所有流程理清,不再被各种奇奇怪怪的报错困扰。