亮暗模式选择
腾讯云
TencentCloud
宝塔面板
以LuckyPlane为例
本地代码部署到服务器流程
以LuckyPlane为例,基于 rsync + SSH编写的部署脚本deploy.sh ,
1. 本地测试通过后,先预览变更(dry-run)
bash
./deploy.sh默认是预览模式,只列出会上传的文件, 不会改动服务器 。确认文件列表无误后再执行真正部署。
2. 正式部署(推荐完整流程)
bash
./deploy.sh --apply --backup --finish这会依次执行:
--backup:在服务器打包备份当前代码到/root/luckyplane-bak-*.tar.gz(排除 vendor/node_modules)--apply:用 rsync 上传本地代码到Tencent:/www/wwwroot/LuckyPlane--finish:服务器收尾——修正文件归属为www:www、composer install --no-dev、重建 config/route/view 缓存、storage:link
3. 各参数说明
参数 作用 无参数 预览模式,只显示将要同步的文件 --apply 真正执行上传 --backup 上传前在服务器打包备份 --finish 上传后修正归属、跑 composer、重建缓存 --delete 同步删除服务器上本地没有的文件( 慎用 ,会二次确认)
脚本自动排除的内容
.env ( 硬性排除 ,避免覆盖生产数据库配置)、.git/ 、node_modules/ 、vendor/ 、storage/logs/ 、storage/framework/ 、bootstrap/cache/ 等。
注意事项
.env不会上传 ——服务器的生产配置(数据库、APP_KEY 等)保持原样,这是刻意设计的vendor/和node_modules/不上传,由服务器的--finish阶段执行composer install- 如果前端有构建产物(如
public/build),脚本也排除了,需要在服务器上单独构建或手动上传 - SSH 免密登录已配置好(
~/.ssh/config中Tencent→124.220.44.180:9922)
deploy.sh脚本内容
bash
#!/usr/bin/env bash
#
# LuckyPlane 部署脚本(本地 → 腾讯云服务器 /www/wwwroot/LuckyPlane)
#
# 用法:
# ./deploy.sh 预览:只列出会上传的文件,不动服务器
# ./deploy.sh --apply 真正上传
# ./deploy.sh --apply --backup 上传前先在服务器打包备份到 /root/
# ./deploy.sh --apply --finish 上传后修正归属、跑 composer、重建缓存(均以 www 身份)
# ./deploy.sh --apply --delete 同步删除服务器上多余的文件(慎用,会二次确认)
# ./deploy.sh -h 查看用法
#
# 选项可组合,例如:./deploy.sh --apply --backup --finish
#
# 重要:.env 永不在同步范围内。本地 .env 与服务器 .env 内容不同,
# 上传会覆盖生产配置(数据库、密钥等),脚本已硬性排除。
#
set -euo pipefail
LOCAL_DIR="/Users/ben/Sites/LuckyPlane/"
SSH_HOST="Tencent"
REMOTE_DIR="/www/wwwroot/LuckyPlane"
APPLY=0
BACKUP=0
FINISH=0
DELETE=0
usage() {
awk 'NR>2 && /^#/ {sub(/^#[[:space:]]?/, ""); print; next} NR>2 && !/^#/ {exit}' "$0"
}
for arg in "$@"; do
case "$arg" in
--apply) APPLY=1 ;;
--backup) BACKUP=1 ;;
--finish) FINISH=1 ;;
--delete) DELETE=1 ;;
-h|--help) usage; exit 0 ;;
*) echo "未知参数: $arg"; usage; exit 1 ;;
esac
done
GREEN='\033[0;32m'; YELLOW='\033[0;33m'; RED='\033[0;31m'; BOLD='\033[1m'; NC='\033[0m'
info() { printf "${GREEN}[信息]${NC} %s\n" "$1"; }
warn() { printf "${YELLOW}[注意]${NC} %s\n" "$1"; }
err() { printf "${RED}[错误]${NC} %s\n" "$1"; }
# 同步时要排除的内容(顺序无关,均为 rsync --exclude)
EXCLUDES=(
--exclude='.env'
--exclude='.git/'
--exclude='.workbuddy/'
--exclude='.idea/'
--exclude='.vscode/'
--exclude='node_modules/'
--exclude='vendor/'
--exclude='storage/framework/'
--exclude='storage/logs/'
--exclude='bootstrap/cache/'
--exclude='public/storage'
--exclude='public/build'
--exclude='public/hot'
--exclude='_ide_helper.php'
--exclude='.phpunit.result.cache'
--exclude='.DS_Store'
--exclude='*.log'
)
printf "${BOLD}LuckyPlane 部署${NC}\n"
echo " 本地: ${LOCAL_DIR}"
echo " 服务器: ${SSH_HOST}:${REMOTE_DIR}"
echo
# 1) 检查 SSH 连通性(密钥登录,不交互)
if ! ssh -o BatchMode=yes -o ConnectTimeout=10 "$SSH_HOST" "true" 2>/dev/null; then
err "无法免密连接 ${SSH_HOST}。请检查 ~/.ssh/config 与密钥是否有效。"
exit 1
fi
info "SSH 连接正常"
# 2) --delete 需要二次确认(会删服务器文件,风险最高)
if [[ "$DELETE" -eq 1 && "$APPLY" -eq 1 ]]; then
warn "--delete 会删除服务器上本地没有的文件(含线上用户上传内容)"
printf "确认继续?请输入 yes: "
read -r ans
if [[ "$ans" != "yes" ]]; then
info "已取消"
exit 0
fi
fi
# 3) 组装 rsync 参数
RSYNC_ARGS=(-avz -e ssh "${EXCLUDES[@]}")
# 不把本地的 uid/gid(Mac 上是 501:games)带到服务器,归属统一由 --finish 阶段的 chown 收编
RSYNC_ARGS+=(--no-owner --no-group)
if [[ "$APPLY" -eq 0 ]]; then
RSYNC_ARGS+=(--dry-run)
fi
if [[ "$DELETE" -eq 1 ]]; then
RSYNC_ARGS+=(--delete)
fi
# 4) 服务器侧备份(可选)
if [[ "$BACKUP" -eq 1 ]]; then
info "在服务器打包备份(排除 vendor / node_modules)..."
ssh "$SSH_HOST" "bash -s" <<REMOTE_BACKUP
set -e
tar czf /root/luckyplane-bak-\$(date +%m%d-%H%M).tar.gz \
--exclude='vendor' --exclude='node_modules' --exclude='storage/framework/*' \
-C /www/wwwroot LuckyPlane
ls -lh /root/luckyplane-bak-*.tar.gz | tail -3
REMOTE_BACKUP
info "备份完成"
fi
# 5) 同步
if [[ "$APPLY" -eq 1 ]]; then
info "开始上传..."
else
warn "预览模式(未加 --apply),服务器不会被改动"
fi
echo
rsync "${RSYNC_ARGS[@]}" "$LOCAL_DIR" "${SSH_HOST}:${REMOTE_DIR}/" || {
err "rsync 执行失败,请查看上方输出"
exit 1
}
echo
# 6) 服务器收尾(可选)
if [[ "$FINISH" -eq 1 ]]; then
if [[ "$APPLY" -eq 0 ]]; then
warn "预览模式下不执行收尾命令"
else
info "在服务器执行收尾:归属修正 / 依赖安装 / 缓存重建(composer 与 artisan 均以 www 身份运行)..."
ssh "$SSH_HOST" "bash -s" <<'REMOTE_FINISH'
set -e
PROJECT=/www/wwwroot/LuckyPlane
cd "$PROJECT"
# 1) 统一归属,消除历史遗留的 501:games(Mac 本地 uid)
chown -R www:www "$PROJECT"
if [ -f .env ]; then chmod 600 .env; fi
# 2) composer / artisan 一律以 www 身份执行
# root 下 composer 会禁用插件并告警;artisan 也需用 www,
# 否则生成的缓存文件归 root,www 下次无法重写
# 注意:www 的 shell 是 /sbin/nologin,sudo -u / su 会被 PAM 拒绝,只能用 runuser
runuser -u www -- env COMPOSER_HOME=/home/www/.composer bash -c \
"cd $PROJECT && composer install --no-dev --optimize-autoloader --no-interaction"
artisan() { runuser -u www -- php artisan "$@"; }
artisan config:clear
artisan config:cache
artisan route:cache
artisan view:cache
artisan storage:link || echo "(storage:link 已存在,跳过)"
chmod -R 775 storage bootstrap/cache
echo "收尾完成"
REMOTE_FINISH
info "收尾完成"
fi
fi
if [[ "$APPLY" -eq 1 ]]; then
info "部署结束"
echo " 提示:.env 未被上传,服务器上的生产配置保持原样"
else
info "预览结束。确认无误后加 --apply 真正上传"
fi运行前置条件
确保脚本有执行权限:
bash
chmod +x /Users/ben/Sites/LuckyPlane/deploy.sh运行方式
方式一:在项目目录下运行(推荐)
bash
cd /Users/ben/Sites/LuckyPlane
./deploy.sh方式二:用绝对路径运行
bash
/Users/ben/Sites/LuckyPlane/deploy.sh方式三:用 bash 显式调用(最稳妥,无需执行权限)
bash
bash /Users/ben/Sites/LuckyPlane/deploy.sh配置更改后需要刷新缓存配置
bash
php artisan config:clear
php artisan config:cache验证 (改完后在你本机执行)
bash
curl -i -X OPTIONS "https://luckyplane.com/api/user/current" \
-H "Origin: http://yadonghx.vicp.net" \
-H "Access-Control-Request-Method: GET"