每次修改代码后手动登录服务器、上传文件、重启服务——这套流程做一次要 10 分钟,一天改三次就是半小时。如果你正在管理一个网站或 Web 应用,如何让部署变得自动化且可靠,是提升开发效率的关键一步。
GitHub Actions 是 GitHub 内置的 CI/CD(持续集成/持续部署)工具,它能在你推送代码时自动触发构建和部署流程。配合一台 VPS(虚拟专用服务器),你可以搭建一套零成本(GitHub Actions 免费额度足够个人项目使用)的自动化部署流水线。本文将带你从零完成整套配置,包括 SSH 密钥设置、workflow 编写、rsync 文件同步和 Docker 容器化部署三种方案。
前提准备:你需要什么
在开始之前,确保以下条件已就绪:
- GitHub 仓库:你的项目代码已托管在 GitHub 上,可以是公开或私有仓库
- 一台 VPS:运行 Ubuntu 20.04+ 或其他主流 Linux 发行版,已配置 SSH 登录。如果你还没有服务器,可以参考 VPS 主机方案,支持按需选择配置
- 基本的命令行操作能力:能通过 SSH 连接服务器、执行基础 Linux 命令
- 项目已配置好构建流程:例如 Node.js 项目的
npm run build,或 Python 项目的构建脚本
本文假设你的 VPS IP 地址为 your-server-ip,SSH 用户为 deploy,实际操作时替换为你自己的值即可。
第一步:生成 SSH 密钥并配置 GitHub Secrets
GitHub Actions 需要通过 SSH 连接到你的 VPS 来执行部署命令。出于安全考虑,我们不使用你的个人 SSH 密钥,而是专门为 CI/CD 生成一对独立密钥。
在本地终端执行以下命令生成密钥对:
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_deploy -N ""
这条命令会在 ~/.ssh/ 目录下生成两个文件:github_deploy(私钥)和 github_deploy.pub(公钥)。-N "" 表示不设置密钥密码,这样 GitHub Actions 运行时无需交互输入。
接下来,将公钥添加到 VPS 的授权列表中:
cat ~/.ssh/github_deploy.pub | ssh root@your-server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
如果你使用的是非 root 用户(推荐),将 root 替换为对应用户名。同时建议在 VPS 上为部署创建专用用户并限制权限:
# 在 VPS 上执行
useradd -m deploy
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
然后将私钥内容和服务器信息配置到 GitHub 仓库的 Secrets 中。打开仓库页面,进入 Settings → Secrets and variables → Actions,添加以下三个 Secrets:
SSH_PRIVATE_KEY:粘贴~/.ssh/github_deploy文件的完整内容(包括 BEGIN 和 END 行)SERVER_HOST:你的 VPS IP 地址,例如123.45.67.89SERVER_USER:SSH 用户名,例如deploy
这套密钥体系的好处是:即使密钥泄露,攻击者也只能访问部署目标目录,无法触及服务器其他部分。配合 VPS 的防火墙规则(只允许 SSH 和 Web 端口),安全风险可控。
第二步:编写 GitHub Actions Workflow
在项目根目录下创建 .github/workflows/deploy.yml 文件,这是整个 CI/CD 流水线的核心配置。以下是一个完整的 rsync 部署方案示例:
name: Deploy to VPS
on:
push:
branches: [main]
jobs:
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: Build project
run: npm run build
- name: Deploy via rsync
uses: burnett01/rsync-deployments@7.0.1
with:
switches: -avzr --delete
path: dist/
remote_path: /var/www/html/
remote_host: ${{ secrets.SERVER_HOST }}
remote_user: ${{ secrets.SERVER_USER }}
remote_key: ${{ secrets.SSH_PRIVATE_KEY }}
这段配置的执行逻辑是:当你向 main 分支推送代码时,GitHub Actions 会自动拉取代码、安装依赖、构建项目,然后通过 rsync 将构建产物同步到 VPS 的 /var/www/html/ 目录。--delete 参数会删除 VPS 上不再存在于本地构建输出中的文件,确保两端内容一致。
对于使用 npm 的前端项目,npm ci 比 npm install 更快且更可靠——它严格按照 package-lock.json 安装,不会修改依赖版本。如果你的项目使用其他包管理器,将对应命令替换为 yarn install --frozen-lockfile 或 pnpm install --frozen-lockfile。
第三步:Docker 容器化部署方案
如果你的项目使用 Docker,可以将构建和部署都容器化。这种方式的优势在于:无论 VPS 环境如何变化,容器内的运行环境始终一致,避免了”我本地能跑、服务器上不行”的问题。
首先在项目根目录添加 Dockerfile:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
这个多阶段构建的 Dockerfile 先在 builder 阶段编译前端代码,再将编译产物复制到 Nginx 镜像中。最终镜像只有 Nginx 和静态文件,体积通常不超过 50MB。
对应的 GitHub Actions workflow 部署步骤改为:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/myapp
git pull origin main
docker compose down
docker compose up -d --build
这种方式在 VPS 上拉取最新代码后重新构建容器。首次部署需要在 VPS 上 git clone 项目到 /opt/myapp,后续更新全部由 GitHub Actions 自动完成。
如果你选择 Docker 方案,建议在 VPS 上配置 docker compose 的健康检查,确保新容器启动成功后才停止旧容器。这样即使部署失败,服务也不会中断。对于需要 SSL(安全传输协议) 证书的场景,可以在 Nginx 配置中使用 Let’s Encrypt 自动续签。
验证部署是否成功
配置完成后,向 main 分支推送一次代码来测试。在 GitHub 仓库的 Actions 标签页,你可以看到 workflow 的实时执行状态。绿色对勾表示所有步骤执行成功,红色叉号表示有步骤失败——点击进去可以看到详细的日志输出。
部署成功后,在 VPS 上验证文件是否已同步:
ls -la /var/www/html/
如果使用 Docker 方案,检查容器运行状态:
docker compose ps
docker compose logs --tail=20
一个常见问题是 rsync 报错 Permission denied,这通常是因为部署用户对目标目录没有写权限。解决方法是在 VPS 上执行:
chown -R deploy:deploy /var/www/html/
常见问题与排查
Q:workflow 触发了但部署步骤超时?
检查 VPS 的 SSH 端口是否被防火墙拦截。GitHub Actions 的运行环境使用固定 IP 段,你可以在 VPS 防火墙中放行这些 IP。如果你使用的是 独立服务器,可以在控制面板中直接管理防火墙规则。
Q:构建成功但部署后网站显示空白?
大概率是构建输出路径与 Nginx 配置的 root 路径不一致。确认 workflow 中的 path 字段与项目实际构建输出目录匹配。Vue 项目默认输出到 dist/,Next.js 的静态导出则需要额外配置 output: 'export'。
Q:如何只在特定分支或标签触发部署?
将 on.push.branches 改为你的部署分支,或者使用标签触发:
on:
push:
tags:
- 'v*'
这样只有推送 v1.0.0 这样的版本标签时才会触发部署,适合需要手动控制发布节奏的场景。
总结与下一步
建议你按照以下顺序实施:先配置 SSH 密钥和 GitHub Secrets(约 5 分钟),再创建最基本的 rsync workflow(约 10 分钟),确认基础流程跑通后,再根据项目需要添加构建缓存、多环境部署、通知等高级功能。
如果你需要一台稳定的 VPS 来运行这套 CI/CD 流水线,可以考虑 VPS 主机方案,支持一键部署常见应用环境,配合 GitHub Actions 可以实现从代码提交到线上运行的全自动流程。更多服务器运维和 网站优化 相关教程,欢迎访问 博客 获取。