Skip to content
Home
Go back

上手配置一台新的服务器(五):配置日常更新工作流

Updated:

上一篇文章中我们已经把博客跑起来了。但这里留下几个问题:

  1. 服务器配置可能比较低,构建静态网页的过程可能会让服务器资源耗尽。
  2. 目前工作流是其他设备写文章,然后使用 git 推送到 GitHub 上。然后 SSH 登陆服务器再进行 git pull && pnpm build,太笨重了。

这一篇搭建一套自动化流程:本地写完文章 git push,GitHub Actions 在云端构建,构建完成后 Webhook 通知服务器自动拉取。之后更新博客只需将文章推送到 GitHub 即可。

思路

服务器只负责展示构建结果,不负责构建过程。把构建拆到 GitHub Actions 上,构建完产物推到独立的 build 分支,触发 GitHub Webhook 主动推送消息。

GitHub Actions:免费、配置高、速度快的 CI 机器

整体链路:

   git push


GitHub Actions: checkout → install → build → push dist/ 到 build 分支


GitHub Webhook 发 POST 到服务器


服务器 webhook 服务:校验 HMAC → git pull → Nginx 自动生效

构建 GitHub Actions

要使用 GitHub Actions 要在项目根目录下的 .github/workflows 目录编写部署脚本,用于构建博客静态内容后推送到 build 分支。

# .github/workflows/deploy.yml
name: Build and Push to build branch

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: write

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    timeout-minutes: 10

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

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          version: "11.3.0"

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "24"
          cache: "pnpm"

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build
        run: pnpm run build

      - name: Push dist to build branch
        run: |
          cd dist
          git init
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add -A
          git commit -m "Build: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" || exit 0
          git push --force \
            "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \
            HEAD:build

关键点:

服务器 Webhook 配置

接下来让服务器感知到 build 分支的更新。

可以使用 webhook 这个轻量工具来接收 Github Webhooks 的请求。GitHub 收到 push 后向服务器发一个带签名的 POST 请求,服务器校验后执行 git pull

安装 webhook

sudo apt install -y webhook

编写 webhook 配置文件

// -> /etc/webhook/hooks.json
[
  {
    "id": "blog-deploy",
    "execute-command": "/etc/webhook/deploy.sh",        // <---- 触发脚本
    "command-working-directory": "/var/www/blog/dist",  // <---- 目标文件夹
    "trigger-rule": {
      "match": {
        "type": "payload-hmac-sha256",
        "secret": "替换成你自己的随机密钥",
        "parameter": {
          "source": "header",
          "name": "X-Hub-Signature-256"
        }
      }
    }
  }
]

HMAC 签名校验保证只有 GitHub(持有同一个 secret)才能触发脚本。使用下面命令可以生成密钥:

openssl rand -hex 32

编写执行脚本

这是 webhook 触发后实际执行的脚本。逻辑很简单:

  1. 写日志:每次触发都记录时间戳到 /tmp/webhook-deploy.log,方便事后排查这次 webhook 到底有没有执行、什么时候执行的。
  2. 进入工作目录 git fetch + git reset --hard:之所以不用 git pull,是因为 GitHub Actions 对 build 分支是 force push,本地和远端历史完全不重合,git pull 会报冲突。fetch 拿到最新远端状态后 reset --hardorigin/build,干净利落地覆盖本地所有文件。
  3. 拉取成功写入日志
#!/bin/bash

set -euo pipefail

LOG_FILE="/tmp/webhook-deploy.log"

log() {
    echo "[$(date '+%F %T')] $*" >> "$LOG_FILE"
}

log "Deploy triggered"

cd /var/www/blog/dist

git fetch origin build
git reset --hard origin/build
git pull

log "Deploy successful"
sudo chmod +x /etc/webhook/deploy.sh

systemd 服务

webhook 需要以守护进程方式一直在后台运行,用 systemd 管理最合适。几个关键配置:

编写 systemd 单元文件:

sudo vim /etc/systemd/system/webhook.service
# /etc/systemd/system/webhook.service
[Unit]
Description=Webhook server
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/webhook -hooks /etc/webhook/hooks.json -port 9000 -verbose
Restart=always
User=<your_username>  # <---- 修改成自己的用户名

[Install]
WantedBy=multi-user.target

重载 systemd 并设置开机自启:

sudo systemctl daemon-reload  # 让 systemd 识别新写的 service 文件
sudo systemctl enable --now webhook

Nginx 反向代理

blog.conf 的 443 server 块中加一个 location,把 /hooks/ 代理到 webhook:

location /hooks/ {
    proxy_pass http://127.0.0.1:9000/hooks/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

重载 Nginx:

sudo nginx -t && sudo systemctl reload nginx

我们也可以设置单独的子域名 hooks.huazaiki.com,只要和 Github Webhooks 对照上即可。

GitHub Webhook

去 GitHub 仓库 Settings → Webhooks → Add webhook:

字段
Payload URLhttps://hooks.huazaiki.com/blog-deploy
Content typeapplication/json
Secretopenssl rand -hex 32 生成的那个
EventsJust the push event

添加后 GitHub 发一个 ping 测试连通性,显示绿勾就算通了。

踩坑记录

实际配置中踩了几个坑,记下来免得下次再掉进去。

webhook 用哪个用户运行。 一开始我照着教程把 User 设成了 www-data,结果 webhook 触发后 git fetch 因为权限不足静默失败——仓库是我自己的用户 clone 的,www-data 读不了。后来直接把 service 文件里的 User 改成自己的用户名(比如 blogadmin),就绕过了权限问题。比 chown -R www-data:www-data /var/www/blog 更直接,也不用担心以后自己手动进去 git pull 调试时又把文件所有者改回去。

日常使用

配置完成后的日常流程:

  1. 在本地机器上编写文章

  2. git 推送,剩下的全自动

git add . && git commit -m "新文章" && git push origin main

1-2 分钟后访问博客,文章已经在上面了。一次配置,长期省心。



Previous Post
Spring Cloud 上手:用 Nacos 注册中心让服务找到彼此
Next Post
上手配置一台新的服务器(四):部署博客与 HTTPS