GitHub Actions 自动部署到 VPS:从零搭建 CI/CD 流水线

还记得那些年用 FTP 手动上传代码的日子吗?每次改一行配置,都要打开 FileZilla,找到对应目录,拖拽文件,祈祷没有遗漏。部署完还要手动刷新浏览器检查效果,万一出错又得回滚——整个过程耗时、低效,还容易因人为疏忽导致线上事故。

本文将教你如何用 GitHub Actions 搭建自动部署流水线,让代码推送后自动测试、构建、部署到 VPS,彻底告别手动上传的低效流程。

如果你正在使用 Hostease 的 VPS 或[独立服务器](https://cn.hostease.com/dedicated-server/)托管项目,那么恭喜你,你已经拥有了强大的基础设施。现在,只需要再迈出一步——借助 GitHub Actions 搭建 CI/CD 流水线,就能让每一次代码推送自动触发测试、构建和部署,把重复劳动彻底交给机器。

本文将从零开始,带你搭建一条完整的 GitHub Actions 自动部署流水线,涵盖核心概念、实战配置、安全加固以及多环境进阶方案。

一、GitHub Actions 核心概念

在动手写配置之前,先搞清楚四个关键术语:

  • Workflow(工作流):存放在 .github/workflows/ 目录下的 YAML 文件,定义了一整套自动化流程。一个仓库可以有多个 workflow,分别负责测试、部署、发布等不同任务。
  • Job(作业):workflow 中的一个独立执行单元。多个 job 默认并行运行,也可以用 needs 关键字串行依赖。每个 job 运行在独立的虚拟机(runner)上。
  • Step(步骤):job 内的具体操作,可以是一条 shell 命令,也可以是调用社区提供的 Action。步骤按顺序依次执行。
  • Runner(运行器):执行 job 的服务器环境。GitHub 提供免费的 ubuntu-latestwindows-latest 等托管 runner,也可以使用自托管 runner。

它们的关系是:workflow 包含多个 job,每个 job 包含多个 step,每个 job 运行在一个 runner 上。

GitHub Actions 的免费额度

对于公开仓库,GitHub Actions 完全免费。私有仓库每月有 2000 分钟的免费额度(Linux runner),对于个人项目和中小型团队来说绰绰有余。这也是它相比 Jenkins 等自建方案的最大优势——零运维成本。

二、实战:编写 deploy.yml

接下来我们以一个典型的前端项目为例(构建后部署到 VPS),编写完整的 workflow 配置文件。

2.1 创建 workflow 文件

在项目根目录创建 .github/workflows/deploy.yml

name: Deploy to VPS

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Build project
        run: npm run build

      - name: Deploy to VPS via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/myapp
            git pull origin main
            npm ci --production
            npm run build
            pm2 restart myapp

2.2 逐行解析

  • on: push → branches: main:仅当代码推送到 main 分支时触发,避免开发分支的频繁触发。
  • actions/checkout@v4:将仓库代码克隆到 runner 的工作目录。
  • actions/setup-node@v4:安装指定版本的 Node.js,并启用 npm 缓存加速后续构建。
  • npm ci:严格按照 lock 文件安装依赖,比 npm install 更快更可靠,适合 CI 环境。
  • npm test:运行测试套件。如果测试失败,后续步骤不会执行,部署自动中断。
  • appleboy/ssh-action:社区广泛使用的 SSH Action,通过 SSH 连接 VPS 并执行远程命令。

2.3 替代方案:rsync 同步构建产物

如果你不想在 VPS 上重复构建,也可以选择在 runner 上构建完成后,用 rsync 只同步产物目录:

      - name: Deploy build artifacts via rsync
        uses: burnett01/rsync-deployments@7.0.1
        with:
          switches: -avzr --delete
          path: ./dist/
          remote_path: /var/www/myapp/dist/
          remote_host: ${{ secrets.SERVER_HOST }}
          remote_user: ${{ secrets.SERVER_USER }}
          remote_key: ${{ secrets.SSH_PRIVATE_KEY }}

这种方式适合纯静态站点,VPS 上只需一个 Nginx 指向 /var/www/myapp/dist/ 即可。

三、安全配置:Secrets、SSH Key 与 known_hosts

CI/CD 流水线中涉及服务器密码、私钥等敏感信息,绝不能硬编码在 YAML 文件中。GitHub 提供了 Secrets 机制来安全存储这些凭据。

3.1 生成 SSH 密钥对

在本地终端执行以下命令,生成专用的部署密钥:

ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_key -N ""

这会生成两个文件:

  • deploy_key(私钥)→ 存入 GitHub Secrets
  • deploy_key.pub(公钥)→ 部署到 VPS 的 ~/.ssh/authorized_keys

3.2 配置 VPS 端

将公钥添加到 VPS 的授权列表:

cat ~/.ssh/deploy_key.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

如果你的 VPS 面板支持 SSH Key 管理,也可以通过面板界面直接添加公钥,操作更加直观。

3.3 配置 GitHub Secrets

进入仓库 → Settings → Secrets and variables → Actions,添加以下三个 Secrets:

  • SERVER_HOST:VPS 的 IP 地址或域名,例如 123.45.67.89
  • SERVER_USER:SSH 登录用户名,例如 deploy
  • SSH_PRIVATE_KEY:上一步生成的私钥完整内容,包括 -----BEGIN OPENSSH PRIVATE KEY----- 和结尾标记

3.4 获取 known_hosts 指纹

为防止 SSH 中间人攻击,建议在 workflow 中固定 known_hosts

ssh-keyscan -H 123.45.67.89 >> ~/.ssh/known_hosts

然后将输出内容存入 KNOWN_HOSTS Secret,在 Action 中使用:

      - name: Setup SSH known hosts
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
          ssh-known-hosts: ${{ secrets.KNOWN_HOSTS }}

四、进阶:多环境部署与回滚策略

当项目步入正轨,你通常需要区分 staging(预发布)和 production(生产)两套环境。GitHub Actions 通过 Environment 功能优雅地解决了这个需求。

4.1 多环境 Workflow

name: Multi-Environment Deploy

on:
  push:
    branches:
      - develop
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}

    steps:
      - uses: actions/checkout@v4

      - name: Deploy
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ github.ref == 'refs/heads/main' && secrets.PROD_HOST || secrets.STAGING_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd ${{ github.ref == 'refs/heads/main' && '/var/www/prod' || '/var/www/staging' }}
            git fetch --all
            git reset --hard origin/${{ github.ref == 'refs/heads/main' && 'main' || 'develop' }}
            npm ci --production
            npm run build
            pm2 restart ${{ github.ref == 'refs/heads/main' && 'prod-app' || 'staging-app' }}

在 GitHub 仓库的 Settings → Environments 中分别创建 stagingproduction 环境,并为 production 环境添加审批保护——这样每次部署到生产环境前,都需要指定人员手动批准。

4.2 回滚策略

即使有自动化测试保驾护航,线上偶尔仍会出问题。以下是两种实用的回滚方案:

方案一:Git commit 回滚

# 在 VPS 上回退到上一个版本
cd /var/www/myapp
git log --oneline -5          # 查看最近5次提交
git reset --hard abc1234      # 回退到指定 commit
npm ci --production
npm run build
pm2 restart myapp

方案二:Release Tag 部署

将触发条件改为 tag 推送,每次部署对应一个版本标签,回滚时切换到指定 tag 即可:

on:
  push:
    tags:
      - 'v*'

4.3 通知与监控

部署完成后,可以通过 Slack、Telegram 或钉钉等渠道发送通知。以下是一个 Telegram 通知的示例步骤:

      - name: Send Telegram notification
        if: always()
        uses: appleboy/telegram-action@v1
        with:
          to: ${{ secrets.TELEGRAM_CHAT_ID }}
          token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
          message: |
            🚀 部署 ${{ job.status }}
            📦 分支: ${{ github.ref_name }}
            📝 提交: ${{ github.event.head_commit.message }}
            👤 作者: ${{ github.actor }}

更多服务器运维相关内容,可以参考 服务器运维指南 中的系列教程。

更多选择 VPS相关内容,可以参考 主机选购指南 中的系列教程。

工作流优化技巧

当你的 CI/CD 流水线运行一段时间后,可能会遇到构建速度变慢、配额消耗过快等问题。以下几个优化策略可以显著提升效率并降低成本。

缓存依赖加速构建

每次 CI 运行都重新安装依赖会浪费大量时间。使用缓存 Action 可以将依赖缓存在 GitHub 的对象存储中,通常能将安装步骤从两三分钟缩短到十秒以内。

矩阵策略实现多环境测试

如果你的项目需要在多个 Node.js 版本或操作系统上测试,矩阵策略是最优雅的方案。只需在工作流中定义矩阵变量,GitHub Actions 会自动为每种组合创建独立任务并行运行。

自托管 Runner 的成本控制

对于私有仓库,GitHub Actions 的免费额度有限。如果构建频繁,可以考虑使用自托管 Runner,将 CI 任务跑在自己的 VPS 上,省去按分钟计费的成本。

总结与行动建议

通过本文,你已经了解了 GitHub Actions 的核心概念,并掌握了从基础到进阶的完整部署方案。回顾一下关键要点:

  • Workflow → Job → Step → Runner,四层结构清晰分工
  • 使用 Secrets 存储敏感信息,公钥部署到 VPS,私钥交给 GitHub
  • rsync 适合静态站点,SSH + 远程脚本适合需要在服务器构建的项目
  • Environment + 分支策略实现多环境隔离,tag 部署便于版本回滚

现在就行动起来吧:

  1. 打开你的 GitHub 仓库,创建 .github/workflows/deploy.yml
  2. 生成 SSH 密钥对,配置 Secrets
  3. 推一次代码,观察 Actions 页面的绿色勾 ✅

如果你正在寻找一台稳定可靠的服务器来托管项目,不妨了解一下 Hostease 提供的 VPS 方案——配合 GitHub Actions 的自动化流水线,你将拥有一套真正省心的开发部署体验。关于[服务器配置](https://cn.hostease.com/blog/server/)与优化的更多技巧,也可以参考我们的 VPS 托管指南技术博客,助你高效运维,专注开发。

建议将本文收藏为部署清单,每次上线新项目时对照检查,可以避免 90% 的常见配置问题。

发表评论