Docker+Hexo+VPS+webhook 实现博客自动更新
最近正好准备入学,于是想搭建一个博客,重新系统地记录一下自己的学习,本来想简单的部署一个静态博客并托管到 github,又正好看到cloudcone有折扣,打算买了个VPS学习一下,于是脑袋一拍,决定把博客部署到VPS中去。
准备工作
- 一台VPS:我在cloudcone购买
- 一个可解析的域名:我在万网购买
- 一个github账号
思路
- 创建一个hexo博客文件夹 blog/ 并上传到到 github
- 创建一个blog-webhook文件夹用来管理webhook服务,监听blog仓库更新后,拉取更新并重新渲染hexo的静态文件
- webhook 和 hexo 都进行容器化管理,使用nginx-proxy-manager进行反向代理,博客则只暴露静态文件给 nginx
项目
blog
最终blog的文件结构
1 2 3 4 5 6 7 8 9
| BLOG ├── node_modules ├── scaffolds ├── source ├── themes ├── _config.yml ├── db.json ├── Dockerfile └── package.json
|
创建一个默认blog
详细配置可参考hexo官网
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| npm install -g hexo-cli
hexo init blog
cd blog
npm install
hexo s
|
为blog添加容器化能力
在blog根目录创建Dockerfile,用于构建 Docker 镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| FROM node:20-alpine
WORKDIR /app/blog
RUN npm install -g hexo-cli
COPY package.json ./
RUN npm install --production
COPY . .
EXPOSE 4000
|
为blog添加 git 能力
在 GitHub 上创建远端仓库
打开 https://github.com/new
填写信息:
- Repository name: blog
- Description: (可选)
- Visibility: Public 或 Private(按需)
- 初始化选项:不要勾选 README、.gitignore 或 License
点击「Create repository」
完整的本地 Git 初始化 + 推送流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| cd blog
git init
git add .
git commit -m "init hexo blog"
git remote add origin https://github.com/你的用户名/blog.git
git push -u origin develop
|
至此我们完成关于博客部分的创建工作。
blog-webhook
最终blog-webhook目录结构
1 2 3 4 5 6 7
| blog-webhook ├── webhook │ └── scripts │ └── refresh-blog.sh ├── Dockerfile ├── hooks.json └── docker-compose.yml
|
1 2 3 4 5
| mkdir blog-webhook && cd blog-webhook
mkdir webhook && cd webhook
|
创建博客刷新脚本
1 2 3
| mkdir scripts && cd scripts
touch refresh-blog.sh
|
编辑 refresh-blog.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #!/bin/bash set -e
BRANCH="${HEXO_BRANCH:-develop}" GIT_REPO="${GIT_REPO:-https://github.com/your_username/blog.git}"
echo "=============================================" echo "开始刷新博客内容" echo "仓库: $GIT_REPO" echo "分支: $BRANCH" echo "时间: $(date)" echo "============================================="
echo "进入博客目录..." cd /app/blog || { echo "错误:无法进入博客目录"; exit 1; }
echo "修复目录权限..." chown -R $(id -u):$(id -g) .
echo "拉取最新代码 (分支: $BRANCH)..." git fetch origin "$BRANCH" || { echo "错误:fetch 失败"; exit 1; } git reset --hard "origin/$BRANCH" || { echo "错误:reset 失败"; exit 1; }
echo "安装依赖..." npm install || { echo "错误:依赖安装失败"; exit 1; }
echo "清理旧文件..." rm -rf public || echo "警告:public 删除失败"
echo "生成静态文件..." npx hexo generate || { echo "错误:生成静态文件失败"; exit 1; }
if [ -f "public/index.html" ]; then echo "=============================================" echo "博客刷新成功!" echo "最后更新时间: $(date)" echo "=============================================" else echo "=============================================" echo "错误:未找到生成的静态文件!" echo "=============================================" exit 1 fi
|
创建 webhook 服务
在webhook目录下创建hooks.json文件,管理github hook 通知。注意替换关键字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| [ { "id": "hexo-webhook", "execute-command": "/app/scripts/refresh-blog.sh", "command-working-directory": "/app/scripts", "response-message": "Blog refresh triggered", "trigger-rule": { "and": [ { "match": { "type": "payload-hmac-sha1", "secret": "secret", "parameter": { "source": "header", "name": "X-Hub-Signature" } } }, { "match": { "type": "value", "value": "value", "parameter": { "source": "payload", "name": "repository.full_name" } } } ] } } ]
|
添加容器化能力
在 webhook目录下创建 Dockerfile 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| FROM node:20-alpine
RUN apk add --no-cache \ webhook \ git \ bash
WORKDIR /app
COPY ./scripts ./scripts
RUN chmod +x ./scripts/refresh-blog.sh
EXPOSE 9000
CMD ["webhook", "-verbose", "-hooks", "/etc/webhook/hooks.json", "-hotreload"]
|
管理 blog 和 blog-webhook 镜像服务
在 blog-webhook 根目录下创建 docker-compose.yml 管理不同的镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| services: hexo: container_name: hexo build: context: ./blog dockerfile: Dockerfile volumes: - static_files:/app/blog/public - hexo_node_modules:/app/blog/node_modules user: "0:0" restart: always command: sh -c "cd /app/blog && npm install --unsafe-perm --no-optional && hexo generate && tail -f /dev/null" networks: - webproxy
webhook: container_name: hexo-webhook build: context: ./webhook dockerfile: Dockerfile volumes: - ./webhook:/etc/webhook - ./blog:/app/blog - static_files:/app/blog/public - hexo_node_modules:/app/blog/node_modules user: "0:0" ports: - "9001:9000" restart: always networks: - webproxy
hexo-static: image: nginx:alpine container_name: hexo-static volumes: - static_files:/usr/share/nginx/html:ro networks: - webproxy ports: - "8080:80"
volumes: static_files: hexo_node_modules:
// 我自己定义的外部网络,支持不同镜像间通信 networks: webproxy: external: true
|
为blog-webhook添加 git 能力
操作与为blog添加 git 能力相同。
部署