Phase 0: 容器化数据面 + CI/CD 自动部署
deploy-pangolin / deploy (push) Has been cancelled

- deploy/: Xray VLESS+REALITY (11443, 经宿主 nginx SNI 分流) + sing-box Hysteria2 (UDP 443) docker-compose
- 幂等 deploy.sh / gen-secrets.sh / print-clients.sh;受限 nginx-apply 特权脚本 + 一次性 root-setup
- .gitea/workflows/deploy.yml: NAS runner 经 SSH 远程部署到 EC2
- docs/ plan/: 设计方案与实施计划

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-05-30 11:48:21 +08:00
parent 833b8365da
commit cf96989e01
23 changed files with 1048 additions and 2 deletions
+56
View File
@@ -0,0 +1,56 @@
#!/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
+1
View File
@@ -0,0 +1 @@
www.apple.com 127.0.0.1:11443;
+23
View File
@@ -0,0 +1,23 @@
# 仅当宿主机【没有】nginx 时使用的完整 stream 配置(deploy.sh 自动判断)。
# 本机已有宿主 nginx,故此文件不会被使用 —— 留作「无 nginx 则先部署」的兜底。
#
# 用法(deploy.sh 在无 nginx 分支里):
# 1. 安装 nginx + stream 模块
# 2. 将本文件渲染到 /etc/nginx/stream.conf 并 include
# 3. nginx -t && systemctl enable --now nginx
stream {
map $ssl_preread_server_name $pangolin_backend {
www.apple.com 127.0.0.1:11443; # pangolin REALITY
default 127.0.0.1:11443;
}
server {
listen 443;
listen [::]:443;
proxy_pass $pangolin_backend;
ssl_preread on;
proxy_connect_timeout 10s;
proxy_timeout 3600s;
}
}