目录
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-actionappleboy/scp-actionrsync + 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 作废
- 保持最小暴露面
十一、这次实战里最值得记住的结论
如果把这篇文章压缩成几句最重要的话,大概就是:
- SSH Key 是一对密钥:私钥自己保管,公钥交给服务器
- GitHub Actions 作为 SSH 客户端,必须持有私钥
- 目标服务器要保存对应公钥到
authorized_keys - 自动部署最好单独生成一把专用 Key,不和日常登录混用
ed25519是现代环境里非常推荐的选择- 私钥最敏感,不能泄露,不能提交 Git
十二、结语
很多时候,自动部署卡住,并不是卡在 Docker、GHCR 或 GitHub Actions 本身,而是卡在最基础的“连接凭证”这一层。
SSH Key 一旦理解透了,后面很多事情都会顺很多:
- 自动部署
- 代码同步
- 远程执行脚本
- 多服务器运维
- CI/CD 管道落地
它不是一个“顺手配一下”的小知识点,而是一整套自动化工程实践里的基础设施。
所以与其背命令,不如把底层逻辑想明白:
谁发起连接,谁拿私钥;谁接收连接,谁保存公钥。
一旦这句真正刻进脑子里,后面再配 GitHub Actions SSH 登录,你就不会再晕了。
文文,2026 年 3 月 21 日
部署这件事,表面拼的是命令,底层拼的是你对每一层凭证和链路的理解~ 💕
