termal.in

← 博客

GitHub、GitLab SSH 密钥用不了?分步修复指南

· 更新于 2026年9月29日 · Termalin Team sshgittroubleshootingssh-keys

一把无法向 GitHub 或 GitLab 认证的 SSH 密钥,是开发者被 Google 搜得最多的问题之一,而有一半时候密钥本身没问题——只是诊断错了。所以在你重新生成任何东西之前,先跑一个测试,并学会读懂它的答案。然后按“真正是元凶的频率”从高到低逐个排查。

“You’ve successfully authenticated, but GitHub does not provide shell access”

如果你收到的是这一句,停下——**你的密钥已经生效了。**GitHub 和 GitLab 不会给你一个 shell;它们只在 SSH 之上说 git,所以它们认证了你,然后立刻挂断,而“does not provide shell access”就是它们在这么说,不是一个错误。GitLab 的措辞略有不同(Welcome to GitLab, @you!),但意思一样。如果你的密钥能用、git push 却仍然要密码,那密钥从来就不是问题——跳到下面的 HTTPS 远程地址那个元凶,那通常才是真正的原因。

第 0 步:告诉你它到底坏没坏的那个测试

直接问 git 托管方,它认不认你的密钥:

ssh -T git@github.com        # GitHub
ssh -T git@gitlab.com        # GitLab

现在仔细读那个回应,因为成功的信息看起来像一个错误:

Hi <username>! You've successfully authenticated, but GitHub does not
provide shell access.

那是成功。“Does not provide shell access”不是失败——GitHub 和 GitLab 不给你 shell,它们只在 SSH 之上说 git,所以它们认证了你,然后挂断。人们看到“does not provide”就开始给一个本来好好的配置排障。如果你在那一行里看到了你的用户名,你的密钥就能用;你的问题在别处(跳到下面的 HTTPS 远程地址元凶——那通常才是真正的问题)。

真正的失败看起来是这样的:

git@github.com: Permission denied (publickey).

那才是我们来修的。注意端点:Permission denied (publickey) 意味着服务器没有接受你提供的任何密钥。往下逐条排查。

元凶 1:密钥没有添加到你的账户

最常见的真实原因。笔记本上的一把密钥,在它的公钥那一半被注册到 git 托管方之前,什么都做不了。复制公钥:

cat ~/.ssh/id_ed25519.pub     # note the .pub — this is the safe half to share

把它粘贴到 GitHub → Settings → SSH and GPG keys → New SSH key,或 GitLab → Preferences → SSH Keys。

一条规则,没有例外:**粘贴 .pub 文件,绝不要粘贴那个没有 .pub 的文件。**公钥是以 ssh-ed25519 AAAA…(或 ssh-rsa AAAA…)开头的一行。如果你即将粘贴的东西以 -----BEGIN OPENSSH PRIVATE KEY----- 开头,停下——那是你的私钥,是那个就是你身份的秘密。把它粘进一个网页表单,等于把你的凭据交给任何能读到那个页面的人。分享公钥那一半;守住私钥那一半。

(还没有密钥?生成一把——几乎所有情况都用 Ed25519(英文):ssh-keygen -t ed25519 -C "you@device"。)

元凶 2:提供出去的是错误的密钥

你的密钥注册了,但 SSH 提供的是另一把——当你带着好几把密钥、而代理按一个服务器会拒绝的顺序去试时,这很常见。看清到底发出去的是哪把:

ssh -vT git@github.com

找 Offering public key: 那几行。如果你注册的密钥不在其中,或者有一把错误的被接受了,就在 ~/.ssh/config 里按主机把正确的密钥钉死:

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

IdentitiesOnly yes 是关键的一行——它告诉 SSH 只提供你指定的那个 IdentityFile,别再把你代理里的每一把密钥都朝服务器喷(这也顺带治好了 Too many authentication failures)。对 GitLab 用 Host gitlab.com 做同样的事。关于如何组织这个文件,更多见 ssh_config 指南(英文)。

元凶 3:代理没在运行,或密钥没加载

如果你的密钥有密码短语、而代理没有持有它,SSH 可能会悄悄跳过它。查一下代理里有什么:

ssh-add -l

The agent has no identities(或 Could not open a connection to your authentication agent)意味着你得启动它并加载密钥:

eval "$(ssh-agent -s)"        # start the agent in this shell
ssh-add ~/.ssh/id_ed25519     # load the key (prompts for the passphrase once)

ssh-add -l 现在应当列出你密钥的指纹。(关于代理到底是什么、它如何持有密钥,见什么是 SSH 代理(英文)。)

元凶 4:你用的是 HTTPS 远程地址,不是 SSH 的

这就是“我的密钥能用(ssh -T 成功了),但 git push 还是要密码”背后的元凶。你的仓库被配成用 HTTPS,它完全不理会 SSH 密钥,要的是一个令牌。检查:

git remote -v

如果你看到 https://github.com/you/repo.git,那就是问题所在——HTTPS 从不碰你的 SSH 密钥。把远程地址切到 SSH:

git remote set-url origin git@github.com:you/repo.git      # GitHub
git remote set-url origin git@gitlab.com:you/repo.git      # GitLab

再跑一次 git remote -v 确认它现在以 git@ 开头。这一个修复,解决了很大一部分“SSH 密钥用不了”的报告——而其实密钥一直都好好的。

元凶 5:~/.ssh 上的权限

SSH 拒绝使用别人可能篡改的密钥和配置。如果 verbose 输出提到权限模式不对,或者密钥莫名其妙被忽略:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519          # private key
chmod 644 ~/.ssh/id_ed25519.pub      # public key
chmod 600 ~/.ssh/config

在 Windows 上,这会在你从一个会同步的盘里、或机器之间复制密钥之后冒出来;通过文件的“安全”属性来修,或者别把密钥放进云同步的文件夹里。

元凶 6:每次都提示输入密码短语

如果每一个 git 操作都要你的密钥密码短语,那是代理没在缓存它。用 ssh-add(英文)加载一次(元凶 3),再往 ~/.ssh/config 里加上这段、让它跨会话保持:

Host github.com gitlab.com
    AddKeysToAgent yes

在 macOS 上,ssh-add --apple-use-keychain ~/.ssh/id_ed25519 会把密码短语存进钥匙串,让它在重启后依然有效。

元凶 7:两个账户,同一个主机

工作和个人的 GitHub 账户不能共用一把密钥——一把给定的公钥只属于恰好一个账户。给每个账户配各自的密钥,再用一个选择它的 Host 别名:

Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/work_ed25519
    IdentitiesOnly yes

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/personal_ed25519
    IdentitiesOnly yes

然后用别名作为主机来 clone 或设置远程地址:git@github-work:org/repo.git。SSH 匹配到 github-work,挑中工作密钥,并在底层把连接改写回 github.com。

元凶 8:组织的 SSO 没有授权(GitHub)

你认证自己的仓库没问题,但在一个受 SAML SSO 保护的组织的仓库上得到 Permission denied。密钥是存在的,只是没为那个组织授权。去 Settings → SSH and GPG keys,找到那把密钥,点 Configure SSO,为该组织授权它。GitLab 有一个平行的情况:一把过期的密钥会被悄悄拒绝——如果一把之前好用的密钥突然失灵,去 SSH Keys 查它的过期日期。

当它仍然是 Permission denied (publickey) 时

如果你把这份清单走了一遍、还是撞在这个端点上,那你已经把范围缩小到了一个真正的密钥接受问题——针对那个确切报错的系统化循环(读 ssh -vvv、服务器的方法列表、提供 vs 接受的密钥)在 permission denied (publickey),一套快速而系统的修法(英文)里,而更全面的 SSH 报错地图在 SSH 报错解码里。但具体到 git 托管方,上面的顺序几乎能抓住一切:注册公钥、提供正确的那把、把它加载进代理,再确认你确实在一个 SSH 远程地址上。

一款客户端如何把这套设置彻底省掉

这些摩擦大多是记账的活儿——哪把密钥属于哪个主机、它有没有加载、远程地址到底是不是 SSH。Termalin 把密钥和它所属的主机放在一起,通过一个内置代理把你的密钥解锁一次,这样密码短语就不用反复敲(而一个被取消的提示也绝不会悄悄跳过一把密钥)——并且因为它会说标准的 ssh-agent 协议,git 和你的 CLI 都能通过同一个代理签名。指纹按密钥可见,所以把正确的公钥那一半注册到 GitHub 或 GitLab,是复制粘贴,而不是在五个 ~/.ssh 文件夹里翻找。上面那套账户与别名的来回折腾,变成了一个按主机的设置,而不是一道配置文件谜题。


Termalin 是一款免费、跨平台的 SSH 客户端,用一个“解锁一次”的代理管理你的密钥,git 可以通过它签名——下载它,或了解它如何安全地处理密钥。

先在一台主机上试试。

Termalin 是为你和你的智能体打造的高速 SSH 客户端。

免费版 · Pro 14 天试用 · 价格