Skip to content

部署服务器

规划目录

/humi-web 主目录

/humi-web/docker Docker 相关文件存放目录

/humi-web/nginx/conf.d nginx 配置文件相关目录

/humi-web/app/vitepress/htdocs vitepress 存放目录

/humi-web/certs 证书存放目录

通过 github webhook 自动构建 vitepress

webhook 监听器

js
//index.js

const express = require("express");
const { exec } = require("child_process");
const crypto = require("crypto");

const app = express();
const port = 3000;

// 从环境变量获取 Webhook Secret
const webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;

if (!webhookSecret) {
  console.error("Webhook Secret not defined in environment variable.");
  process.exit(1);
}

app.use(express.json());

app.post("/webhook", (req, res) => {
  const contentType = req.get("content-type");
  const payload =
    contentType === "application/json" ? JSON.stringify(req.body) : req.body;
  console.log(req.headers);

  // 获取请求头中的签名信息
  const signature = req.get("X-Hub-Signature-256");
  if (
    !signature ||
    !verifySignature(payload, signature, webhookSecret) ||
    contentType !== "application/json"
  ) {
    console.error("Invalid signature. Request not from GitHub.");
    return res.status(403).send("Invalid signature");
  }

  // 在这里处理 GitHub Webhook 事件
  //console.log('Received GitHub Webhook:', payload);
  console.log(
    `sh /app/hook.sh ${req.body.repository.owner.name} ${req.body.repository.name}`
  );
  // 执行 Shell 命令
  exec(
    `sh /app/hook.sh ${req.body.repository.owner.name} ${req.body.repository.name}`,
    (error, stdout, stderr) => {
      if (error) {
        console.error(`Error executing deploy script: ${error}`);
      } else {
        console.log(`Deploy script output: ${stdout}`);
      }
    }
  );
  res
    .status(200)
    .send("Webhook received and deploy script executed successfully");
});

function verifySignature(payload, signature, secret) {
  const hmac = crypto.createHmac("sha256", secret);
  const digest = Buffer.from(
    "sha256=" + hmac.update(payload).digest("hex"),
    "utf8"
  );

  const checksum = Buffer.from(signature, "utf8");
  return crypto.timingSafeEqual(digest, checksum);
}

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});
bash
#hook.sh
#!/bin/env sh

if [ ! -d /repo ]
then
        mkdir -p /repo
fi

user=$1
repo=$2
if [ -d /repo/$repo ]
then
        cd /repo/$repo
        git pull https://$GITHUB_USERNAME:$GITHUB_REPO_TOKEN@github.com/$user/$repo.git
else
        git clone https://$GITHUB_USERNAME:$GITHUB_REPO_TOKEN@github.com/$user/$repo.git /repo/$repo
fi


if [ -d /repo/$repo ]
then
        cd /repo/$repo
        yarn install
        yarn run docs:build
        rm -r /vitepress/htdocs
        cp -r docs/.vitepress/dist /vitepress/htdocs

fi

echo "更新完成时间:"$(date)
Dockerfile
FROM node:20.10.0-bullseye
WORKDIR /app
COPY src/* /app

RUN sed -i 's/deb.debian.org/mirrors.tencentyun.com/g' /etc/apt/sources.list
RUN yarn config set registry https://registry.npmmirror.com/
RUN cd /app \
    &&apt update \
    && yarn install

RUN yarn global add pm2
RUN git config --global http.proxy http://clash:17890
CMD ["pm2-runtime", "index.js"]

docker-compose.yaml

yaml
version: "3.1"

services:
  gh_hook:
    build: gh_hook
    working_dir: /app

    environment:
      GITHUB_USERNAME: #
      GITHUB_REPO_TOKEN: #
      GITHUB_WEBHOOK_SECRET: #
    volumes:
      - /humi-web/app/vitepress:/vitepress

当有更新推送到 github 时,github 会调用服务器的 webhook 接口,当接口被调用时,服务器会拉取最新的代码,然后自动构建,构建完成后将静态内容拷贝到/humi-web/app/vitepress/htdocs

配置 Docker

构建 wordpress

Dockerfile:

docker
from wordpress
copy humi-wordpress-setup.sh /

run chmod +x /humi-wordpress-setup.sh && /humi-wordpress-setup.sh
run a2enmod ssl
run a2ensite default-ssl

humi-wordpress-setup.sh:

bash
#!/usr/bin/env sh
dm="example.com"
openssl req -new -newkey rsa:2048 -x509 -nodes -days 3650 -out /etc/ssl/certs/ssl-cert-snakeoil.pem -keyout /etc/ssl/private/ssl-cert-snakeoil.key -subj "/C=CN/ST=ShenZhen/L=ShenZhen/O=Oricur Inc./OU=Web Security/CN=$dm"

docker-compose

yaml
version: "3.1"

services:
  nginx:
    image: nginx
    restart: always
    volumes:
      - /humi-web:/humi
      - /humi-web/nginx/conf.d:/etc/nginx/conf.d
    ports:
      - 80:80
      - 443:443

  wordpress:
    build: wordpress
    restart: always
    environment:
      WORDPRESS_DB_HOST: wp-db
      WORDPRESS_DB_USER: wp
      WORDPRESS_DB_PASSWORD: wppw
      WORDPRESS_DB_NAME: wp
    volumes:
      - wp-data:/var/www/html

  wp-db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: wp
      MYSQL_USER: wp
      MYSQL_PASSWORD: wppw
      MYSQL_RANDOM_ROOT_PASSWORD: "1"
    volumes:
      - wp-db:/var/lib/mysql

volumes:
  wp-data:
  wp-db:

自动获取证书

bash
# acme.sh
curl  https://get.acme.sh | sh -s email=u@qq.com

domain_main='oricur.com'
certs_dir_prefix="/humi-web/certs"


#获取泛域名
export DP_Id=""
export DP_Key=""

cert_wide_domain_dir="$certs_dir_prefix/wide/$domain_main"
mkdir -p $cert_wide_domain_dir
echo "创建文件夹:$cert_wide_domain_dir"

acme.sh --issue --dns dns_dp -d *.$domain_main \
--key-file  $cert_wide_domain_dir/key \
--fullchain-file  $cert_wide_domain_dir/fullchain

#获取根域名
cert_root_domain_dir="$certs_dir_prefix/root/$domain_main"
mkdir -p $cert_root_domain_dir
echo "创建文件夹:$cert_root_domain_dir"
acme.sh --issue --dns dns_dp -d $domain_main \
--key-file $cert_root_domain_dir/key \
--fullchain-file $cert_root_domain_dir/fullchain