#!/usr/bin/env bash # cutover.sh —— 一次性切换:宿主 nginx → pangolin-edge 容器(需 root 一次)。 # sudo bash /home/ec2-user/pangolin/scripts/cutover.sh # 选空闲时段执行;代理(Marzban REALITY)会有秒级重连,Shadowrocket 自动恢复。 # 失败可秒级回滚:docker-compose -p pangolin stop edge && systemctl start nginx set -euo pipefail if [[ "$(id -u)" -ne 0 ]]; then echo "请以 root 运行:sudo bash $0" >&2 exit 1 fi cd "$(dirname "$0")/.." # -> deploy/ EDGE_IMAGE="nginx:1.27-alpine" echo "==> [1/4] 切换前校验 edge 配置(含证书路径)" docker run --rm \ -v "$PWD/edge/nginx.conf:/etc/nginx/nginx.conf:ro" \ -v "$PWD/edge/stream.conf:/etc/nginx/stream.conf:ro" \ -v "$PWD/edge/conf.d:/etc/nginx/conf.d:ro" \ -v /etc/letsencrypt:/etc/letsencrypt:ro \ -v /opt/jiu:/opt/jiu:ro \ -v /var/www/pay:/var/www/pay:ro \ "$EDGE_IMAGE" nginx -t rollback() { echo "==> !! 自动回滚:停 edge,恢复宿主 nginx" >&2 docker-compose -p pangolin stop edge >/dev/null 2>&1 || true systemctl enable nginx >/dev/null 2>&1 || true systemctl start nginx || echo " !! 宿主 nginx 启动失败,请手动 systemctl start nginx" >&2 echo " 已回滚到宿主 nginx。" >&2 exit 1 } echo "==> [2/4] 停用宿主 nginx 并起 edge 容器(交接窗口,秒级)" systemctl stop nginx systemctl disable nginx 2>/dev/null || true docker build -t pangolin-edge:local ./edge || { echo " edge 镜像构建失败" >&2; rollback; } if ! docker-compose -p pangolin up -d edge singbox; then echo " edge 启动失败" >&2; rollback fi echo "==> [3/4] 等待并健康检查" sleep 2 # edge 容器必须在跑 if [[ "$(docker inspect -f '{{.State.Running}}' pangolin-edge 2>/dev/null)" != "true" ]]; then echo " edge 容器未运行" >&2; docker logs pangolin-edge 2>&1 | tail -10; rollback fi fail=0 # REALITY 经 443 → 10443(Marzban),SNI=www.cloudflare.com 应握手成功 if echo | timeout 10 openssl s_client -connect 127.0.0.1:443 -servername www.cloudflare.com >/dev/null 2>&1; then echo " [REALITY] 443 握手 OK"; else echo " [REALITY] 握手失败"; fail=1; fi # 业务 vhost(经 stream→本机 8443/8444/8445) for d in blog jiu vpn; do code="$(curl -ks -o /dev/null -w '%{http_code}' --resolve ${d}.51yanmei.com:443:127.0.0.1 https://${d}.51yanmei.com/ 2>/dev/null || echo 000)" echo " [${d}] https -> ${code}" [[ "$code" =~ ^[2-4][0-9][0-9]$ ]] || fail=1 done echo "==> [4/4] 结果" if [[ "$fail" == "0" ]]; then echo " 切换成功 ✅(宿主 nginx 已停,配置保留可回滚)" else echo " 部分检查未通过" >&2; rollback fi