当你的服务部署在本地服务器上(没有公网 IP),如何让 GitHub Actions 构建完成后将产物安全上传到本地设备?暴露 SSH 端口不安全,自建 Runner 又太麻烦。本文将介绍如何利用 Tailscale 让 CI 临时加入虚拟局域网,实现安全传输。

一、方案概述
Tailscale 官方提供了 GitHub Action 工具,可以在工作流运行时创建一个临时节点接入 Tailscale 虚拟局域网。工作流完成后,这个临时节点自动从网络中移除,不留任何痕迹——即不需要手动清理,也不存在遗留的安全隐患。
二、准备工作:理解 Tags 和 Grants
在 Tailscale 中,默认情况下所有归属于你账号的节点可以互相访问。但 GitHub Actions 创建的临时节点必须添加标签(Tags)。节点一旦添加标签就不再归属你的账号,也无法与其他未打标签的节点互相访问。因此建议所有设备都打上标签,然后通过 Grants(访问控制规则)精确配置访问权限。

三、配置步骤
1. 创建标签
进入 Tailscale 控制台 → Access controls → Tags → Create tag。建议创建三个标签:tag:home(家庭设备)、tag:vps(云服务器)、tag:ci(GitHub Actions CI)。标签的拥有者选自己的账号。
返回节点列表,为每个设备选择对应的标签。重要警告:添加标签后节点不再归属你的账号,也无法在控制台移除所有标签。如需恢复,必须在节点上重新执行 tailscale up 重新验证加入。
2. 配置 Grants 访问规则
在 Access controls → Grants 中通过可视化界面配置访问规则。推荐的三条规则:家庭设备可以访问所有设备;所有 VPS 之间可以互相访问;VPS 与 GitHub Actions 可以访问目标设备的指定端口。
对于仅需要 SCP 上传的场景,只需一条规则:允许 tag:ci 访问目标设备 IP 的 22 端口即可。
3. 创建 OAuth 凭证
GitHub Actions 无法手动打开 login.tailscale.com 授权登录,所以需要创建 OAuth 信任凭证。进入 Settings → Trust credentials → Credential → 选择 OAuth。权限只勾选 Auth Keys,标签选择 tag:ci。记录下生成的 client_id 和 secret。

4. 配置 GitHub Actions 工作流
在 GitHub 仓库的 Settings → Secrets and variables → Actions 中添加两个 Secrets:TS_OAUTH_CLIENT_ID 和 TS_OAUTH_SECRET。
在工作流文件中添加 Tailscale 步骤:
- name: Tailscale
uses: tailscale/github-action@v4
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
此外还需要添加一个 ping 参数指向目标设备的 Tailscale IP,并在随后的步骤中执行 SCP/SSH 命令上传文件。

四、效果验证
推送代码触发工作流运行,在构建日志中搜索 “Tailscale is running and connected”,看到这条日志说明 Tailscale 连接成功。此时可以在 Tailscale 控制面板上看到一个带有 tag:ci 标签的临时节点。工作流结束后,该节点自动从面板上消失。
五、安全注意事项
- 标签不可逆:节点打标签后只能重新验证恢复,操作前确认无误
- 最小权限原则:所有设备打标签,通过 grants 精确控制而非默认全互通
- 临时节点自动销毁:工作流结束后自动移除,安全无痕
- Secrets 管理:OAuth 凭据用 GitHub Secrets 存储,不写入工作流文件
六、总结
Tailscale + GitHub Actions 的方案完美解决了本地服务器无公网 IP 时的 CI/CD 部署问题。相比暴露 SSH 端口或自建 Runner,这个方案更安全、更便捷,而且 Tailscale 的免费计划对个人用户完全够用。
原创文章,作者:kp51,如若转载,请注明出处:https://www.kepu51.com/instant-messaging/702.html
