#!/usr/bin/env bash # 一键发布到云服务器:本地构建 → 上传 → 原地同步 # # 用法: # SERVER=root@132.232.203.88 ./deploy/deploy.sh # SERVER=root@1.2.3.4 WEB_ROOT=/var/www/kanban SSH_PORT=2222 ./deploy/deploy.sh # # 环境变量: # SERVER 远端 SSH 目标(必填),如 root@1.2.3.4 # WEB_ROOT 远端站点目录,默认 /opt/kanban/dist(容器挂载的就是这里) # SSH_PORT SSH 端口,默认 22 # SKIP_BUILD 设为 1 时跳过本地构建,直接发布现有 dist/ # # 注意:站点目录是容器的 bind mount,必须「原地同步」。 # 整目录 mv 之后容器仍指向旧 inode,看不到新文件 —— 所以这里只用 rsync / tar 解包原地覆盖。 set -euo pipefail # 无论从哪里调用,都切到仓库根目录 cd "$(dirname "$0")/.." SERVER="${SERVER:-}" WEB_ROOT="${WEB_ROOT:-/opt/kanban/dist}" SSH_PORT="${SSH_PORT:-22}" SKIP_BUILD="${SKIP_BUILD:-0}" if [ -z "$SERVER" ]; then echo "缺少 SERVER。示例:SERVER=root@1.2.3.4 $0" >&2 exit 1 fi if [ "$SKIP_BUILD" != "1" ]; then echo "==> 本地构建" npm run build fi if [ ! -f dist/index.html ]; then echo "dist/index.html 不存在,构建可能失败了" >&2 exit 1 fi echo "==> 远端准备目录 $WEB_ROOT" ssh -p "$SSH_PORT" "$SERVER" "mkdir -p '$WEB_ROOT'" if command -v rsync >/dev/null 2>&1; then echo "==> rsync 原地增量同步" rsync -az --delete -e "ssh -p $SSH_PORT" dist/ "$SERVER:$WEB_ROOT/" else # Windows / Git Bash 一般没有 rsync:上传到远端临时目录,再在远端原地同步 echo "==> tar 上传后远端原地同步(本地未检测到 rsync)" STAMP=$(date +%Y%m%d%H%M%S) STAGE="/tmp/kanban-release-$STAMP" ssh -p "$SSH_PORT" "$SERVER" "rm -rf '$STAGE' && mkdir -p '$STAGE'" tar -czf - -C dist . | ssh -p "$SSH_PORT" "$SERVER" "tar -xzf - -C '$STAGE'" ssh -p "$SSH_PORT" "$SERVER" " set -e if command -v rsync >/dev/null 2>&1; then rsync -a --delete '$STAGE/' '$WEB_ROOT/' else # 没有 rsync 时退化为「清空 + 解包」,会有毫秒级空窗 find '$WEB_ROOT' -mindepth 1 -delete cp -a '$STAGE/.' '$WEB_ROOT/' fi rm -rf '$STAGE' " fi echo "==> 发布完成:$SERVER:$WEB_ROOT" echo " 验证:curl -I http://<域名或 IP>/today # 期望 200,而不是 404"