#!/usr/bin/env bash # pangolin-nginx-apply.sh —— 受限特权脚本(以 root 安装到 /usr/local/sbin/) # # 作用:把 pangolin REALITY 的 SNI 路由 (www.apple.com -> 127.0.0.1:11443) # 幂等地插入宿主机 nginx 的 stream map,并热重载。 # # 安全设计: # - 唯一被 sudoers 授权 NOPASSWD 的命令,作用域锁死本脚本; # - 幂等:已存在则直接退出; # - 改前备份 + nginx -t 校验 + 失败自动回滚,不影响其他服务(热 reload 不断连)。 set -euo pipefail STREAM_CONF="/etc/nginx/stream.conf" BACKEND="127.0.0.1:11443" SNI="www.apple.com" ROUTE_LINE=" ${SNI} ${BACKEND};" if [[ ! -f "$STREAM_CONF" ]]; then echo "[nginx-apply] $STREAM_CONF 不存在,放弃(本机预期已有 nginx)" >&2 exit 1 fi # 幂等:路由已存在则跳过 if grep -qF "$BACKEND" "$STREAM_CONF"; then echo "[nginx-apply] 路由已存在,跳过" exit 0 fi BACKUP="${STREAM_CONF}.pangolin.bak" cp -a "$STREAM_CONF" "$BACKUP" TMP="$(mktemp)" # 在 map 的 default 行之前插入我们的 SNI 路由 awk -v ins="$ROUTE_LINE" ' $0 ~ /default[[:space:]]+127\.0\.0\.1:10443;/ && !done { print ins; done=1 } { print } ' "$STREAM_CONF" > "$TMP" # 校验:确实插入了我们的后端,且没有破坏文件 if ! grep -qF "$BACKEND" "$TMP"; then echo "[nginx-apply] 插入失败(未找到 default 锚点?),不改动" >&2 rm -f "$TMP" exit 1 fi cat "$TMP" > "$STREAM_CONF" rm -f "$TMP" if nginx -t 2>/dev/null; then nginx -s reload echo "[nginx-apply] 已插入路由并热重载成功" else echo "[nginx-apply] nginx -t 失败,回滚" >&2 cp -a "$BACKUP" "$STREAM_CONF" exit 1 fi