信长博客站部署
背景: 之前将信长笔记部署在gitPage上, 但由于GitHub访问太慢, 代码经常提交不上去, 而giteePage又关闭掉了, 国内没有找到合适的方案, 因此买了阿里云的服务器, 使用nginx部署, 并使用Webhook+Flask(web服务器)+shell脚本达到代码提交自动化更新
搭建nginx部署博客
nginx安装以及配置
安装
# 安装nginx
yum install nginx
# 自启动
systemctl enable nginx
systemctl start nginx
systemctl status nginx
配置
- 注意/var/www/xinzhang-note/docs/.vitepress/dist为制品目录
server {
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
listen 80;
server_name _;
index index.html;
location / {
# content location
root /var/www/xinzhang-note/docs/.vitepress/dist;
# exact matches -> reverse clean urls -> folders -> not found
try_files $uri $uri.html $uri/ =404;
# non existent pages
error_page 404 /404.html;
# a folder without index.html raises 403 in this setup
error_page 403 /404.html;
# adjust caching headers
# files in the assets folder have hashes filenames
location ~* ^/assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
部署博客
本地代码提交码云
- 信长笔记本地目录结构示意
- Git 全局设置:
# 注意替换用户以及邮箱
git config --global user.name "xinzhang-up"
git config --global user.email "15706918+xinzhang-up@user.noreply.gitee.com"
创建 git 仓库, 在项目根目录下:
git init
git add .
git commit -m "first commit"
# 注意替换仓库地址
git remote add origin https://gitee.com/xinzhang-up/demo.git
git push -u origin "master"
服务器GIT安装以及SSH配置
使用SSH方式在服务器端保存git凭证, 使git pull命令顺利执行, 无需输入密码
- GIT安装
yum install -y git
- SSH配置, 这里使用的是Gitee仓库的部署公钥
官方指南: https://help.gitee.com/repository/ssh-key/generate-and-add-ssh-public-key
# 生成SSH key
ssh-keygen -t rsa
# 查看公钥, 将公钥复制粘贴到gitee仓库的部署公钥上
cat ~/.ssh/id_rsa.pub
# 生成config文件,指定gitee使用的私钥
cat <<EOL | tee ~/.ssh/config > /dev/null
Host gitee-repo
HostName gitee.com
User git
IdentityFile ~/.ssh/id_rsa
EOL
服务器拉取代码并构建
# 安装nodejs
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo yum install -y nodejs
# 拉取代码
mkdir -p /var/www
cd /var/www
git clone https://gitee.com/xinzhang-up/xinzhang-note.git
cd xinzhang-note
# 构建
npm install
npm run docs:build
这里最后一步构建有问题的, 先同步一下node和npm版本, 再试一下
node 版本为v20.13.1, npm 版本为 10.5.2
有个坑, 服务端端构建报错找不到依赖 rollup/rollup-linux-x64-gnu
. 参考博客https://blog.csdn.net/weixin_45012973/article/details/144199095 的解决方案, 在
package.json
中加入以下配置项:
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "*"
}
开放80端口&公网访问博客
- xinzhang-note构建完成后制品目录在: /var/www/xinzhang-note/docs/.vitepress/dist
- 服务器防火墙开放80端口, 外网即可访问博客: http://120.24.243.46/
搭建webhook服务实现代码提交博客自动更新
服务器端搭建webhook.service
webhook.service使用Flask框架, Flask是一个轻量级的Python Web框架, 这里用途是接收webhook请求, 然后执行shell脚本, 拉取并构建vitePress项目, 然后刷新nginx
- 安装python
yum install -y curl wget python3 python3-pip
# 验证安装
python3 --version # 应输出 Python 3.x
- 创建目录结构
sudo mkdir -p /opt/webhook_listener
cd /opt/webhook_listener
sudo mkdir logs
- 创建webhook.py, 这个脚本要注意:
- 这里验签采用的是webhook密码的方式(需要将脚本中xxx改成在码云webhook中配置的密码), 若是秘钥则需要调整下verify_signature方法
- 码云webhook请求超时时间为10s, 而vitePress构建时间比较长, 因此这里采用异步执行
cat > webhook.py << 'EOF'
from flask import Flask, request, abort
import subprocess
import hmac
import hashlib
import logging
from concurrent.futures import ThreadPoolExecutor
app = Flask(__name__)
logging.basicConfig(filename='logs/webhook.log', level=logging.INFO)
# 码云 Webhook 密钥(需与码云配置一致)
WEBHOOK_SECRET = "xxx"
# 创建线程池
executor = ThreadPoolExecutor(max_workers=1)
def verify_signature(body):
signature = request.headers.get('X-Gitee-Token')
return WEBHOOK_SECRET == signature
def run_deploy_script():
try:
result = subprocess.run(
["/opt/webhook_listener/deploy.sh"],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
logging.info(f"Deploy success: {result.stdout}")
except subprocess.CalledProcessError as e:
logging.error(f"Deploy failed: {e.stderr}")
@app.route('/webhook', methods=['POST'])
def handle_webhook():
# 验证签名
if not verify_signature(request.data.decode()):
abort(403, "Invalid signature")
# 记录请求信息
logging.info(f"Webhook received from IP: {request.remote_addr}")
# 异步执行部署脚本
executor.submit(run_deploy_script)
# 立即返回响应
return "✅ 触发构建成功", 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
EOF
- 创建deploy.sh
cat > deploy.sh << 'EOF'
#!/bin/bash
# 进入项目目录
cd /var/www/xinzhang-note
# 拉取合并最新代码
git pull origin master
# 清理旧文件
rm -rf docs/.vitepress/dist
# 安装依赖并构建
# npm install
npm run docs:build
# 重载 Nginx
nginx -s reload
echo "✅ 部署完成于 $(date)"
EOF
- 赋予脚本执行权限
chmod +x webhook.py deploy.sh
- 创建webhook.service的启动命令, 注意将xxx替换成码云webhook密码
sudo tee /etc/systemd/system/webhook.service > /dev/null << 'EOF'
[Unit]
Description=Webhook Listener Service
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/opt/webhook_listener
ExecStart=/usr/bin/python3 webhook.py
Restart=always
RestartSec=10
Environment=WEBHOOK_SECRET=xxx
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=webhook_listener
[Install]
WantedBy=multi-user.target
EOF
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 启用服务(开机自启动)
sudo systemctl enable webhook.service
# 启动服务
sudo systemctl start webhook.service
到此, webhook.service就可以通过systemctl命令来操作了
服务器nginx配置/webhook路由
目的是将webhook请求转发至本地webhook.service, 这里我不想对外暴露webhook服务
- 在/etc/nginx/conf.d/xinzhang-note.conf中添加如下路由
location /webhook {
proxy_pass http://127.0.0.1:5000/webhook;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
码云配置webhook钩子
每次构建都会触发webhook, 发送请求至webhook.service服务
- url即为Flask服务设置的url, IP为服务器公网IP, 后续会替换成域名
- 添加webhook时有个WebHook密码, 要与上文Flask服务中设置的密码一致(如果使用签名秘钥, 需要变更上文webhook.py中的验签方法)
- 自此, 代码提交就会触发webhook, 发送/webhook请求, webhook.service接收到请求后, 执行deploy.sh脚本, 重新构建xinzhang-note, 博客站就实现了刷新
域名与HTTPS
申请域名
- 阿里云申请域名, 以及备案(备案需要实名认证+居住证+其他一些资料, 申请完成预计1-2周下来)
- 网站主页底部需要标明备案信息, 并链接工信部网站
HTTPS
- Certbot 是 Let's Encrypt (全球最大的免费证书颁发机构)的官方客户端工具,用于自动化获取、安装和续期 SSL/TLS 证书 。
# 1. 安装 EPEL 仓库(如果未安装)
sudo yum install epel-release
# 2. 安装 Certbot 和 Nginx 插件
sudo yum install certbot python3-certbot-nginx
# 3. 一键获取证书(自动修改 Nginx 配置)
sudo certbot --nginx -d xinzhang.cc -d www.xinzhang.cc
- ngx配置参考如下, 注意阿里云也需要放开443端口
# HTTP 配置(监听 80 端口,用于重定向到 HTTPS)
server {
listen 80;
server_name xinzhang.cc www.xinzhang.cc; # 明确指定域名
# 强制跳转到 HTTPS
return 301 https://$host$request_uri;
}
# HTTPS 配置(监听 443 端口)
server {
listen 443 ssl;
server_name xinzhang.cc www.xinzhang.cc;
# SSL 证书路径(Certbot 会自动填充)
ssl_certificate /etc/letsencrypt/live/xinzhang.cc/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/xinzhang.cc/privkey.pem; # managed by Certbot
# 原有配置(压缩、根目录、路由等)
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
root /var/www/xinzhang-note/docs/.vitepress/dist;
index index.html;
location / {
try_files $uri $uri.html $uri/ =404;
error_page 404 /404.html;
error_page 403 /404.html;
location ~* ^/assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# Webhook 反向代理配置
location /webhook {
proxy_pass http://127.0.0.1:5000/webhook;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# SSL 协议优化(可选但推荐)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+AESGCM:EDH+AESGCM;
}
Q&A
心得体会
- 博客站是用vitePress搭建的(nodejs), 服务端使用的是python的flask框架, 执行的shell脚本, 最后这个博客内容主要还是java技术笔记, 还真是个综合性项目...
- 难度不算高, 但坑很多, 使用vitePress/vuePress搭建之初, 就计划侧边栏菜单一定要自动生成, 我只想关注笔记核心内容, 以及一定要实现代码提交博客的自动更新, 以下是遇到的诸多的坑:
- vuePress/vitePress的目录结构有严格要求, 一定要细读官方文档, 确保熟悉了目录结构以及相关配置, 本笔记也给出了好几个截图参考
- 侧边栏自动生成的js脚本, 我用llm生成的, 目前llm无法一步到位, 建议先手动配置导航栏, 调试ok了, 然后再让AI参考生成, 准确率更高, 笔记中也给出了prompt参考
- python脚本, shell脚本也是用llm生成的, 直接生成的脚本会有一些问题, 如生成的python是3.7语法的, 但我的环境是3.6的; 生成的码云wenhook验签方法是瞎编的等等, 需要结合自己的经验知识, 对生成内容做鉴别和调整, 并且对整体实现思路有一定把控, 然后重新开启一个对话, 精细化调整prompt, 使llm生成的内容更可靠
- 举个例子, 地面有个水坑, 问llm如何过去, llm可能给出架座桥的大致步骤, 这时候我觉得跨一步就可以过了, 没必要架桥, 于是我调整prompt, 问llm如何迈出合适的步子使我跨过这个水坑, llm给出的答案就精准多了
为啥叫信长笔记2.0?
- 信长是我在第一家公司使用的花名, 来自于全职猎人中蜘蛛旅团成员"信长"的角色, 仅作为我网络昵称, 无特殊含义
- 笔记1.0时代(https://www.yuque.com/xinzhang0618/xinzhang), 如下图, 主要是按书籍, 课程的维护来整理笔记的, 2.0时代, 我开始按照知识体系, 打碎书籍课程的隔离, 将知识重新梳理和整合
- 之前我的笔记维护在语雀/飞书, 但使用云平台最大的问题是平台依赖会越来越重, 也难导出, 随着AI时代的来临, 这些笔记也是宝贵的个人知识库, 因此我计划逐步整理迁移下来, 搭建自己的博客站, 也在此过程中重新梳理知识体系