astro-yukunhh-blog/deploy/deploy.sh
yukun-hh 12dd13a76f feat: init Astro blog with wikilinks, KaTeX and local search
- Astro 5 static blog, zero runtime JS
- Obsidian wikilink remark plugin (slug matches Astro content collection)
- KaTeX math rendering, local search, TOC, archives, tags
- 5 posts on math/physics/ML topics
- deploy scripts for nginx + certbot + rsync
2026-08-14 00:19:33 +08:00

307 lines
12 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Yukun's Blog · 部署脚本
#
# 用法:
# ./deploy/deploy.sh 博客:构建 → rsync → reload nginx
# ./deploy/deploy.sh setup-nginx 博客上传并启用站点配置HTTP 直通)
# ./deploy/deploy.sh certbot 博客:签 HTTPS 证书并自动启用 443 + 80 跳转
# ./deploy/deploy.sh doctor 诊断并清理残留的 baidu 反代配置
#
# 子域名反代请用同目录的 proxy.sh如 ./deploy/proxy.sh db 7000
# 首次使用前改下面「配置区」。建议以 root 运行;非 root 需配好免密 sudo。
set -euo pipefail
# ====== 配置区(按你的 VPS 修改) ======
REMOTE_USER="root" # SSH 用户
REMOTE_HOST="sausagetoast.cloud" # VPS 地址 / 主域名
REMOTE_DIR="/var/www/yukun" # 博客站点根目录
NGINX_RELOAD=1 # 1=博客发布后 reload nginx
# ========================================
SSH_TARGET="${REMOTE_USER}@${REMOTE_HOST}"
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
SSH_OPTS="-o StrictHostKeyChecking=accept-new"
# 通用远端执行(支持 &&root 免 sudo非 root 自动 sudo
remote_run() {
local cmd="$1"
ssh $SSH_OPTS "$SSH_TARGET" "bash -s" <<REMOTE
set -euo pipefail
SUDO=""
[ "\$(id -u)" -ne 0 ] && SUDO="sudo"
if [ -n "\$SUDO" ]; then exec \$SUDO bash -c '$cmd'; else $cmd; fi
REMOTE
}
# 启用 HTTPS 的 awk 程序(取消 443 段注释 + 80 段切跳转 + 注释 include
# 同时适用于博客与 db共用 @@HTTPS@@ / @@HTTPS-REDIRECT@@ / @@HTTP-SERVE@@ 标记)
read -r -d '' ENABLE_HTTPS_AWK <<'AWKPROG' || true
BEGIN { in443=0; inredir=0; inserv=0 }
/@@HTTPS-START@@/ { in443=1; next }
/@@HTTPS-END@@/ { in443=0; next }
/@@HTTPS-REDIRECT-START@@/ { inredir=1; next }
/@@HTTPS-REDIRECT-END@@/ { inredir=0; next }
/@@HTTP-SERVE-START@@/ { inserv=1; next }
/@@HTTP-SERVE-END@@/ { inserv=0; next }
in443 && /^# / { sub(/^# ?/, ""); print; next }
in443 && /^#/ { sub(/^#/, ""); print; next }
inredir && /^[[:space:]]*#.*return 301 https:/ { sub(/^[[:space:]]*#[[:space:]]*/, ""); print; next }
inserv && /^[[:space:]]*include / && !/^[[:space:]]*#/ { $0 = "#" $0; print; next }
{ print }
AWKPROG
export ENABLE_HTTPS_AWK
# ----------------------------------------------------------------
# 通用:上传并启用一个站点(主配置 + 共享片段)
# $1 site 域名,如 sausagetoast.cloud / blog.sausagetoast.cloud
# $2 main_conf deploy/ 下的主配置文件名
# $3 serve_conf deploy/ 下的片段文件名
# $4 snippet 片段在远端 /etc/nginx/snippets/ 下的名字
# ----------------------------------------------------------------
do_setup_site() {
local site="$1" main_conf="$2" serve_conf="$3" snippet="$4"
echo "==> 上传 $main_conf + $serve_conf${SSH_TARGET} ..."
scp $SSH_OPTS "$ROOT_DIR/deploy/$main_conf" "$SSH_TARGET:/tmp/yukun-main.conf"
scp $SSH_OPTS "$ROOT_DIR/deploy/$serve_conf" "$SSH_TARGET:/tmp/yukun-serve.conf"
echo "==> 远端启用站点 $site ..."
ssh $SSH_OPTS "$SSH_TARGET" "SITE='$site' SNIPPET='$snippet' ENABLE_HTTPS_AWK=\"$(printf '%s' "$ENABLE_HTTPS_AWK" | base64)\" bash -s" <<'REMOTE'
set -euo pipefail
SUDO=""
[ "$(id -u)" -ne 0 ] && SUDO="sudo"
SITE="$SITE"; SNIPPET="$SNIPPET"
ENABLE_HTTPS_AWK_b64="$ENABLE_HTTPS_AWK"; unset ENABLE_HTTPS_AWK
_enable_https() {
local conf="$1"
printf '%s' "$ENABLE_HTTPS_AWK_b64" | base64 -d > /tmp/enable-https.awk
$SUDO bash -c 'f="$1"; awk -f /tmp/enable-https.awk "$f" > "$f.tmp" && mv "$f.tmp" "$f"' _ "$conf"
rm -f /tmp/enable-https.awk
}
# 1) 共享片段 → /etc/nginx/snippets/<snippet>
$SUDO mkdir -p /etc/nginx/snippets
$SUDO cp /tmp/yukun-serve.conf "/etc/nginx/snippets/$SNIPPET"
echo " 片段: /etc/nginx/snippets/$SNIPPET"
# 2) 站点配置:优先 sites-available(Debian),其次 conf.d(CentOS)
CONF=""
if [ -d /etc/nginx/sites-enabled ] || $SUDO [ -d /etc/nginx/sites-enabled ]; then
AVAIL=/etc/nginx/sites-available; EN=/etc/nginx/sites-enabled
$SUDO mkdir -p "$AVAIL" "$EN"
$SUDO cp /tmp/yukun-main.conf "$AVAIL/$SITE"
$SUDO ln -sfn "$AVAIL/$SITE" "$EN/$SITE" # 幂等
if ! $SUDO grep -q "sites-enabled" /etc/nginx/nginx.conf 2>/dev/null; then
echo " nginx.conf 缺 include sites-enabled/*,自动追加"
$SUDO sed -i '/http {/a\ include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf
fi
CONF="$AVAIL/$SITE"
echo " 站点: $CONF (+软链接 $EN/$SITE)"
else
$SUDO mkdir -p /etc/nginx/conf.d
$SUDO cp /tmp/yukun-main.conf "/etc/nginx/conf.d/$SITE.conf"
CONF="/etc/nginx/conf.d/$SITE.conf"
echo " 站点: $CONF"
fi
# 3) 清理另一位置的重复配置(防止 conflicting server name 警告)
if [ "$CONF" = "/etc/nginx/sites-available/$SITE" ]; then
if $SUDO [ -f "/etc/nginx/conf.d/$SITE.conf" ]; then
$SUDO rm -f "/etc/nginx/conf.d/$SITE.conf"
echo " 已移除重复配置 /etc/nginx/conf.d/$SITE.conf"
fi
else
if $SUDO [ -f "/etc/nginx/sites-available/$SITE" ]; then
$SUDO rm -f "/etc/nginx/sites-available/$SITE" "/etc/nginx/sites-enabled/$SITE"
echo " 已移除重复配置 sites-available/$SITE"
fi
fi
# 4) 若证书已存在(重跑场景),自动启用 HTTPS
if $SUDO [ -f "/etc/letsencrypt/live/$SITE/fullchain.pem" ]; then
echo "==> 检测到已有证书,自动启用 HTTPS ..."
_enable_https "$CONF"
fi
echo "==> 测试 nginx 配置 ..."
$SUDO nginx -t
echo "==> reload nginx ..."
$SUDO systemctl reload nginx || $SUDO systemctl restart nginx
rm -f /tmp/yukun-main.conf /tmp/yukun-serve.conf
echo "✓ 站点 $SITE 已启用HTTP 直通)"
echo " 下一步(可选):申请 HTTPS 证书"
REMOTE
}
# ----------------------------------------------------------------
# 通用:为一个站点签 HTTPS 证书并自动启用 443 + 80 跳转
# $1 site 域名
# ----------------------------------------------------------------
do_certbot_site() {
local site="$1"
echo "==> 远端为 $site 申请证书webroot 方式)..."
echo " 前置:站点已 setup$site 已解析到本机、80 端口可达"
ssh $SSH_OPTS "$SSH_TARGET" "SITE='$site' ENABLE_HTTPS_AWK=\"$(printf '%s' "$ENABLE_HTTPS_AWK" | base64)\" bash -s" <<'REMOTE'
set -euo pipefail
SUDO=""
[ "$(id -u)" -ne 0 ] && SUDO="sudo"
SITE="$SITE"
ENABLE_HTTPS_AWK_b64="$ENABLE_HTTPS_AWK"; unset ENABLE_HTTPS_AWK
_enable_https() {
local conf="$1"
printf '%s' "$ENABLE_HTTPS_AWK_b64" | base64 -d > /tmp/enable-https.awk
$SUDO bash -c 'f="$1"; awk -f /tmp/enable-https.awk "$f" > "$f.tmp" && mv "$f.tmp" "$f"' _ "$conf"
rm -f /tmp/enable-https.awk
}
# 没装 certbot 就装
if ! command -v certbot >/dev/null 2>&1; then
echo "==> 安装 certbot ..."
if command -v apt >/dev/null 2>&1; then $SUDO apt update && $SUDO apt install -y certbot python3-certbot-nginx
elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y certbot python3-certbot-nginx
elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y certbot python3-certbot-nginx
else echo "✗ 未识别的包管理器,请手动装 certbot"; exit 1; fi
fi
$SUDO mkdir -p /var/www/html
echo "==> 签发证书 ..."
$SUDO certbot certonly --webroot -w /var/www/html \
-d "$SITE" \
--non-interactive --agree-tos --register-unsafe --email "root@$SITE"
# 找到站点配置文件
CONF=""
for p in "/etc/nginx/sites-available/$SITE" "/etc/nginx/conf.d/$SITE.conf"; do
if $SUDO [ -f "$p" ]; then CONF="$p"; break; fi
done
if [ -z "$CONF" ]; then echo "✗ 找不到 $SITE 的配置,请先 setup"; exit 1; fi
echo "==> 启用 HTTPS取消 443 段注释 + 80 段切跳转)..."
_enable_https "$CONF"
echo "==> 测试并重载 nginx ..."
$SUDO nginx -t && $SUDO systemctl reload nginx
echo "✓ $SITE 的 HTTPS 已启用,访问 https://$SITE"
echo " 证书: /etc/letsencrypt/live/$SITE/ (certbot 已自动配置续期)"
REMOTE
}
# ----------------------------------------------------------------
# 博客专用命令
# ----------------------------------------------------------------
cmd_setup_nginx() { do_setup_site "sausagetoast.cloud" "nginx.conf" "nginx-serve.conf" "yukun.conf"; }
cmd_certbot() { do_certbot_site "sausagetoast.cloud"; }
# ----------------------------------------------------------------
# 诊断 + 清理:找出并禁用残留的 baidu 反代配置
# ----------------------------------------------------------------
cmd_doctor() {
echo "==> 远端诊断:搜索 baidu 反代残留 ..."
ssh $SSH_OPTS "$SSH_TARGET" "bash -s" <<'REMOTE'
set +e
SUDO=""
[ "$(id -u)" -ne 0 ] && SUDO="sudo"
echo "########## 1. 含 baidu 的配置/脚本nginx/宝塔/caddy/apache/定时任务)##########"
hits=$($SUDO grep -rln "baidu" /etc/nginx/ /www/server/ /etc/caddy/ /etc/apache2/ /etc/httpd/ 2>/dev/null)
if [ -n "$hits" ]; then
for f in $hits; do
echo ">> $f"
$SUDO grep -nE "baidu|server_name|proxy_pass|return 30|listen " "$f" 2>/dev/null
echo ""
done
else
echo "(配置文件里没有 baidu)"
fi
echo "-- crontab / cron.d 里的 baidu --"
($SUDO crontab -l 2>/dev/null | grep -n "baidu"; $SUDO grep -rn "baidu" /etc/cron.d/ /var/spool/cron/ 2>/dev/null) || echo "(定时任务里没有 baidu)"
echo "########## 2. 生效配置里 sausagetoast.cloud 的去向 ##########"
$SUDO nginx -T 2>/dev/null | grep -B2 -A10 "sausagetoast" || echo "(nginx -T 无相关配置)"
echo "########## 3. 80/443 监听者 + 其他 web 服务 ##########"
ss -tlnp 2>/dev/null | grep -E ':80|:443' || netstat -tlnp 2>/dev/null | grep -E ':80|:443'
systemctl list-units --type=service --state=running 2>/dev/null | grep -iE 'caddy|apache|httpd|traefik|nginx|bt|baota' || true
echo ""
echo "########## 4. 清理:禁用已启用且含 baidu 的配置 ##########"
TS=$(date +%Y%m%d-%H%M%S)
BK="/tmp/yukun-doctor-backup-$TS"
mkdir -p "$BK"
disabled=0
# 检查 sites-enabled可能是软链接和 conf.d
for d in /etc/nginx/sites-enabled /etc/nginx/conf.d; do
[ -d "$d" ] || continue
for f in "$d"/*; do
[ -e "$f" ] || continue
if $SUDO grep -ql "baidu" "$f" 2>/dev/null; then
echo ">> 发现 baidu 配置: $f"
$SUDO cp -a "$f" "$BK/$(basename "$f").bak"
if [ -L "$f" ]; then
echo " 软链接,删除链接(保留源文件)"
$SUDO rm -f "$f"
else
echo " 普通文件,改名为 .disabled"
$SUDO mv "$f" "$f.disabled"
fi
disabled=$((disabled+1))
fi
done
done
echo "备份目录: $BK"
if [ "$disabled" -gt 0 ]; then
echo "==> 测试 nginx ..."
if $SUDO nginx -t 2>/dev/null; then
$SUDO systemctl reload nginx
echo "✓ 已禁用 $disabled 个 baidu 配置并 reload nginx"
else
echo "✗ nginx -t 失败,恢复备份 ..."
# 恢复(简化:提示手动从 $BK 恢复)
echo " 请从 $BK 手动恢复,或检查 nginx -t 报错"
fi
else
echo "(已启用的配置里没有 baidu若仍跳转 baidu看上面第 2/3 项排查其他服务或 DNS)"
fi
REMOTE
}
# ----------------------------------------------------------------
# 博客发布:构建 + rsync + reload
# ----------------------------------------------------------------
cmd_deploy() {
echo "==> 工作目录: $ROOT_DIR"
echo "==> [1/3] 构建站点 (astro build)..."
cd "$ROOT_DIR"
npm run build
[ -d "$ROOT_DIR/dist" ] || { echo "✗ 构建失败dist 不存在"; exit 1; }
echo "==> [2/3] 同步到 ${SSH_TARGET}:${REMOTE_DIR} ..."
rsync -avz --delete --human-readable \
"$ROOT_DIR/dist/" "${SSH_TARGET}:${REMOTE_DIR}/"
if [ "$NGINX_RELOAD" = "1" ]; then
echo "==> [3/3] reload nginx..."
remote_run "nginx -t && systemctl reload nginx"
fi
echo ""
echo "✓ 部署完成!访问 https://${REMOTE_HOST}"
}
# ----------------------------------------------------------------
case "${1:-deploy}" in
setup-nginx) cmd_setup_nginx ;;
certbot) cmd_certbot ;;
doctor) cmd_doctor ;;
deploy|"") cmd_deploy ;;
*)
echo "用法: $0 [setup-nginx|certbot|doctor|deploy]"
echo " setup-nginx 博客:上传并启用站点配置"
echo " certbot 博客:签 HTTPS 证书并启用 443"
echo " doctor 诊断并清理残留的 baidu 反代配置"
echo " deploy 博客:构建并同步到 VPS默认"
echo " 子域名反代请用: $0 所在目录的 proxy.sh"
exit 1 ;;
esac