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 能力相同。
部署