termal.in

← 博客

Windows 上的 ssh-agent:启动服务、添加密钥、修复报错

· Termalin Team sshssh-agentwindowstutorial

你给 SSH 密钥设了密码短语,现在 Windows 在每次 git push 和每次 ssh 时都要你输入它。解决办法就是 SSH 代理——解锁一次密钥,之后每次连接都会静默签名。Windows 上的曲折在于:并不是只有一个代理。有三个代理可能同时在运行,它们把密钥存在各自不同的地方,加载进其中一个里的密钥,对其他几个是不可见的。几乎所有“昨天还好好的”代理问题,在 Windows 上其实都是用错了代理。所以本指南先给它们起个名字,再逐个把它们跑起来,最后解读你真正会遇到的报错。

三个代理,以及它们为何不共享密钥

代理随附于监听位置哪个 ssh 能看到它
OpenSSH Authentication Agent(一个 Windows 服务)Windows 原生的 OpenSSH命名管道 \\.\pipe\openssh-ssh-agentC:\Windows\System32\OpenSSH 里的 ssh.exe
MSYS2 代理(ssh-agent)Git for Windows / Git Bash由 SSH_AUTH_SOCK 指定的 Unix 式套接字Git Bash 内置的 ssh
Linux 代理你的 WSL 发行版内部该发行版里的一个 Unix 套接字在 WSL 内运行的 ssh

表格给出的教训:在 Git Bash 里运行 ssh-add 会把密钥加载进 MSYS2 代理,而 Windows 原生的 ssh.exe 永远看不到它——不同的端点,不同的密钥库。选定一个代理,把密钥加载到那里,再用与之匹配的 ssh。把它们混着用,是下面大多数困惑的根源。ssh-agent 与 ssh-add 指南(英文)讲的是跨平台的机制;本页是 Windows 专属的那一半。

内置的 OpenSSH Authentication Agent 服务

现代的 Windows 10 和 11 都自带 OpenSSH,随之而来的是一个运行该代理的 Windows 服务——但它默认是关闭的。只需在管理员权限的 PowerShell(以管理员身份运行)里启用一次:

Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent

Automatic 会在每次开机时启动它,所以这是一次性设置。检查结果:

Get-Service ssh-agent | Select-Object Status, StartType

你要看到的是 Running 和 Automatic。此后,在普通(非 Git Bash)的 PowerShell 或 cmd 里,ssh-add 就会和这个服务通信:

ssh-add                                 # load default keys (id_ed25519, id_rsa, …)
ssh-add $env:USERPROFILE\.ssh\id_ed25519  # load a specific key
ssh-add -l                              # list loaded key fingerprints

ssh-add -l 是任何登录失败的首要诊断手段——如果你期望的密钥没有列出来,那么无论别的看起来多正确,代理都无法用它来签名。

为了不用反复敲 ssh-add,让第一次连接替你加载密钥。把下面这段放进 %USERPROFILE%\.ssh\config(就是 OpenSSH 到处都在读的那个 ssh_config 文件(英文)):

Host *
    AddKeysToAgent yes

现在,第一个需要密码短语的 ssh 会提示一次,并顺带把密钥加载进服务。由于原生的 Windows git 和 ssh 都用这个服务,git push 也会开始静默工作。

错误 1058:“unable to start the ssh-agent service”

你运行 Start-Service ssh-agent,得到:

Start-Service : Service 'OpenSSH Authentication Agent (ssh-agent)' cannot be started due to the following error:
Cannot start service ssh-agent on computer '.'.
... error 1058 ...

错误 1058 意味着该服务被禁用了——Windows 不会启动一个启动类型为 Disabled 的服务,而 Start-Service 不会替你改这个设置。先修好启动类型,再启动它(管理员 PowerShell):

Set-Service ssh-agent -StartupType Manual
Start-Service ssh-agent

Manual 足以让它按需启动;如果你想每次开机都起来,就用 Automatic。如果你用的是受管或域内机器,某个组策略可能已经禁用了它——那样的话,得由管理员先允许该服务,这些设置才能生效。

“error connecting to agent: No such file or directory”

这一条来自 Git Bash / MSYS2 的 ssh,不是那个 Windows 服务。它表示那个 ssh 被告知了去哪里找代理套接字——通过 SSH_AUTH_SOCK——但那里什么都没有。两个常见原因:

  • **这个 shell 里没有代理在运行。**Git Bash 不会替你启动一个。在你正用的 shell 里启动它:

    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/id_ed25519

    eval 很重要:ssh-agent -s 只会打印变量;eval 才会设置它们,好让 ssh 能找到套接字。光运行 ssh-agent、然后纳闷为什么什么都没变,是经典的误操作。

  • **SSH_AUTH_SOCK 过期了。**由上一个会话、某个登录配置文件或别的工具设置的变量,指向了一个已不存在的套接字。用 echo $SSH_AUTH_SOCK 检查它,然后要么取消设置它并启动一个全新的代理,要么把它修正为指向一个有效的代理。

如果你更想在 Git Bash 里面使用那个 Windows 服务,就直接调用原生二进制文件——/c/Windows/System32/OpenSSH/ssh.exe——而不是你 PATH 上的 MSYS2 ssh。这样 Git Bash 就能访问到你加载进该服务的同一批密钥,SSH_AUTH_SOCK 也不再重要。

WSL 里的密钥

WSL 是一个独立的 Linux 系统,所以它有自己的代理、自己的 ~/.ssh 和自己的 SSH_AUTH_SOCK。在 Windows 一侧加载的密钥,在你的发行版内部看不到,反之亦然。你有两个诚实的选择:

  • 在 WSL 内部运行一个代理,用普通的 Linux 方式——eval "$(ssh-agent -s)" 加 ssh-add,或者在发行版的 ~/.ssh/config 里写 AddKeysToAgent yes。简单、完全隔离,ssh-add 指南(英文)里有讲。
  • 桥接到 Windows 代理,让两个世界共用一个密钥库。常见做法是用 npiperelay.exe 配合 socat,把 Windows 命名管道接到一个 Unix 套接字上,再让 WSL 的 SSH_AUTH_SOCK 指向它。配好之后用起来很顺,但多了不少活动部件——只有当你确实需要同一把密钥在两边都能用时,才去碰它。

无论选哪种,记住 WSL 里的 ssh-add -l 和 PowerShell 里的 ssh-add -l 是两个不同的问题。调试时问对那一个。

代理没问题,但登录仍然失败时

如果 ssh-add -l 显示了你的密钥,服务器却仍然说 Permission denied (publickey),那么代理已经完成了它的工作——问题转移到了下游:服务器的 authorized_keys、用错了用户,或者提供了错误的密钥。那是另一份清单:Permission denied (publickey),按顺序修复(英文)。而在你用 ssh -A 把代理转发到远程机器之前,先读读为什么代理转发既方便又危险(英文)——它会把你密钥的实时使用权暴露在对端。

Termalin 在 Windows 上如何处理这件事

如果要操心服务、套接字和三个密钥库,超出了你想思考的范围,那正是 Termalin 内建好的工作流。它在一个 Windows 命名管道 \\.\pipe\termalin-ssh-agent 上运行自己的密钥代理,并通过标准的 ssh-agent 协议把你已在应用里解锁的密钥提供出去——于是任何会说这个协议的工具都能通过它签名,无需启用任何操作系统服务,无需 eval 那一行,也无需手动 ssh-add。私钥留在运行中的应用里,从不写入磁盘。这个代理的意义,是让 Termalin 自己的 MCP 服务器能用你的密钥向服务器认证,却从不持有密钥材料本身——代理负责签名,调用方永远看不到秘密。这和 OpenSSH 服务“解锁一次”的思路一样,只是把 Windows 的那套设置从你肩上卸了下来。


Termalin 是一款免费、跨平台的 SSH 客户端,它内置的代理把你的密钥解锁一次,然后代你签名——下载它,或了解它如何安全地处理你的密钥。

先在一台主机上试试。

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

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