GitHub Actions 自动化部署手把手教程:从零构建 CI/CD 工作流并发布至自有服务器
在日常开发中,每次提交代码后都要手动登录服务器、拉取最新代码、执行打包编译、重启服务,这一套机械化的操作不仅繁琐,而且极易因遗漏某一步骤导致线上事故。
借助 GitHub 官方提供的 GitHub Actions,我们可以非常轻松地为项目配置一套全自动的 CI/CD(持续集成/持续部署)流水线。只要往指定分支 Push 代码,GitHub 就会自动运行测试、打包,并安全地部署到你自己的云服务器上。
本文将以一个常见的 Node.js/前端项目为例,手把手带你配置一套直达自有 VPS 服务器的自动化部署流程。
准备工作
在配置流水线之前,需要准备好以下要素:
- GitHub 仓库:存放你的项目代码。
- 一台云服务器:确保可以通过 SSH 登录(拥有公网 IP)。
- 基本的 Linux 操作常识:知道如何创建目录及修改文件权限。
第一步:配置安全的 SSH 免密登录
GitHub Actions 运行在 GitHub 提供的托管虚拟环境(Runner)中。要让 Runner 能够把打包好的文件发送到你的服务器并执行重启命令,Runner 必须拥有登录你服务器的权限。
为了安全起见,绝对不能直接将服务器的 root 密码写在脚本里。我们必须使用 SSH Key(密钥对) 来完成鉴权。
1. 在本地或服务器上生成一套专用的密钥对
执行以下命令(不要一路回车,建议给这个专门用于部署的密钥起个名字,比如 id_rsa_deploy):
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
这会生成两个文件:
id_rsa_deploy(私钥,留在 GitHub)id_rsa_deploy.pub(公钥,放到服务器)
2. 将公钥部署到目标服务器
登录你的服务器,将 id_rsa_deploy.pub 中的内容追加到目标部署用户家目录下的 .ssh/authorized_keys 文件中:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat id_rsa_deploy.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
(注意:如果使用的是非 root 用户登录,确保该用户对部署目录拥有读写权限。)
3. 在 GitHub 仓库配置 Secrets
为了保护隐私,密钥、服务器 IP 等敏感信息不能直接写在代码仓库的 YAML 文件中。GitHub 提供了 Secrets 功能来安全地存储这些变量。
依次点击仓库的:Settings -> Secrets and variables -> Actions -> New repository secret,依次添加以下 4 个变量:
| Secret 名称 | 对应内容 | 示例 |
|---|---|---|
SERVER_HOST |
服务器的公网 IP 地址 | 123.45.67.89 |
SERVER_USER |
登录服务器的用户名 | root 或 deploy-user |
SERVER_SSH_KEY |
刚刚生成的 私钥 (id_rsa_deploy) 的完整内容 |
-----BEGIN RSA PRIVATE KEY----- ... |
SERVER_PORT |
SSH 端口(默认是 22) | 22 |
第二步:编写 GitHub Actions 工作流文件
在项目根目录下,创建 .github/workflows 文件夹,并在其中新建一个名为 deploy.yml 的文件。
这个 YAML 文件定义了流水线在什么时机触发、需要运行哪些步骤。以下是一个标准的、带依赖缓存的前端打包并部署至 VPS 的完整工作流配置:
name: Build and Deploy
# 触发条件:当 main 分支收到 push 请求时触发
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. 拉取仓库代码
- name: Checkout Code
uses: actions/checkout@v4
# 2. 设置 Node.js 环境
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
# 3. 配置缓存(优化构建速度,避免每次都完整下载 node_modules)
- name: Cache Node Modules
uses: actions/cache@v4
id: node-cache
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# 4. 安装依赖并执行打包
- name: Install Dependencies & Build
run: |
npm install
npm run build
# 5. 将打包产物同步到服务器 (使用 appleboy/scp-action)
- name: Copy Files to Server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
port: ${{ secrets.SERVER_PORT }}
# source 是你要复制的本地文件/文件夹,dist 是打包生成的静态资源目录
source: "dist/*"
# target 是服务器上的目标部署路径
target: "/var/www/my-app"
strip_components: 1 # 去除 dist 层级,直接把内容扔进 my-app
# 6. 在服务器上执行后续命令(如重启 Nginx、PM2,清理旧文件等)
- name: SSH and Restart Services
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
port: ${{ secrets.SERVER_PORT }}
script: |
# 示例:如果是 Node 后端项目,可以在这里重启 PM2
# cd /var/www/my-app && pm2 restart all
# 如果是前端静态项目,重载 Nginx 即可
sudo nginx -s reload
第三步:实战踩坑与优化经验
在实际应用中,鲜有一次性配置成功不报错的。这里整理了几个在搭建 CI/CD 过程中最容易遇到的“深坑”:
1. 权限不足导致 SCP 失败 (Permission Denied)
如果你的 SERVER_USER 不是 root,而是自定义的普通用户(如 deploy),那么当 GitHub Actions 尝试向 /var/www/my-app 写入文件时,极有可能会报权限错误。
解决方案:
提前登录服务器,将目标目录的所有者修改为该部署用户,或者赋予其写权限:
sudo chown -R deploy:deploy /var/www/my-app
2. 缓存配置失效,每次构建依然很慢
在 actions/cache 步骤中,缓存的唯一标识是基于 package-lock.json 的哈希值。如果你的项目根目录下实际使用的是 yarn.lock 或 pnpm-lock.yaml,请务必修改对应的 key 计算规则。例如使用 pnpm 时:
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
3. 目标服务器目录积累大量“历史垃圾”
appleboy/scp-action 默认只会覆盖同名文件,并不会自动删除服务器上已经失效的旧文件(比如旧的带 hash 值的 js 文件)。日积月累会导致服务器磁盘被撑爆。
优化方案:
在拷贝文件之前,先通过 ssh-action 执行清空历史的操作,或者在打包后直接将整站打包为 tar.gz 压缩包上传,在服务器端解压并覆盖。
例如在 SSH and Restart Services 步骤中加入:
cd /var/www/my-app && rm -rf static/
4. 首次连接报错 "Host key verification failed"
当使用第三方 Action 连接服务器时,有时会因为未知的主机密钥而连接中断。appleboy/ssh-action 默认处理了这个问题,但如果你使用的是原生 ssh 命令,记得在 workflow 脚本中加上 -o StrictHostKeyChecking=no 参数来跳过公钥确认。
检验成果
完成上述配置并把 .github/workflows/deploy.yml 提交并 Push 到 GitHub 仓库的 main 分支后,点击仓库顶部的 Actions 标签页,就能看到正在运行的工作流:
(此处可查看具体的步骤日志)
每一个步骤左侧都会亮起绿色的对勾,代表该步骤执行成功。如果某一步出错,点击进入即可查看详细的报错日志,方便针对性排查。
至此,一个从零搭建的自动化部署流水线正式运转。未来你只需专注写代码,剩下的打包、传输、部署工作,全部交由 GitHub Actions 自动搞定。