VuePress 博客自动部署
2025/5/4大约 1 分钟
VuePress 博客自动部署
本博客基于 VuePress 框架搭建而成,使用的主题为 VuePress-Theme-Hope,但是提供的自动部署功能仅限于 GitHub Pages,而笔者想要在轻量应用服务器上实现博客的自动部署,于是就有了本项目。
需求分析
总体而言,本项目的需求如下。
- 功能需求:笔者用 GitHub 私有仓库托管博客源代码,然后通过 GitHub Action 实现对源代码的翻译,然后通过 GitHub Action 将翻译后的文件部署到轻量应用服务器上,这就是本项目的功能需求。
- 安全需求:GitHub Action 部署时,需要进行身份验证,且使用的用户不能为具有 root 权限的用户。
- 性能需求:部署速度尽量快,且不会对服务器造成过大负担,服务器仅负责博客访问请求,不负责博客内容的管理。
- 配置需求:笔者希望配置过程尽量简单,
技术选型
本项目的技术选型如下。
- 语言:JavaScript
创建博客管理用户
#!/bin/sh
username="blog_user"
# 该脚本必须以 root 权限运行
if [ "$(id -u)" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
# 创建博客管理用户
useradd \
-c "Blog Administrator, used to maintain blog resources and SSL certificates" \
-m \
-s "/bin/sh" \
"${username}"
# 确保博客管理用户无密码且无法通过密码登录
passwd -dlq "${username}"
# 生成 ssh 密钥,算法为 ed25519,文件名为 "${username}_key"
ssh-keygen \
-t ed25519 \
-C "Authentication for Blog Administrator" \
-N "" \
-f "${username}_key"
# 获取博客管理用户的用户目录
user_dir=$(getent passwd "${username}" | cut -d ':' -f6)
# 将公钥添加到博客管理用户的 authorized_keys 文件中
mkdir -p "${user_dir}/.ssh"
cat "${username}_key.pub" >>"${user_dir}/.ssh/authorized_keys"
# 提醒用户保存私钥
echo "Please save the private key file: ${username}_key"
# 退出
exit 0
mkdir -p ~blog_user/blog
mkdir -p ~blog_user/cert
mkdir -p ~blog_user/logs
mkdir -p ~blog_user/nginx
mkdir -p ~blog_user/scripts
配置 nginx HTTP
#!/bin/sh
# 该脚本必须以 root 权限运行
if [ "$(id -u)" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
# 博客管理用户的用户名
username="blog_user"
# 启动 docker 中的 nginx
docker run \
--detach \
--name blog_nginx \
nginx:latest
# 获取博客管理用户的用户目录
user_dir=$(getent passwd "${username}" | cut -d ':' -f6)
# 从 docker 中拷贝 nginx 配置文件到博客管理用户的用户目录
docker cp "blog_nginx:/etc/nginx" "${user_dir}"
# 删除 docker 中的 nginx 容器
docker rm -f blog_nginx
vi /usr/lib/systemd/system/docker_nginx.service
[Unit]
Description="Blog Nginx Service"
After=docker.service network.target
Requires=docker.service
[Service]
# 启动 nginx 前先删除之前的 nginx 容器
ExecStartPre=-/usr/bin/docker rm -f blog_nginx
# 启动 docker 中的 nginx
ExecStart=/usr/bin/docker run \
--name blog_nginx \
-p 80:80 \
-p 443:443 \
-v /home/blog_user/cert:/home/blog_user/cert \
-v /home/blog_user/blog:/home/blog_user/blog \
-v /home/blog_user/logs:/var/log/nginx \
-v /home/blog_user/nginx:/etc/nginx \
nginx:latest
# 重新加载 nginx 配置
ExecReload=/usr/bin/docker exec blog_nginx nginx -s reload
# 停止 nginx
ExecStop=/usr/bin/docker stop blog_nginx
[Install]
WantedBy=multi-user.target
vi ~blog_user/nginx/conf.d/blog_verify_or_redirect.conf
# 定义 HTTP 服务 (80 端口)
server {
listen 80;
listen [::]:80;
server_name blog.agicy.cn;
# 用于 Let's Encrypt 的验证
location /.well-known {
root /home/blog_user/blog;
}
# 重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
配置 certbot
#!/bin/sh
username="blog_user"
domain="blog.agicy.cn"
# 当前用户应当具有 root 权限
if [ "$(id -u)" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
# 博客目录在用户目录下的 blog 文件夹,计算博客目录的绝对路径
blog_dir="$(getent passwd "${username}" | cut -d ':' -f6)/blog"
# 生成 SSL 证书
certbot certonly --webroot \
--email="2359800311@qq.com" \
--webroot-path="${blog_dir}" --domains="${domain}"
vi ~blog_user/scripts/certbot_renew.sh
#!/bin/sh
username="blog_user"
domain="blog.agicy.cn"
# 该脚本必须以 root 权限运行
if [ "$(id -u)" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
# 计算博客管理用户的用户目录
user_dir="$(getent passwd "${username}" | cut -d ':' -f6)"
# 创建博客管理用户目录下的 cert 文件夹
mkdir -p "${user_dir}/cert"
# 生成 SSL 证书
certbot renew
# 通过 umask 设定生成的文件权限不超出 -rwxr-x---
umask 0027
# 将生成的 SSL 证书复制到 blog_user 的用户目录,设定权限为 -rw-r-----
cp "/etc/letsencrypt/live/${domain}/privkey.pem" "${user_dir}/cert"
cp "/etc/letsencrypt/live/${domain}/fullchain.pem" "${user_dir}/cert"
chmod 640 "${user_dir}/cert/privkey.pem"
chmod 640 "${user_dir}/cert/fullchain.pem"
# 获取 blog_nginx 容器的中 nginx 用户的组
nginx_gid=$(docker exec blog_nginx id -g nginx)
# 输出 nginx 用户的组
echo "nginx group id is ${nginx_gid}"
# 设置 SSL 证书的组为 nginx
chgrp -R "${nginx_gid}" "${user_dir}/cert"
vi /usr/lib/systemd/system/certbot_renew.service
[Unit]
Description="Let's Encrypt certificates for blog.agicy.cn"
[Service]
Type=oneshot
ExecStart=/bin/sh "/home/blog_user/scripts/certbot_renew.sh"
[Install]
WantedBy=multi-user.target
vi /usr/lib/systemd/system/certbot_renew.timer
[Unit]
Description=Renew Let's Encrypt certificates for blog.agicy.cn
[Timer]
Unit=certbot_renew.service
OnCalendar=*-*-* 00:00:00
[Install]
WantedBy=multi-user.target
配置 nginx HTTPS
vi ~blog_user/nginx/conf.d/blog.conf
标题 2
这里是内容。
标题 3
这里是内容。