#!/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" < 上传 $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/ $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