GitHub Actions 自动部署里的 SSH Key 是什么?公钥私钥怎么用?一篇讲透

结合一次真实的 GitHub Actions 自动部署配置,详细讲清 SSH Key、公钥私钥的区别、ed25519 的生成方式、GitHub Secrets 配置思路,以及部署场景下的安全注意事项。

GitHub Actions 自动部署里的 SSH Key 是什么?公钥私钥怎么用?一篇讲透
目录

GitHub Actions 自动部署里的 SSH Key 是什么?公钥私钥怎么用?一篇讲透

作者:文文

前言

最近在继续完善项目自动部署流程时,除了 GHCR 镜像拉取这一层,还顺手把服务器侧专用的 GitHub Actions 部署 SSH Key 也配上了。

这一步看起来只是执行了一条命令:

ssh-keygen -t ed25519 -f /root/.ssh/github_actions_deploy -C "github-actions-deploy"

但如果你之前没有系统理解过 SSH Key,很容易一边生成,一边脑子发懵:

  • 公钥和私钥到底谁该放哪?
  • 为什么私钥不能传服务器?
  • 为什么 GitHub Actions 反而要保存私钥?
  • ed25519 是什么,为什么现在经常推荐它?
  • 部署场景下为什么最好单独生成一把专用 Key?

这篇文章就把这些问题一次讲清楚,而且尽量用实战视角来讲,不搞玄学。


一、SSH Key 到底是什么?

SSH Key 本质上是一对“配套使用的密钥”:

  • 私钥(Private Key):只能你自己保管
  • 公钥(Public Key):可以发给目标服务器

它们是成对生成的。

你可以把它理解成一种更安全的“免密登录凭证系统”:

  • 以前你登录服务器,可能靠密码
  • 现在你登录服务器,可以靠 SSH Key

登录时并不是“把私钥发给服务器”,而是:

  • 服务器保存你的公钥
  • 你本地保存私钥
  • SSH 协议通过一套加密验证机制证明“你确实拥有与这把公钥配套的私钥”

因此,真正敏感的是私钥,不是公钥。


二、公钥和私钥分别是什么?

假设你执行:

ssh-keygen -t ed25519 -f /root/.ssh/github_actions_deploy -C "github-actions-deploy"

生成后,通常会得到两个文件:

/root/.ssh/github_actions_deploy
/root/.ssh/github_actions_deploy.pub

其中:

1. 私钥

/root/.ssh/github_actions_deploy

这就是私钥。

特点: - 绝对敏感 - 不能泄露 - 不能随便发别人 - 不能提交进 Git 仓库 - 如果别人拿到它,并且服务器也信任这把 Key,那别人就可能直接登录你的服务器

2. 公钥

/root/.ssh/github_actions_deploy.pub

这就是公钥。

特点: - 可以发给服务器 - 可以追加到 authorized_keys - 一般不会因为泄露公钥本身而直接造成安全问题 - 它的作用是告诉服务器:“以后拿着对应私钥的人,可以被允许登录”

所以请牢牢记住一句:

私钥自己留着,公钥发给目标服务器。


三、为什么 GitHub Actions 场景里反而要保存私钥?

这点是最容易把人绕晕的地方。

很多人第一次做自动部署时会问:

既然私钥敏感,为什么还要把私钥放进 GitHub Secrets?

答案是:

  • 因为真正执行 SSH 登录动作的是 GitHub Actions Runner
  • Runner 想登录你的服务器,就必须像“客户端”一样持有私钥
  • 服务器那边则要提前保存对应公钥

也就是说,在自动部署场景里:

GitHub Actions Runner = SSH 客户端 = 需要私钥
你的服务器 = SSH 服务端 = 需要公钥

所以配置关系一般是这样:

GitHub 侧

保存到 Secrets: - 私钥内容

服务器侧

写入: - 公钥内容到 ~/.ssh/authorized_keys

这样 GitHub Actions 在运行时,就可以:

  • 把私钥写入临时文件
  • 用这把私钥 SSH 到你的服务器
  • 执行部署命令

四、为什么推荐为部署单独生成一把 Key?

这也是非常重要的工程习惯。

很多人图省事,直接把自己平时登录服务器的那把 SSH Key 拿来给 GitHub Actions 用。

技术上当然可以,但不够优雅,也不够安全。

更推荐的方式是:

  • 专门为 GitHub Actions 自动部署生成一把独立的 Key
  • 只用于部署,不混用个人日常登录 Key

比如这次用的:

ssh-keygen -t ed25519 -f /root/.ssh/github_actions_deploy -C "github-actions-deploy"

这样做的好处有几个:

1. 权限边界更清晰

你可以明确知道:

  • 这把 Key 就是给自动部署用的
  • 不是给自己日常 shell 登录用的

2. 后续撤销更方便

如果哪天不想让 GitHub Actions 再登录服务器,直接把对应公钥从服务器删掉就行。

不需要影响你自己的其他 SSH Key。

3. 审计更清楚

当你在 authorized_keys 里看到注释:

github-actions-deploy

你一眼就知道这把 Key 是干嘛的。


五、为什么现在常推荐 ed25519?

这次命令里用了:

-t ed25519

这表示生成的是 ed25519 类型的 SSH Key。

相比传统的 rsa,ed25519 现在常被推荐,原因主要有:

  • 密钥更短,但安全性很强
  • 生成速度快
  • 验证速度快
  • 现代 OpenSSH 支持很好
  • 配置简单,不容易踩旧算法兼容问题

当然,如果你的服务器环境非常老旧,也可能还在用 RSA。

但如果系统环境比较新,优先用 ed25519 往往是更省心的选择。


六、完整创建过程怎么做?

第一步:生成 Key

在服务器或本地执行:

ssh-keygen -t ed25519 -f /root/.ssh/github_actions_deploy -C "github-actions-deploy"

参数解释:

  • ssh-keygen:生成 SSH Key 的命令
  • -t ed25519:指定密钥算法为 ed25519
  • -f /root/.ssh/github_actions_deploy:指定输出文件路径
  • -C "github-actions-deploy":给这把 Key 加一个注释,便于识别

执行后如果不设置密码短语(passphrase),就直接回车即可。

生成结果:

/root/.ssh/github_actions_deploy
/root/.ssh/github_actions_deploy.pub

第二步:查看公钥

cat /root/.ssh/github_actions_deploy.pub

输出看起来大概像这样:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... github-actions-deploy

把这整行追加到目标服务器允许登录用户的 authorized_keys 中。

例如:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat github_actions_deploy.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

如果你是在“目标服务器自己生成”的 Key,那通常也可以直接把 .pub 文件内容写进对应登录用户的 authorized_keys。


第三步:查看私钥

cat /root/.ssh/github_actions_deploy

输出内容大概会像这样:

-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----

这一整段就是要保存到 GitHub Secrets 的内容。

注意:

  • 必须整段完整复制
  • 包括头尾标记
  • 中间换行也要保留

七、GitHub Actions 里怎么用这把私钥?

最常见的做法是:

1. 在 GitHub 仓库里新增 Secret

比如:

  • DAOYIN_SERVER_SSH_KEY

值就是刚才那整段私钥内容。

2. Workflow 运行时写入临时文件

例如:

- name: Setup SSH key
  run: |
    mkdir -p ~/.ssh
    echo "${{ secrets.DAOYIN_SERVER_SSH_KEY }}" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    ssh-keyscan -p ${{ secrets.DAOYIN_SERVER_PORT }} ${{ secrets.DAOYIN_SERVER_HOST }} >> ~/.ssh/known_hosts

然后后面就可以:

```yaml
ssh -p ${{ secrets.DAOYIN_SERVER_PORT }} user@host "your deploy command"

或者配合:

  • appleboy/ssh-action
  • appleboy/scp-action
  • rsync + ssh

去完成部署。


八、公钥到底放哪?私钥到底放哪?一句话版本

如果你老记混,就记下面这张表:

内容 放哪里 作用
私钥 GitHub Secrets / 本地客户端 用来发起 SSH 登录
公钥 目标服务器 authorized_keys 告诉服务器信任对应私钥

最短版口诀:

  • 私钥跟着发起连接的一方走
  • 公钥跟着被登录的一方走

在 GitHub Actions 自动部署里:

  • GitHub Actions 是发起连接的一方 → 要私钥
  • 服务器是被登录的一方 → 要公钥

九、常见错误与排查方法

1. Permission denied (publickey)

通常说明:

  • 公钥没加到 authorized_keys
  • 私钥和公钥不是一对
  • 登录用户错了
  • ~/.ssh 或 authorized_keys 权限不对

可以重点检查:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

以及:

  • 当前登录用户是否和公钥写入的用户一致
  • Secrets 里的私钥是否完整复制

2. Load key ... invalid format

通常说明:

  • 私钥复制时格式坏了
  • GitHub Secret 中换行丢失
  • 少了 BEGIN/END OPENSSH PRIVATE KEY

这类问题通常不是密钥本身错,而是“保存方式错”。


3. Host key verification failed

通常说明:

  • 没把服务器主机指纹写入 known_hosts

可以通过:

ssh-keyscan -p 22 your-server-host >> ~/.ssh/known_hosts

来解决。

GitHub Actions 里常常就是在工作流里先做一次 ssh-keyscan。


十、安全上还有哪些注意事项?

1. 私钥绝对不要提交进仓库

这条是底线。

无论:

  • git push
  • 截图
  • 粘贴日志
  • 发聊天记录

都不要把私钥内容暴露出去。


2. 最好专钥专用

不要把:

  • 个人开发登录 Key
  • GitHub Actions 部署 Key
  • 其他自动化脚本 Key

全混成一把。

分开更安全,也更好撤销。


3. 给部署用户最小权限

如果条件允许:

  • 不要让自动部署直接用 root
  • 最好单独给部署用户、部署目录和有限权限

这样即便 Key 出问题,损失范围也更可控。


4. 可以考虑定期轮换

长期使用的自动化部署 Key,后面如果项目更正式了,可以考虑:

  • 定期更新 Key
  • 旧 Key 作废
  • 保持最小暴露面

十一、这次实战里最值得记住的结论

如果把这篇文章压缩成几句最重要的话,大概就是:

  1. SSH Key 是一对密钥:私钥自己保管,公钥交给服务器
  2. GitHub Actions 作为 SSH 客户端,必须持有私钥
  3. 目标服务器要保存对应公钥到 authorized_keys
  4. 自动部署最好单独生成一把专用 Key,不和日常登录混用
  5. ed25519 是现代环境里非常推荐的选择
  6. 私钥最敏感,不能泄露,不能提交 Git

十二、结语

很多时候,自动部署卡住,并不是卡在 Docker、GHCR 或 GitHub Actions 本身,而是卡在最基础的“连接凭证”这一层。

SSH Key 一旦理解透了,后面很多事情都会顺很多:

  • 自动部署
  • 代码同步
  • 远程执行脚本
  • 多服务器运维
  • CI/CD 管道落地

它不是一个“顺手配一下”的小知识点,而是一整套自动化工程实践里的基础设施。

所以与其背命令,不如把底层逻辑想明白:

谁发起连接,谁拿私钥;谁接收连接,谁保存公钥。

一旦这句真正刻进脑子里,后面再配 GitHub Actions SSH 登录,你就不会再晕了。


文文,2026 年 3 月 21 日
部署这件事,表面拼的是命令,底层拼的是你对每一层凭证和链路的理解~ 💕

相关文章

技术 · 2026-03-21FastAPI 后端 Docker + GHCR + GitHub Actions 自动部署实践技术 · 2026-03-16深入理解 Kubernetes:从容器编排到微服务架构的完整学习路线技术 · 2026-03-16如何用 Docker 打包部署你的应用?一篇文章搞定 Docker 的所有核心概念