刚接触 GitHub 的时候,折腾最多的就是认证方式。密码、Token、SSH Key 来回切换,尤其第一次在终端里看到 Permission denied (publickey) 的时候,很容易一头雾水。这篇文章把 GitHub SSH Key 生成这件事从头到尾捋一遍,从原理到实操再到排障,一次性讲透。
1. 为什么 GitHub 要推 SSH Key:从密码登录到密钥认证
1.1 公私钥到底是怎么一回事
SSH(Secure Shell)本来就是一个用于安全远程登录的协议,核心靠的是非对称加密。简单说,它一次生成一对钥匙:一把私钥,一把公钥。私钥放在你自己电脑上,绝不能给任何人;公钥可以放心地交给 GitHub,相当于你对外公开的“锁”。
GitHub 拿公钥锁住一个箱子,你本地用私钥去开。握手的时候,服务器验证的是“你确实持有与公钥配对的私钥”,而不是你记住了一个密码。整个过程不需要传输密码本身,也不存在密码在网络里被截获的问题。
日常操作里我们常用的 HTTPS 方式,靠的是用户名加密码或 Token 认证,每次 push 都要过一遍认证流程。而 SSh Key 配置好之后,push、pull、clone 都是静默完成,不需要反复输入凭据。
1.2 为什么比输密码更安全
密码最大的问题是可猜测性和可复用性。一旦密码泄露,别人直接拿你的账号做任何事。SSH 私钥是一串几百位的随机字节,长度通常 256 到 4096 位,暴力破解的复杂度完全不是一个量级。
另一个容易被忽略的点是,密码认证在每次请求时都要把密码(或 Token)发给服务器确认,虽然走的是加密通道,但任何多一跳的传输都多一分风险。私钥认证则是通过“签名”来证明身份——客户端用私钥对服务器给出的挑战数据做签名,服务器用公钥验证签名,私钥本身永远不出本地。
顺便吐槽一句,很多人觉得 https 方式也安全,确实安全,但那是“传输层”的安全。SSH Key 是“身份层”的安全,两者解决的问题不一样。前者防线路窃听,后者防止身份被冒用。
1.3 什么时候用 SSH Key,什么时候继续用 HTTPS
不要被“SSH Key 更好”这句话带偏。两种方式都官方支持,适用场景不同:
| 场景 | 推荐方式 | 理由 |
|---|---|---|
| 长期开发、日常 push/pull | SSH Key | 一次配置,长期免登录,体验稳定 |
| 偶尔在公共电脑上操作 | HTTPS + Token | 不留下私钥文件,用完即弃 |
| CI/CD 流水线拉代码 | 专用 Deploy Key 或 Token | 最小权限,可单独吊销 |
| 公司内网 Git 服务器 | 视平台而定 | 有些内网系统只开放 HTTPS 端口 |
我个人的习惯是:个人电脑上所有 GitHub 仓库统一走 SSH,临时借用别人电脑或者奇怪的网络环境时才用 HTTPS。这样既省心又安全。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前检查:环境准备与参数怎么选
2.1 确认 Git 和 OpenSSH 已就绪
生成 SSH Key 依赖两个基础工具:Git 和 OpenSSH 客户端。绝大多数情况下你电脑上已经有了,但版本差距会导致行为差异,建议先确认一下。
终端里分别执行:
bash复制git --version
ssh -V
git --version 会输出类似 git version 2.39.0 的结果。ssh -V 会输出 OpenSSH 的版本号,比如 OpenSSH_9.0p1, OpenSSH for Windows。
如果提示找不到命令,那就需要先安装。macOS 自带 Git 和 OpenSSH,Linux 一般也是内置的,Windows 建议装 Git for Windows,它自带 Git Bash 和 OpenSSH,不需要额外折腾环境变量。
2.2 选 ed25519 还是 RSA 4096
这个问题几乎是每次讨论 SSH Key 时的必争话题。直接给结论:新项目一律用 ed25519,只有遇到老服务器不支持时才回退到 RSA 4096。
| 参数 | ed25519 | RSA 4096 |
|---|---|---|
| 密钥长度 | 256 位 | 4096 位 |
| 安全性 | 高 | 高(但依赖长度堆砌) |
| 生成速度 | 极快 | 明显更慢 |
| 签名速度 | 快 | 较慢 |
| 兼容性 | 较新系统均支持 | 兼容性最广 |
选择 ed25519 的原因是它在同等安全级别下密钥更短、运算更快,而且生成时不需要像 RSA 那样跑一大堆素数测试,体验上就是“秒出”。RSA 4096 的优势是兼容几乎所有 SSH 实现,但生成时需要等几秒,而且密钥文件更大。
有一点需要说明:GitHub 本身对两者都支持,所以不必担心平台限制。只有在连接某些特别老旧的服务器时,才需要考虑对方是否支持 ed25519。
2.3 密钥保存位置与命名习惯
默认密钥文件保存在 ~/.ssh/ 目录下,macOS/Linux 是 /Users/你的用户名/.ssh,Windows 是 C:\Users\你的用户名\.ssh。默认文件名是 id_ed25519(私钥)和 id_ed25519.pub(公钥)。
如果你只有一个账号、只连一个平台,用默认文件名就好,省去很多配置。但如果你有多个平台账号(比如 GitHub 一个账号、某个公司 GitLab 另一个账号),就强烈建议用自定义文件名,比如 ~/.ssh/id_ed25519_github。
实际上,我见过太多人把所有密钥都堆在默认位置,换电脑或者换账号时完全分不清哪个是哪个。命名清晰是第一步,后续配合 ~/.ssh/config 文件做多账号分流,会轻松很多。
3. 三平台生成密钥实操:Windows、macOS、Linux
3.1 macOS / Linux:一条命令搞定
macOS 和 Linux 的操作几乎一样。打开终端,执行:
bash复制ssh-keygen -t ed25519 -C "你的邮箱@example.com"
-t 指定算法,-C 是注释,通常填你的邮箱,GitHub 会用它来辅助识别这个 Key 属于谁。注释不会被加密验证,只是给人看的。
接着终端会问你:
bash复制Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/你的名字/.ssh/id_ed25519):
这里直接回车就会使用默认路径。如果你想自定义,就在这里输入完整路径,比如 ~/.ssh/id_ed25519_github。
然后:
bash复制Enter passphrase (empty for no passphrase):
这一步很关键,建议不要留空,原因我后面单独讲。输入两次后,屏幕上会显示一串类似这样的输出:
bash复制Your identification has been saved in /Users/yourname/.ssh/id_ed25519
Your public key has been saved in /Users/yourname/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yourname@example.com
到这一步密钥文件就生成了。
3.2 Windows:PowerShell 与 Git Bash 两种姿势
Windows 用户有两条路可以走,原理一样,只是命令环境不同。
Git Bash 方式(推荐新手):安装 Git for Windows 后,打开 Git Bash,执行和 macOS 一模一样的命令:
bash复制ssh-keygen -t ed25519 -C "你的邮箱@example.com"
后面的流程完全一致。
PowerShell 方式:打开 PowerShell,执行同样的命令。注意:较新版本的 Windows 10/11 自带 OpenSSH 客户端,所以 ssh-keygen 是可以直接用的。如果你的 PowerShell 提示找不到命令,去“设置 → 可选功能”里把 OpenSSH 客户端装上。
有个小地方需要注意:Windows 下如果一句话里有空格的文件路径,需要用引号包起来。比如:
powershell复制ssh-keygen -t ed25519 -C "your@email.com" -f "$HOME\.ssh\id_ed25519_github"
-f 参数可以直接指定保存路径,省去交互式输入。
3.3 设置 passphrase:安全与便利的权衡
passphrase 相当于给私钥再加一道本地密码。即使你的私钥文件被别人拷走了,没有 passphrase 他也用不了。
很多人觉得麻烦就不设置,我强烈建议设置。原因很简单:私钥文件被窃取的事件一旦发生,没有 passphrase 意味着对方直接获得你所有 Git 仓库的读写权限。设置了 passphrase 之后,只是每次使用时多输一次口令,配合后文讲的 ssh-agent,体验几乎无感。
一个小技巧:passphrase 不需要搞成“强密码”那种变态复杂度,但也不要太短。我一般建议至少 16 位,可以是几个单词组合加符号,重点是你能记住。
3.4 把私钥交给 ssh-agent 托管
设置 passphrase 后,如果每次 push 都让你输一次,确实烦。ssh-agent 就是来解决这个问题的:它把私钥加载到内存中,之后一段时间内的 SSH 认证都由它代为完成,不用反复输 passphrase。
macOS / Linux 执行:
bash复制eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Windows PowerShell 先确认 ssh-agent 服务在运行:
powershell复制Get-Service ssh-agent
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
提示:macOS 用户如果想在重启后仍然让 ssh-agent 自动记住密钥,可以把
ssh-add --apple-use-keychain ~/.ssh/id_ed25519写进~/.zprofile,这是 macOS 特有的 keychain 集成方案。
4. 把公钥复制到 GitHub 并完成验证
4.1 查看并复制公钥
公钥是 .pub 结尾的文件,内容是纯文本,可以放心查看和复制。先找到它:
macOS / Linux:
bash复制cat ~/.ssh/id_ed25519.pub
Windows PowerShell:
powershell复制Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub
输出内容长这样:
code复制ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK2vMvgtOabc3kGjKfDdU3hFZZyLmTQw your@example.com
复制这一整行,注意不要漏掉开头的高亮部分,也不要加了换行。
懒得手动全选复制?可以直接走剪贴板:
bash复制# macOS
pbcopy < ~/.ssh/id_ed25519.pub
# Linux
xclip -sel clip < ~/.ssh/id_ed25519.pub
# Windows PowerShell
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard
4.2 GitHub 后台添加 Key 的正确步骤
登录 GitHub,依次进入:
- 右上角头像 → Settings
- 左侧菜单找 SSH and GPG keys
- 点击 New SSH key 按钮
- Title 字段填一个便于识别的名字,比如
my-macbook-pro - Key type 选 Authentication Key
- Key 文本框粘贴刚才复制的公钥内容
- 点击 Add SSH key
添加到这一步,GitHub 已经“认识”你的公钥了。但很多时候你会发现添加完还是连不上,所以下一步必须做验证。
4.3 测试连接与常见回显
终端执行:
bash复制ssh -T git@github.com
第一次连接时会看到:
bash复制The authenticity of host 'github.com (xxx.xxx.xxx.xxx)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/tL2pVsmBv7shWPPF9TgQ.
Are you sure you want to continue connecting (yes/no)?
输入 yes 回车。这里是在确认 GitHub 服务器的身份指纹,正常情况直接信任即可。如果之后测试时发现指纹对不上,就要警惕中间人攻击的可能,但在正常使用场景下不会出现。
认证成功的回显是:
bash复制Hi 你的用户名! You've successfully authenticated, but GitHub does not provide shell access.
注意:GitHub 的 SSH 接入只用于 Git 操作,不提供真正的 shell,所以看到这句就说明认证打通了。
4.4 本地仓库切换 SSH 地址
如果之前克隆仓库用的是 HTTPS 地址,需要把 remote 换成 SSH。查看当前地址:
bash复制git remote -v
输出形如:
bash复制origin https://github.com/用户名/仓库名.git (fetch)
origin https://github.com/用户名/仓库名.git (push)
改成 SSH 地址:
bash复制git remote set-url origin git@github.com:用户名/仓库名.git
之后再执行 git remote -v,应该看到 git@github.com:用户名/仓库名.git 开头的地址,就可以直接 push 了。
如果你还没有克隆仓库,直接复制 GitHub 仓库页面的 SSH 地址克隆即可:
bash复制git clone git@github.com:用户名/仓库名.git
5. 高频报错与排障实录
5.1 Permission denied (publickey) 怎么查
这是出现频率最高的报错,没有之一。完整错误通常是:
bash复制git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
排查思路按顺序来:
- 确认测试连接时的用户名是
git,不是你的 GitHub 用户名。ssh -T git@github.com这个git是固定的,不能换。 - 确认公钥确实已经添加到 GitHub。去后台检查 Key 内容是否和本地
.pub文件完全一致,有时复制时少了头尾字符就会造成不匹配。 - 确认 SSH 使用的是哪把私钥。执行
ssh -vT git@github.com查看详细日志,日志里会显示尝试了哪些密钥文件。如果尝试的不是你生成的那把,说明 SSH 没找到正确私钥。 - 确认 ssh-agent 里加载的私钥是对的。执行
ssh-add -l查看当前已加载的密钥列表,如果为空,用ssh-add ~/.ssh/id_ed25519手动加载。
绝大多数情况是第 2 和第 3 步的问题。我曾经见过一个用户把公钥和私钥内容搞反了,把私钥贴到了 GitHub 后台,结果当然认证失败,这种低级错误排查起来最费时间。
5.2 多账号多密钥的 config 配置法
如果你同一个电脑上需要同时使用 GitHub 账号 A 和公司 GitLab 账号 B,光靠默认密钥是行不通的,因为 SSH 默认只会找 id_ed25519 这一把。解决办法是写配置文件。
在 ~/.ssh/ 下新建一个名为 config 的文件(注意没有后缀名),内容参考:
code复制# GitHub 个人账号
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
# 公司 GitLab
Host gitlab.company.com
HostName gitlab.company.com
User git
IdentityFile ~/.ssh/id_ed25519_gitlab
配置完成后,需要让这些密钥生效:
bash复制ssh-add ~/.ssh/id_ed25519_github
ssh-add ~/.ssh/id_ed25519_gitlab
这里有个细节很容易踩坑:Host 字段是逻辑别名,如果写了 Host github.com,那所有对 github.com 的连接都会自动匹配这条规则。但如果你在同一台机器上对同一个 GitHub 账号用了不同仓库,只要远程地址里的域名都是 github.com,就会共用这一个 key。所以真正需要多 key 区分的是不同的 HostName(不同域名),而不是同一个域名下的多个账号。
对于同一个 GitHub 账号下的多个仓库,不需要多把 SSH Key,一把就够了,这是很多人一开始的理解误区。
5.3 权限过宽的 Permission 报错
在 macOS / Linux 下,如果私钥文件的权限太开放,OpenSSH 会直接拒绝使用它,这是安全机制在起作用。
报错信息类似:
bash复制Permissions 0644 for 'xxxxx' are too open.
It is required that your private key files are NOT accessible by others.
解决方法是收紧权限:
bash复制chmod 600 ~/.ssh/id_ed25519
私钥文件必须是 600(仅属主可读写),公钥文件可以用 644。如果 .ssh 目录本身的权限不对,也可能引发问题:
bash复制chmod 700 ~/.ssh
Windows 下则不用太纠结这个,系统对文件的 ACL 处理方式和 Unix 不同,一般不触发这个报错。
5.4 换电脑、换邮箱后的密钥迁移
换了新电脑,密钥怎么迁移?这里有两个选择:复制旧密钥,或者生成新密钥。
复制旧密钥的坑在于:如果你之前没有备份,私钥丢了就是丢了,没法从 GitHub 倒推出来。这也是为什么我建议密钥生成后就把私钥备份到一个安全的加密存储里。
生成新密钥更推荐。操作流程:
- 生成新密钥(换个文件名,比如
id_ed25519_new) - 把新公钥添加到 GitHub
- 到 GitHub 后台把旧公钥删除
- 本地
~/.ssh/config或默认路径切换到新私钥
这里有个细节:GitHub 允许一个账号添加多把公钥,所以新旧交替期间可以共存,等新电脑完全验证通过后再删旧的,避免中途出现无法连接的窗口期。
6. 容易被忽略的收尾细节
6.1 密钥文件的权限要求
前文提到了 chmod 600,这里再展开说一下。OpenSSH 对密钥文件的权限检查非常严格,因为如果其他人也能读你的私钥,认证就没有意义了。
在 Linux / macOS 上,一把合格的私钥应该满足:
- 私钥文件:属主可读写,其他用户无任何权限(
600) - 公钥文件:属主可读写,其他用户可读(
644) .ssh目录:属主可读写执行,其他用户无写权限(700)
如果发现连不上,第一反应可以先检查权限。我调试过很多次 SSH 问题,最后都发现是 git clone 到公共目录下操作,权限被重置导致的。
6.2 用 ssh-agent 解决每次输 passphrase 的烦恼
前面提过 ssh-agent,这里补充一个使用细节。每次开机后,ssh-agent 是空的,需要重新添加密钥。
macOS 用户可以在 ~/.ssh/config 里加一段:
code复制Host github.com
AddKeysToAgent yes
UseKeychain yes
这样第一次使用时会自动把密钥加入 ssh-agent 并存入钥匙串,之后开机不用手动 ssh-add。
Windows 用户可以在 PowerShell 的 profile 文件($PROFILE)里写:
powershell复制Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
这样每次打开 PowerShell 会自动启动服务并加载密钥。
Linux 桌面用户比较常用的是 gnome-keyring 或者 keychain 工具,配置方式看发行版,但思路一样:让系统在登录后自动加载密钥。
6.3 一个实用的备份思路
私钥丢了比密码丢了更麻烦,因为无法找回。我现在的习惯是,在任何设备上用 ssh-keygen -t ed25519 生成的私钥,都会在生成当天做一次加密备份到离线存储里。
备份时注意两点:
- 私钥文件要加密存储,不要裸放网盘。可以用
tar打包后配合系统自带的加密工具,或者放进密码管理软件。 - 公钥不需要备份,因为它本来就是给服务器的,丢了随时可以从私钥推导出来。
提示:如果你的私钥在备份后发现已经泄露(比如误发到公共仓库),正确的处理方式是立即生成新密钥并将旧公钥从 GitHub 后台删除,而不是寄希望于私钥没有被下载过。
最后结合我自己的经验说两点。
第一,无论你用什么平台,生成 SSH Key 这件事本身不会超过三分钟,但一次性做对能省下后面无数的麻烦。尤其是在多账号、多电脑的场景下,提前规划好密钥命名和 config 文件,比出了问题时再回头查要高效得多。
第二,ssh -T git@github.com 这个测试命令值得刻在脑子里。几乎所有“我明明配置好了怎么还连不上”的场景,它都能直接告诉你问题出在哪一层。加一个 -v 参数能看到更详细的连接日志,排查时非常有帮助。
如果你现在还在用密码方式推代码,换个 SSH Key 吧,一次性投入三分钟,后续的体验会顺滑很多。
