架构
写文章 → git push → Gitee → Webhook → 云服务器 → git pull → 构建 → Nginx
全链路延迟 3-5 秒。push 完刷新浏览器,新文章就在了。
最爽的部分:全程不需要打开服务器终端,不需要手动构建,不需要 FTP 上传。
先看需要什么
| 组件 | 干什么用 |
|---|---|
| Python 3 | 跑构建脚本和 Webhook 接收器 |
| Git | 拉取源码 |
| Nginx | 反代 Webhook + 托管静态文件 |
| systemd | 管理 Webhook 服务,挂了自动重启 |
第一步:服务器配 Gitee 访问
生成部署专用密钥:
ssh-keygen -t ed25519 -C "gitee-blog-deploy" -f ~/.ssh/id_ed25519_gitee
加到 Gitee SSH 公钥。配 SSH config:
Host gitee.com
HostName gitee.com
IdentityFile ~/.ssh/id_ed25519_gitee
User git
克隆仓库:
git clone git@gitee.com:username/blog.git /opt/blog
坑: 别忘了
ssh -T git@gitee.com先测一下连通性。装了半天发现 SSH key 没配好就尴尬了。
第二步:构建脚本
200 行 Python,核心逻辑不复杂:
#!/usr/bin/env python3
import os, markdown
from datetime import datetime
def read_posts():
# 遍历 posts/ 解析 frontmatter + markdown
pass
def render_index(posts):
# 生成首页文章列表
pass
def build():
os.makedirs('/opt/website/posts', exist_ok=True)
# 调用渲染函数写文件
pass
- 解析 markdown 的 frontmatter(标题、日期、标签)
- 生成首页、RSS feed、Sitemap
- 输出到
/opt/website/
第三步:部署脚本
三行搞定拉取→构建→部署:
#!/bin/bash
set -eo pipefail
git pull origin master
python3 /opt/blog/deploy/build.py
rsync -a --delete /opt/website/ /opt/nginx/html/blog/
第四步:Webhook 接收器
用 Python 内置 http.server,不需要 Flask 等外部依赖:
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import subprocess, json
class WebhookHandler(BaseHTTPRequestHandler):
def do_POST(self):
body = self.rfile.read(content_length)
event = json.loads(body)
# 只处理 master 分支的 push
if event.get('ref') != 'refs/heads/master':
return self._respond(200, 'Ignored')
# 执行部署
subprocess.run(['bash', '/opt/blog/deploy/deploy.sh'])
def _respond(self, code, msg):
self.send_response(code)
self.end_headers()
self.wfile.write(msg.encode())
监听 127.0.0.1:8765,不对外暴露。通过 Nginx 反代提供公网访问。
为什么用内置 http.server 不用 Flask? 少一个依赖就少一个出问题的点。部署依赖越少越好,够用就行。
第五步:systemd 保活
[Unit]
Description=Blog Webhook Receiver
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/bin/python3 /opt/blog/deploy/webhook_receiver.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
启动:
systemctl daemon-reload
systemctl enable --now blog-webhook
Restart=always 保证进程挂了自动拉起来,不用盯着。
第六步:Nginx 反代
location /webhook/blog-deploy {
proxy_pass http://<docker-gateway-ip>:8765;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
<docker-gateway-ip> 通常是 172.17.0.1(如果 Nginx 在 Docker 里,Webhook 在宿主机上)。
第七步:Gitee 配 Webhook
Gitee 仓库 → 管理 → WebHooks:
| 字段 | 值 |
|---|---|
| URL | https://your-domain.com/webhook/blog-deploy |
| 密码 | 可选,建议加 |
| 事件 | 勾选 Push |
测试:发一个 push,看服务器日志:
[2026-06-12 00:49:46] 🚀 开始部署
[2026-06-12 00:49:46] 📥 拉取最新代码...
[2026-06-12 00:49:46] 🔨 构建静态页面...
[2026-06-12 00:49:46] 📦 部署到 Nginx...
[2026-06-12 00:49:46] ✅ 部署成功!
最终工作流
Obsidian 写文章 → git push → 等 3 秒 → 浏览器刷新看效果
写好,push,完事。
你的博客发布流程是什么? 有没有更骚的方案?评论区聊聊。