- 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:
@@ -0,0 +1,49 @@
|
||||
name: deploy-pangolin
|
||||
|
||||
# 触发:改 deploy/** 或本 workflow 时自动;也可在 Gitea Actions 页手动触发。
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'deploy/**'
|
||||
- '.gitea/workflows/deploy.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
# ⚠️ 改成你 NAS 上 act_runner 的实际 label
|
||||
# (Gitea → 仓库/组织 Settings → Actions → Runners 里可见)。
|
||||
# 常见为 self-hosted / nas / ubuntu-latest。
|
||||
runs-on: nas
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Ensure ssh/rsync 存在
|
||||
run: |
|
||||
if ! command -v rsync >/dev/null || ! command -v ssh >/dev/null; then
|
||||
(command -v apt-get >/dev/null && apt-get update -y && apt-get install -y openssh-client rsync) \
|
||||
|| (command -v apk >/dev/null && apk add --no-cache openssh-client rsync)
|
||||
fi
|
||||
|
||||
- name: 准备 SSH 私钥(指向 EC2)
|
||||
run: |
|
||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
printf '%s\n' "${{ secrets.EC2_SSH_KEY }}" > ~/.ssh/ec2_key
|
||||
chmod 600 ~/.ssh/ec2_key
|
||||
ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||
|
||||
- name: 同步 deploy/ 到 EC2(保留 secrets,不删目标)
|
||||
run: |
|
||||
rsync -az \
|
||||
--exclude 'secrets' \
|
||||
--exclude 'xray/config.json' \
|
||||
--exclude 'singbox/config.json' \
|
||||
-e "ssh -i ~/.ssh/ec2_key -o StrictHostKeyChecking=accept-new" \
|
||||
deploy/ "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}:/opt/pangolin/"
|
||||
|
||||
- name: 远程部署(幂等)
|
||||
run: |
|
||||
ssh -i ~/.ssh/ec2_key -o StrictHostKeyChecking=accept-new \
|
||||
"${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}" \
|
||||
'cd /opt/pangolin && chmod +x scripts/*.sh nginx/*.sh setup/*.sh && ./scripts/deploy.sh'
|
||||
@@ -11,3 +11,12 @@
|
||||
*.app
|
||||
.snapshots/*
|
||||
|
||||
# 密钥与渲染产物 —— 绝不入库
|
||||
deploy/secrets/
|
||||
deploy/xray/config.json
|
||||
deploy/singbox/config.json
|
||||
|
||||
# 杂项
|
||||
.DS_Store
|
||||
*.log
|
||||
*.bak
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
# pangolin
|
||||
# Pangolin
|
||||
|
||||
vpn
|
||||
面向中国大陆用户的终端 VPN(科学上网)项目。
|
||||
|
||||
- 设计方案:[`docs/技术方案.md`](docs/技术方案.md)
|
||||
- 实施计划:[`plan/`](plan/)
|
||||
- 部署(Phase 0,容器化 + CI/CD):[`deploy/`](deploy/)
|
||||
|
||||
## Phase 0 现状
|
||||
|
||||
数据面两条线,容器化、经 Gitea Actions 自动部署到节点,与现网服务隔离:
|
||||
|
||||
- **Xray VLESS + REALITY**(主线,经宿主 nginx SNI 分流)
|
||||
- **sing-box Hysteria2**(晚高峰加速线,UDP 443)
|
||||
|
||||
部署细节见 [`deploy/README.md`](deploy/README.md)。
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# 可选环境变量(deploy.sh / print-clients.sh 读取)。
|
||||
# 真正的密钥由 gen-secrets.sh 自动生成到 deploy/secrets/pangolin.env,无需手填。
|
||||
|
||||
# 覆盖客户端导入串里的服务器地址(默认自动取 EC2 公网 IP)
|
||||
# PANGOLIN_PUBLIC_IP=18.136.60.128
|
||||
|
||||
# root-setup.sh 授权的部署用户(默认 ec2-user)
|
||||
# PANGOLIN_DEPLOY_USER=ec2-user
|
||||
@@ -0,0 +1,50 @@
|
||||
# Pangolin 部署(Phase 0)
|
||||
|
||||
容器化数据面:**Xray VLESS+REALITY** + **sing-box Hysteria2**,经 CI/CD 自动部署到节点。
|
||||
与现网 marzban/blog/jiu 完全隔离。设计详见 [`../docs/技术方案.md`](../docs/技术方案.md) 与 [`../plan/`](../plan/)。
|
||||
|
||||
## 端口与隔离
|
||||
|
||||
| 服务 | 监听 | 经由 | 说明 |
|
||||
|------|------|------|------|
|
||||
| Xray REALITY | 容器内 `0.0.0.0:11443` → 宿主 `127.0.0.1:11443` | 宿主 nginx `ssl_preread`(SNI=`www.apple.com`)| 复用 443/TCP,不占公网端口 |
|
||||
| sing-box Hy2 | 公网 `0.0.0.0:443/udp` | 直接暴露 | 与 TCP 443 不同协议栈,互不冲突 |
|
||||
|
||||
现网 Marzban xray 在 `10443`、各站在 `8443-8445`,均不受影响。
|
||||
|
||||
## 自动部署链路
|
||||
|
||||
```
|
||||
本地改 deploy/** → push gitea(NAS) → NAS act_runner → ssh ec2 → docker-compose up + nginx 增量 reload
|
||||
```
|
||||
|
||||
## 一次性前置(首次,人工)
|
||||
|
||||
1. **安全组开 UDP 443**(本地 aws):给 `sg-040cf4cd11bdf4d5b` 加 `udp/443 0.0.0.0/0`。
|
||||
2. **root 前置**(EC2 上一次,需 root):
|
||||
```bash
|
||||
sudo bash /opt/pangolin/setup/root-setup.sh
|
||||
```
|
||||
安装受限特权脚本 `pangolin-nginx-apply.sh` + sudoers,使 CI 能非交互更新 nginx 路由(且拿不到通用 root)。
|
||||
3. **Gitea Actions Secrets**(仓库 Settings → Actions → Secrets):
|
||||
- `EC2_SSH_KEY` = ec2-user 私钥(可登录 18.136.60.128)
|
||||
- `EC2_HOST` = `18.136.60.128`
|
||||
- `EC2_USER` = `ec2-user`
|
||||
4. **确认 runner label**,据此改 `.gitea/workflows/deploy.yml` 的 `runs-on`。
|
||||
|
||||
## 手动部署(不走 CI)
|
||||
|
||||
```bash
|
||||
rsync -az --exclude secrets deploy/ ec2-user@18.136.60.128:/opt/pangolin/
|
||||
ssh ec2 'cd /opt/pangolin && ./scripts/deploy.sh'
|
||||
```
|
||||
|
||||
## 取客户端导入信息(含密钥,不进日志)
|
||||
|
||||
```bash
|
||||
ssh ec2 'cat /opt/pangolin/secrets/clients.txt'
|
||||
```
|
||||
|
||||
## 幂等性
|
||||
|
||||
`deploy.sh` 可重复执行:密钥已存在则复用、nginx 路由已存在则跳过、compose 无变更则不动。
|
||||
@@ -0,0 +1,28 @@
|
||||
# Pangolin Phase-0 数据面:Xray(VLESS+REALITY) + sing-box(Hysteria2)
|
||||
# 独立 project 名 pangolin,与现网 marzban/blog/jiu 完全隔离。
|
||||
# 镜像固定版本,避免 latest 漂移(EC2 实测:Xray 26.3.27 / sing-box 1.13.12)。
|
||||
name: pangolin
|
||||
|
||||
services:
|
||||
xray:
|
||||
image: ghcr.io/xtls/xray-core:26.3.27
|
||||
container_name: pangolin-xray
|
||||
restart: unless-stopped
|
||||
# 仅监听本地 11443,由宿主 nginx 的 ssl_preread 按 SNI(www.apple.com)转入
|
||||
ports:
|
||||
- "127.0.0.1:11443:11443"
|
||||
volumes:
|
||||
- ./xray/config.json:/etc/xray/config.json:ro
|
||||
command: ["run", "-c", "/etc/xray/config.json"]
|
||||
|
||||
singbox:
|
||||
image: ghcr.io/sagernet/sing-box:v1.13.12
|
||||
container_name: pangolin-singbox
|
||||
restart: unless-stopped
|
||||
# Hysteria2 直接对外暴露 UDP 443(与 TCP 443 不同协议栈,互不冲突)
|
||||
ports:
|
||||
- "443:443/udp"
|
||||
volumes:
|
||||
- ./singbox/config.json:/etc/sing-box/config.json:ro
|
||||
- ./secrets/hy2:/etc/sing-box/cert:ro
|
||||
command: ["run", "-c", "/etc/sing-box/config.json"]
|
||||
Executable
+56
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
www.apple.com 127.0.0.1:11443;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy.sh —— 在 EC2 上幂等编排 pangolin 数据面。
|
||||
# 由 CI(NAS runner via ssh)调用,也可手动 `ssh ec2 'cd /opt/pangolin && ./scripts/deploy.sh'`。
|
||||
#
|
||||
# 步骤:生成密钥 -> 渲染配置 -> docker-compose up -> (幂等)加 nginx 路由 -> 健康检查 -> 输出客户端信息
|
||||
# 全程不触碰 marzban/blog/jiu;唯一特权动作是 sudo 调用受限的 nginx-apply 脚本。
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.." # -> deploy/
|
||||
|
||||
COMPOSE="docker-compose -p pangolin"
|
||||
NGINX_APPLY="/usr/local/sbin/pangolin-nginx-apply.sh"
|
||||
|
||||
echo "==> [1/5] 生成/复用密钥与证书"
|
||||
./scripts/gen-secrets.sh
|
||||
|
||||
echo "==> [2/5] 渲染配置(模板 -> config.json)"
|
||||
# shellcheck disable=SC1091
|
||||
source ./secrets/pangolin.env
|
||||
render() { # render <tmpl> <out>
|
||||
sed -e "s|__UUID__|${UUID}|g" \
|
||||
-e "s|__REALITY_PRIVATE_KEY__|${REALITY_PRIVATE_KEY}|g" \
|
||||
-e "s|__REALITY_SHORT_ID__|${REALITY_SHORT_ID}|g" \
|
||||
-e "s|__HY2_PASSWORD__|${HY2_PASSWORD}|g" \
|
||||
"$1" > "$2"
|
||||
}
|
||||
render ./xray/config.tmpl.json ./xray/config.json
|
||||
render ./singbox/config.tmpl.json ./singbox/config.json
|
||||
|
||||
echo "==> [3/5] 拉起容器(docker-compose up -d)"
|
||||
$COMPOSE pull --quiet || true
|
||||
$COMPOSE up -d
|
||||
$COMPOSE ps
|
||||
|
||||
echo "==> [4/5] nginx SNI 路由(幂等)"
|
||||
if grep -qF "127.0.0.1:11443" /etc/nginx/stream.conf 2>/dev/null; then
|
||||
echo " 路由已存在,跳过"
|
||||
elif [[ -x "$NGINX_APPLY" ]]; then
|
||||
sudo "$NGINX_APPLY"
|
||||
else
|
||||
echo " !! 未找到 $NGINX_APPLY(需先执行一次性 root 前置 setup/root-setup.sh)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> [5/5] 健康检查"
|
||||
ok=1
|
||||
# REALITY:经宿主 nginx 用 www.apple.com 做 TLS 握手应成功
|
||||
if echo | timeout 10 openssl s_client -connect 127.0.0.1:443 -servername www.apple.com >/dev/null 2>&1; then
|
||||
echo " [REALITY] 443/www.apple.com 握手 OK"
|
||||
else
|
||||
echo " [REALITY] 握手失败"; ok=0
|
||||
fi
|
||||
# Hy2:UDP 443 应有 sing-box 在监听
|
||||
if ss -uln 2>/dev/null | grep -q ":443 "; then
|
||||
echo " [Hy2] UDP 443 监听 OK"
|
||||
else
|
||||
echo " [Hy2] UDP 443 未监听"; ok=0
|
||||
fi
|
||||
|
||||
./scripts/print-clients.sh
|
||||
|
||||
[[ "$ok" == "1" ]] && echo "==> 部署完成 ✅" || { echo "==> 健康检查未通过 ❌"; exit 1; }
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# gen-secrets.sh —— 首次在 EC2 生成并持久化密钥/证书(幂等)。
|
||||
# 产物存于 ./secrets/(700,gitignore,绝不进仓库/CI 日志)。
|
||||
# - pangolin.env : UUID / REALITY 公私钥 / shortId / Hy2 口令
|
||||
# - hy2/hy2.crt, hy2/hy2.key : Hysteria2 自签证书(ECDSA)
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.." # -> deploy/
|
||||
|
||||
SECRETS_DIR="./secrets"
|
||||
ENV_FILE="${SECRETS_DIR}/pangolin.env"
|
||||
HY2_DIR="${SECRETS_DIR}/hy2"
|
||||
XRAY_IMAGE="ghcr.io/xtls/xray-core:26.3.27"
|
||||
MASQ_CN="www.bing.com"
|
||||
|
||||
mkdir -p "$HY2_DIR"
|
||||
chmod 700 "$SECRETS_DIR"
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
echo "[gen-secrets] $ENV_FILE 已存在,跳过密钥生成(幂等)"
|
||||
else
|
||||
echo "[gen-secrets] 生成 REALITY 密钥对 / UUID / shortId / Hy2 口令 ..."
|
||||
# REALITY x25519 密钥对(从 xray 输出解析 Private/Public)
|
||||
KP="$(docker run --rm "$XRAY_IMAGE" x25519)"
|
||||
REALITY_PRIVATE_KEY="$(printf '%s\n' "$KP" | awk -F': ' '/Private/{print $2}')"
|
||||
REALITY_PUBLIC_KEY="$(printf '%s\n' "$KP" | awk -F': ' '/Public/{print $2}')"
|
||||
UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
REALITY_SHORT_ID="$(openssl rand -hex 8)"
|
||||
HY2_PASSWORD="$(openssl rand -base64 18 | tr -d '/+=' | cut -c1-24)"
|
||||
|
||||
umask 177
|
||||
cat > "$ENV_FILE" <<EOF
|
||||
# pangolin Phase-0 secrets —— 切勿提交/外泄
|
||||
UUID=${UUID}
|
||||
REALITY_PRIVATE_KEY=${REALITY_PRIVATE_KEY}
|
||||
REALITY_PUBLIC_KEY=${REALITY_PUBLIC_KEY}
|
||||
REALITY_SHORT_ID=${REALITY_SHORT_ID}
|
||||
HY2_PASSWORD=${HY2_PASSWORD}
|
||||
EOF
|
||||
echo "[gen-secrets] 已写入 $ENV_FILE"
|
||||
fi
|
||||
|
||||
# Hysteria2 自签证书(幂等)
|
||||
if [[ -f "${HY2_DIR}/hy2.crt" && -f "${HY2_DIR}/hy2.key" ]]; then
|
||||
echo "[gen-secrets] Hy2 证书已存在,跳过"
|
||||
else
|
||||
echo "[gen-secrets] 生成 Hy2 自签证书 (CN=${MASQ_CN}) ..."
|
||||
openssl ecparam -genkey -name prime256v1 -out "${HY2_DIR}/hy2.key"
|
||||
openssl req -new -x509 -days 3650 -key "${HY2_DIR}/hy2.key" \
|
||||
-out "${HY2_DIR}/hy2.crt" -subj "/CN=${MASQ_CN}"
|
||||
# sing-box 容器内以 root 运行,证书需可读
|
||||
chmod 644 "${HY2_DIR}/hy2.crt" "${HY2_DIR}/hy2.key"
|
||||
echo "[gen-secrets] 已写入 Hy2 证书"
|
||||
fi
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# print-clients.sh —— 生成两条客户端导入串,写入 ./secrets/clients.txt。
|
||||
# 注意:含口令/密钥,【不打印到 stdout】以免进入 CI 日志;手动 `ssh ec2 cat` 取用。
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.." # -> deploy/
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source ./secrets/pangolin.env
|
||||
|
||||
# 公网 IP:优先 IMDSv2,可用 PANGOLIN_PUBLIC_IP 覆盖
|
||||
HOST="${PANGOLIN_PUBLIC_IP:-}"
|
||||
if [[ -z "$HOST" ]]; then
|
||||
TOKEN="$(curl -s -X PUT 'http://169.254.169.254/latest/api/token' -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' || true)"
|
||||
HOST="$(curl -s -H "X-aws-ec2-metadata-token: ${TOKEN}" http://169.254.169.254/latest/meta-data/public-ipv4 || true)"
|
||||
fi
|
||||
[[ -z "$HOST" ]] && HOST="YOUR_SERVER_IP"
|
||||
|
||||
REALITY_LINK="vless://${UUID}@${HOST}:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.apple.com&fp=chrome&pbk=${REALITY_PUBLIC_KEY}&sid=${REALITY_SHORT_ID}&type=tcp#pangolin-reality"
|
||||
HY2_LINK="hysteria2://${HY2_PASSWORD}@${HOST}:443?insecure=1&sni=www.bing.com#pangolin-hy2"
|
||||
|
||||
OUT="./secrets/clients.txt"
|
||||
umask 177
|
||||
cat > "$OUT" <<EOF
|
||||
# pangolin Phase-0 客户端导入信息 (生成于 $(date -u +%FT%TZ))
|
||||
# 含敏感信息,勿外泄。
|
||||
|
||||
[REALITY / VLESS+Vision] —— 平时主线
|
||||
${REALITY_LINK}
|
||||
|
||||
[Hysteria2] —— 晚高峰加速线(自签证书,客户端需允许不安全/insecure)
|
||||
${HY2_LINK}
|
||||
|
||||
字段速查:
|
||||
server = ${HOST}
|
||||
REALITY sni = www.apple.com port=443/tcp flow=xtls-rprx-vision
|
||||
REALITY pbk = ${REALITY_PUBLIC_KEY}
|
||||
REALITY sid = ${REALITY_SHORT_ID}
|
||||
uuid = ${UUID}
|
||||
Hy2 sni = www.bing.com port=443/udp insecure=1
|
||||
EOF
|
||||
echo "[print-clients] 已写入 ${OUT}(用 'ssh ec2 cat /opt/pangolin/secrets/clients.txt' 取用)"
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# root-setup.sh —— 一次性 root 前置(在 EC2 上以 root 执行一次)。
|
||||
# sudo bash /opt/pangolin/setup/root-setup.sh
|
||||
#
|
||||
# 作用:
|
||||
# 1. 安装受限特权脚本到 /usr/local/sbin/pangolin-nginx-apply.sh(root:root 0755)
|
||||
# 2. 安装 sudoers 片段,授权 ec2-user 仅 NOPASSWD 调用上述脚本
|
||||
# 之后 CI(ec2-user)即可非交互地增量更新 nginx 路由,且无法获得通用 root。
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "请以 root 运行:sudo bash $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC_DIR="$(cd "$(dirname "$0")/.." && pwd)" # -> /opt/pangolin/deploy 或仓库 deploy/
|
||||
APPLY_SRC="${SRC_DIR}/nginx/pangolin-nginx-apply.sh"
|
||||
APPLY_DST="/usr/local/sbin/pangolin-nginx-apply.sh"
|
||||
SUDOERS="/etc/sudoers.d/pangolin"
|
||||
DEPLOY_USER="${PANGOLIN_DEPLOY_USER:-ec2-user}"
|
||||
|
||||
[[ -f "$APPLY_SRC" ]] || { echo "找不到 $APPLY_SRC" >&2; exit 1; }
|
||||
|
||||
install -o root -g root -m 0755 "$APPLY_SRC" "$APPLY_DST"
|
||||
echo "[root-setup] 已安装 $APPLY_DST"
|
||||
|
||||
cat > "$SUDOERS" <<EOF
|
||||
${DEPLOY_USER} ALL=(root) NOPASSWD: ${APPLY_DST}
|
||||
EOF
|
||||
chmod 0440 "$SUDOERS"
|
||||
visudo -cf "$SUDOERS" >/dev/null && echo "[root-setup] 已安装并校验 $SUDOERS"
|
||||
|
||||
echo "[root-setup] 完成。现在 ${DEPLOY_USER} 可执行: sudo ${APPLY_DST}"
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"log": { "level": "warn", "timestamp": true },
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "hysteria2",
|
||||
"tag": "hy2-in",
|
||||
"listen": "::",
|
||||
"listen_port": 443,
|
||||
"users": [
|
||||
{ "name": "phase0", "password": "__HY2_PASSWORD__" }
|
||||
],
|
||||
"masquerade": "https://www.bing.com",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"alpn": ["h3"],
|
||||
"certificate_path": "/etc/sing-box/cert/hy2.crt",
|
||||
"key_path": "/etc/sing-box/cert/hy2.key"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{ "type": "direct", "tag": "direct" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"log": { "loglevel": "warning" },
|
||||
"inbounds": [
|
||||
{
|
||||
"tag": "vless-reality-in",
|
||||
"listen": "0.0.0.0",
|
||||
"port": 11443,
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{ "id": "__UUID__", "flow": "xtls-rprx-vision" }
|
||||
],
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp",
|
||||
"security": "reality",
|
||||
"realitySettings": {
|
||||
"show": false,
|
||||
"dest": "www.apple.com:443",
|
||||
"xver": 0,
|
||||
"serverNames": ["www.apple.com"],
|
||||
"privateKey": "__REALITY_PRIVATE_KEY__",
|
||||
"shortIds": ["__REALITY_SHORT_ID__"]
|
||||
}
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": ["http", "tls", "quic"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{ "protocol": "freedom", "tag": "direct" }
|
||||
]
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
# Pangolin 终端 VPN —— 整体技术方案
|
||||
|
||||
> 状态:设计稿 v1 · 日期:2026-05-30
|
||||
> 选型基线:客户端 **Flutter 自研 UI**;后端 **先成熟面板、后自研 Go**;协议主推 **REALITY**。
|
||||
|
||||
---
|
||||
|
||||
## 0. 一句话定位
|
||||
|
||||
面向中国大陆用户的「傻瓜式」科学上网工具:一键连接、自动选线、多端统一,
|
||||
免费+付费双轨,抗封锁、防跟踪,客户端自研 + 标准订阅兼容三方软件。
|
||||
|
||||
### ⚠️ 合规与运营者安全前提(与技术同等重要)
|
||||
|
||||
- 在中国境内**运营收费翻墙服务属违法经营**,风险在运营者而非用户。
|
||||
- 运营主体、服务器、域名、收款账户一律用**境外身份**,与国内真实身份**完全隔离**。
|
||||
- 管理后台不暴露公网;节点不留连接日志;支付走加密货币 / 可随时更换的通道。
|
||||
- 本文档只涉及"绕过审查、访问开放互联网"的正当技术,不涉及攻击/入侵他人系统。
|
||||
|
||||
---
|
||||
|
||||
## 1. 总体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
用户(小白) │ 控制面 (境外) │
|
||||
┌──────────┐ │ ┌──────────┐ ┌────────────────┐ │
|
||||
│ Flutter │──订阅──▶ │ │ 面板/API │───▶│ 用户/订单/流量库 │ │
|
||||
│ 客户端 │ │ │(XBoard+ │ └────────────────┘ │
|
||||
└────┬─────┘ │ │ Marzban) │ │
|
||||
│ │ └────┬─────┘ 下发配置 / 限速 / 额度 │
|
||||
│ 科学上网流量 │ ▼ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
└─────────────▶│ 数据面:多地接入节点 (VPS 集群) │ │
|
||||
│ REALITY / Hysteria2 / CDN(WS)中转 │ │
|
||||
└─────────────────────────────────────┘
|
||||
┌──────────┐
|
||||
│ 宣传页 │ ← Cloudflare Pages + 备用直连域名 + GitHub/TG 分发
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
**核心原则:控制面(账号/计费)与数据面(代理节点)分离。**
|
||||
客户端只认「订阅链接」,节点可随时增删换 IP;被封换节点不影响账号体系。
|
||||
这是所有成熟机场的标准架构。
|
||||
|
||||
---
|
||||
|
||||
## 2. 协议选型(抗封锁核心)
|
||||
|
||||
GFW = 主动探测 + 流量指纹 + IP 封锁。2026 年最优组合:
|
||||
|
||||
| 协议 | 用途 | 抗封锁原理 | 速度 |
|
||||
|------|------|-----------|------|
|
||||
| **VLESS + Vision + REALITY** | 主力 | 偷用真实大站 TLS(如 microsoft.com),无自签指纹,主动探测回落真站 | 高 |
|
||||
| **Hysteria2** | 晚高峰/高丢包备线 | QUIC/UDP + 暴力拥塞控制 + 端口跳跃抗 QoS | 极高 |
|
||||
| **VLESS + WS + TLS over CDN** | IP 被封保底 | 走 Cloudflare,用户连 CF 的 IP,难整段封 | 中 |
|
||||
| TUIC v5 / ShadowTLS | 补充 | QUIC / 套真实 TLS 握手 | 高 |
|
||||
|
||||
**主推 REALITY**(快、最难封),**CDN/WS 保底**(REALITY IP 被封自动切),
|
||||
**Hysteria2 加速**(晚高峰)。三者 sing-box 内核原生支持,一套内核搞定。
|
||||
|
||||
**禁用**:裸 Shadowsocks、VMess、自签证书 Trojan —— 指纹已被识别。
|
||||
|
||||
---
|
||||
|
||||
## 3. 客户端 —— Flutter 自研 UI(已选)
|
||||
|
||||
### 3.1 分层
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Flutter UI (Dart) —— 一套代码,~90% 复用 │ 连接按钮 / 节点信号灯 / 额度 / 登录续费
|
||||
├──────────────────────────────────────────┤
|
||||
│ FFI / Platform Channel 桥接层 │
|
||||
├──────────────────────────────────────────┤
|
||||
│ sing-box 内核 (Go, libbox) —— 协议/限速/路由│ 只写一次,全平台复用
|
||||
├──────────────────────────────────────────┤
|
||||
│ 各平台 VPN 壳(平台特定,薄) │
|
||||
│ iOS/iPadOS: NetworkExtension PacketTunnel │
|
||||
│ Android: VpnService │
|
||||
│ Win/macOS/Linux: TUN 网卡 │
|
||||
└──────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **内核**:[sing-box](https://github.com/SagerNet/sing-box) 的 `libbox`(gomobile 产物)。协议、限速、路由、URLTest 全在内核层,只写一次。
|
||||
- **UI**:Flutter,一套 Dart 出 iOS / Android / macOS / Windows / Linux。
|
||||
- **可借鉴的开源实现**(遵守各自许可证):**FlClash**、sing-box 官方 app(SFA/SFI/SFM/SFW)。
|
||||
- **Web 端**:浏览器做不了系统级 VPN。Web 定位 = **用户中心**(登录、看流量、续费、取订阅、看节点状态)。需浏览器代理时另做 Chrome 扩展(WS over CDN)。
|
||||
|
||||
### 3.2 小白友好关键点(差异化卖点)
|
||||
|
||||
- 首屏只有一个**大连接按钮** + 当前节点 + 信号灯。
|
||||
- 默认「**智能选择/自动**」(URLTest 选延迟最低的可用节点),高级用户才手动切地区。
|
||||
- 默认开:**Kill-switch**(断开即断网,防真实 IP 泄露)、防 DNS 泄露、防 WebRTC 泄露。
|
||||
- 一键导入订阅 / 扫码登录,免配置。
|
||||
|
||||
### 3.3 三方软件兼容(并行提供)
|
||||
|
||||
输出标准**订阅链接**(sing-box / Clash.Meta / v2rayN 格式),
|
||||
用户可用 v2rayN、Clash Verge、Shadowrocket、Stash、NekoBox 直接导入。
|
||||
这是"提供账号信息即用"的落地方式,也是高级用户入口。
|
||||
|
||||
### 3.4 上架注意
|
||||
|
||||
- **iOS 中国区会下架翻墙 App** → 用海外 Apple 开发者账号 + 海外区上架 / TestFlight / AltStore。
|
||||
- Android 走官网 APK + GitHub Releases + 应用商店(海外 Google Play)。
|
||||
|
||||
> 开发顺序建议:先用 sing-box 官方 app 改皮肤跑通商业闭环,再切到 Flutter 自研(避免一上来卡在客户端)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 后端 —— 先面板,后自研(已选)
|
||||
|
||||
### 4.1 第一阶段:成熟面板(开箱即用)
|
||||
|
||||
| 组件 | 选型 | 职责 |
|
||||
|------|------|------|
|
||||
| 商业前台 | **XBoard**(或 V2board) | 套餐/下单/支付/工单/邀请返利 |
|
||||
| 节点管理 | **Marzban / Marzneshin** | 用户、订阅生成、流量统计、到期、多节点 |
|
||||
| 数据面 | 各节点 sing-box / Xray | 真正的代理 |
|
||||
|
||||
免费/付费额度、限速、到期,面板原生支持。**起步最快。**
|
||||
|
||||
### 4.2 第二阶段:自研 Go 后端(深度定制时迁移)
|
||||
|
||||
- **语言**:Go(与团队偏好一致,且与 sing-box 同栈)。
|
||||
- **服务**:账号鉴权(JWT)、订阅生成、订单/支付、流量计量、节点健康调度。
|
||||
- **DB**:PostgreSQL(用户/订单)+ Redis(限速令牌桶 / 会话 / 节点状态缓存)。
|
||||
- **节点 Agent**:每节点 = sing-box + 上报 agent(流量 / 在线 / 延迟 → 控制面)。
|
||||
- **迁移策略**:自研时复用面板的数据库 schema 与订阅格式,客户端无感切换。
|
||||
|
||||
### 4.3 限速(需求 3,两层)
|
||||
|
||||
1. **节点层硬限速**:sing-box/Xray 出站按用户打标 + Linux `tc`(HTB);免费用户单独限速队列。最可靠。
|
||||
2. **额度层**:面板按日/月流量配额,超额断流。免费用户每日额度;**看激励视频广告 → 客户端调 API 临时提额**。
|
||||
|
||||
### 4.4 接入点 + 网络状态(需求 4)
|
||||
|
||||
- 控制面每 ~30s 探测每个节点:延迟 / 丢包 / 在线 / 负载。
|
||||
- 订阅下发节点列表 + `status API`;UI 显示**绿/黄/红信号灯 + 延迟 ms**。
|
||||
- IP 分级:免费用户用"消耗品 IP 池"(易被封),付费用户用"精品 IP 池"。
|
||||
|
||||
---
|
||||
|
||||
## 5. 安全 / 抗封锁 / 防跟踪(需求 6)
|
||||
|
||||
**抗被墙(数据面)**
|
||||
- REALITY 为主(无指纹);IP 用冷门小厂 VPS,定期轮换;CDN 中转保底。
|
||||
- Hysteria2 端口跳跃抗 UDP QoS。
|
||||
- 订阅域名、控制面 API 也套 CDN/REALITY,防"取订阅"这步被封或被关联。
|
||||
|
||||
**防跟踪 / 隐私**
|
||||
- 不收集真实身份;注册仅邮箱 / 设备 ID + 卡密。
|
||||
- 节点 **no-log**;DNS 走 DoH/DoQ 防污染与泄露。
|
||||
- 客户端默认 Kill-switch + 防 DNS / WebRTC 泄露。
|
||||
- 控制面与数据面隔离;节点不存用户库,被抄一个节点不暴露全量用户。
|
||||
|
||||
**运营者安全(最致命)**
|
||||
- 服务器 / 域名 / 支付全用境外身份,与国内真实身份隔离。
|
||||
- 加密货币付 VPS;域名隐私保护;管理后台仅 VPN 内网开放。
|
||||
|
||||
---
|
||||
|
||||
## 6. 宣传页(需求 7)
|
||||
|
||||
矛盾:境外部署 + 国内直连 + 安全,三者天然冲突(境外站国内常被墙)。务实方案:
|
||||
|
||||
- **静态站**:Astro / Next.js(SSG)纯静态 → **Cloudflare Pages**(免费、全球 CDN、自带 DDoS 防护)。
|
||||
- **国内直连对策**:
|
||||
1. 多备用域名 + 自有 IP 直连镜像,主站被污染时引导切换。
|
||||
2. 下载/取订阅入口做成可镜像分发:**GitHub Releases、Telegram 频道、网盘**,不把命脉绑死单域名。
|
||||
- **抗封获客靠去中心化**:Telegram 群/频道、Twitter/X、酷安、V2EX、邀请码裂变。宣传页是"信任背书 + 下载入口"。
|
||||
- 安全:全站 HTTPS、无第三方追踪脚本、不收集访客信息。
|
||||
|
||||
---
|
||||
|
||||
## 7. 商业化(需求 2 + 交易)
|
||||
|
||||
### 7.1 套餐
|
||||
- **免费**:每日 1–2 GB 或限速;**看激励视频广告解锁额外额度**(广告用海外 AdMob/Unity)。走消耗品 IP 池。
|
||||
- **付费**:月/季/年 + 流量包;精品线路、不限速、多节点。
|
||||
- 转化漏斗:免费体验 → 晚高峰限速 → 推付费精品线路。
|
||||
|
||||
### 7.2 收款(国内最大难点)
|
||||
|
||||
| 方式 | 说明 | 风险 |
|
||||
|------|------|------|
|
||||
| **USDT(TRC20)** | 最抗封、最隐私,首选 | 用户门槛高 |
|
||||
| **自动发卡(卡密)** | 机场标配,支付宝/微信中转 | 收款码易封,需轮换 |
|
||||
| 爱发电 / Ko-fi | 打赏制,规避直接售卖定性 | 平台可能封 |
|
||||
| Stripe / Paddle(境外主体) | 正规,但需境外公司 + 外卡 | 主体门槛 |
|
||||
|
||||
**建议**:主推 **USDT + 自动发卡**;收款通道与运营主体隔离,随时可换。
|
||||
**禁用**绑定真实身份的个人支付宝/微信收款。
|
||||
|
||||
### 7.3 目标人群 & 获客
|
||||
- **核心**:留学/外贸/跨境电商、程序员/科研、追剧/游戏/ChatGPT 用户、数字游民。
|
||||
- **小白向卖点**:一键连接、自动选线、傻瓜 UI(对比 v2rayN 这类极客工具)。
|
||||
- **渠道**:Telegram、Twitter/X、YouTube 评测合作、酷安、邀请返利裂变、SEO(关键词:稳定梯子 / ChatGPT 怎么用)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 技术栈一页纸
|
||||
|
||||
| 层 | 选型 |
|
||||
|----|------|
|
||||
| 代理内核 | **sing-box**(REALITY + Hysteria2 + WS/CDN 保底) |
|
||||
| 客户端 | **Flutter**(iOS/Android/Win/macOS/Linux)+ 各端 VPN 壳;Web = 用户中心 |
|
||||
| 三方兼容 | 标准订阅(sing-box / Clash.Meta / v2rayN) |
|
||||
| 控制面/计费 | **XBoard**(阶段1)→ 自研 **Go**(阶段2) |
|
||||
| 节点管理 | **Marzban / Marzneshin** |
|
||||
| 数据库 | PostgreSQL + Redis |
|
||||
| 限速 | sing-box 出站标记 + tc + 面板配额 |
|
||||
| 节点监控 | Go agent 上报 → 客户端信号灯 |
|
||||
| 宣传页 | Astro/Next SSG + Cloudflare Pages + 多备份入口 |
|
||||
| 收款 | USDT(TRC20)+ 自动发卡;境外 Stripe 可选 |
|
||||
| 基础设施 | 多地冷门小厂 VPS + Cloudflare CDN |
|
||||
|
||||
---
|
||||
|
||||
## 9. 落地阶段(MVP 优先)
|
||||
|
||||
| 阶段 | 目标 | 周期 |
|
||||
|------|------|------|
|
||||
| **0** | 1 台 VPS + sing-box + REALITY,用 v2rayN/Shadowrocket 连通,跑 vpn-test 验证线路 | 1–2 周 |
|
||||
| **1** | XBoard + Marzban,通注册/订阅/限速/卡密收款;靠分享订阅 + 三方软件**验证付费意愿** | 2–4 周 |
|
||||
| **2** | 先用 sing-box 官方 app 改品牌出客户端,接登录/信号灯/免费额度 | 2–4 周 |
|
||||
| **3** | Flutter 自研 UI、广告变现、多节点智能调度、宣传站 | 持续 |
|
||||
|
||||
**先验证商业模式(有没有人付费),再投入客户端自研。**
|
||||
|
||||
---
|
||||
|
||||
## 10. 待决事项 / 下一步
|
||||
|
||||
- [ ] 阶段0:出 sing-box 服务端 REALITY 配置 + 一键部署脚本
|
||||
- [ ] 选定首批 VPS 服务商与地区(冷门小厂、可加密货币付款)
|
||||
- [ ] XBoard + Marzban 的 docker-compose 部署方案
|
||||
- [ ] 客户端品牌名 / 域名 / 收款通道确定
|
||||
- [ ] Flutter 客户端工程脚手架与 sing-box libbox 桥接 PoC
|
||||
@@ -0,0 +1,26 @@
|
||||
# Pangolin 实施计划(Plan)
|
||||
|
||||
> 配套设计文档:[`../docs/技术方案.md`](../docs/技术方案.md)
|
||||
> 更新日期:2026-05-30 · 总原则:**先验证付费意愿,再投客户端自研**
|
||||
|
||||
## 阶段总览
|
||||
|
||||
| 阶段 | 目标 | 周期 | 文档 |
|
||||
|------|------|------|------|
|
||||
| **0** | 单节点 REALITY 跑通,验证线路质量 | 1–2 周 | [phase-0-线路验证.md](phase-0-线路验证.md) |
|
||||
| **1** | 面板 + 订阅 + 限速 + 卡密收款,验证付费意愿 | 2–4 周 | [phase-1-后端面板与商业闭环.md](phase-1-后端面板与商业闭环.md) |
|
||||
| **2** | 改品牌客户端 + 登录/信号灯/免费额度 | 2–4 周 | [phase-2-客户端MVP.md](phase-2-客户端MVP.md) |
|
||||
| **3** | Flutter 自研 UI + 自研后端 + 广告 + 宣传站 | 持续 | [phase-3-自研与规模化.md](phase-3-自研与规模化.md) |
|
||||
|
||||
## 贯穿全程的横切事项
|
||||
|
||||
| 主题 | 文档 |
|
||||
|------|------|
|
||||
| 运营者安全 / 合规隔离(最高优先级) | [security-运营安全.md](security-运营安全.md) |
|
||||
| 宣传页与获客 | [marketing-宣传与获客.md](marketing-宣传与获客.md) |
|
||||
|
||||
## 阶段门禁(Gate)
|
||||
|
||||
- **0 → 1**:线路稳定 ≥ 3 天,晚高峰 YouTube 1080p 流畅,REALITY 未被探测封锁。
|
||||
- **1 → 2**:有 ≥ N 个真实付费用户(自定阈值),订阅/限速/收款闭环可用。
|
||||
- **2 → 3**:改品牌客户端日活留存达标,客诉集中在体验而非"连不上"。
|
||||
@@ -0,0 +1,42 @@
|
||||
# 横切 —— 宣传页与获客(需求 7 + 定向人群)
|
||||
|
||||
---
|
||||
|
||||
## A. 宣传页(境外部署 + 国内直连 + 安全)
|
||||
|
||||
矛盾:境外站国内常被墙。务实方案 —— 不把命脉绑死单域名。
|
||||
|
||||
- [ ] 静态站:Astro / Next.js(SSG)纯静态
|
||||
- [ ] 部署 **Cloudflare Pages**(免费、全球 CDN、自带 DDoS 防护)
|
||||
- [ ] 国内直连对策:
|
||||
- [ ] 多备用域名 + 自有 IP 直连镜像,主站被污染时引导切换
|
||||
- [ ] 下载 / 取订阅入口可镜像分发:**GitHub Releases、Telegram 频道、网盘**
|
||||
- [ ] 安全:全站 HTTPS、**无第三方追踪脚本**、不收集访客信息
|
||||
- [ ] 定位:宣传页是"信任背书 + 下载入口",不是唯一流量来源
|
||||
|
||||
## B. 获客渠道(抗封靠去中心化)
|
||||
|
||||
- [ ] Telegram 群 / 频道(核心阵地)
|
||||
- [ ] Twitter / X
|
||||
- [ ] 酷安、V2EX、小众论坛
|
||||
- [ ] YouTube 评测合作 / KOL
|
||||
- [ ] **邀请码返利裂变**(老带新)
|
||||
- [ ] SEO 关键词:稳定梯子、ChatGPT 怎么用、科学上网 推荐
|
||||
|
||||
## C. 目标人群
|
||||
|
||||
| 人群 | 痛点 / 卖点 |
|
||||
|------|------------|
|
||||
| 留学 / 外贸 / 跨境电商 | 稳定、回国线路、商务可用 |
|
||||
| 程序员 / 科研 | 查资料、GitHub、稳定不掉线 |
|
||||
| 追剧 / 游戏 / ChatGPT 用户 | 流媒体解锁、低延迟、AI 工具可用 |
|
||||
| 数字游民 | 多地节点、跨设备 |
|
||||
|
||||
## D. 差异化卖点(对比 v2rayN 这类极客工具)
|
||||
|
||||
- **小白友好**:一键连接、自动选线、傻瓜 UI(需求 5)
|
||||
- 多端统一 + 三方软件兼容(给极客留后路)
|
||||
- 免费可用(看广告提额)+ 付费精品线路的清晰分层
|
||||
|
||||
## E. 转化漏斗
|
||||
免费体验 → 晚高峰限速感知 → 推付费精品线路(不限速 / 多节点 / 精品 IP)
|
||||
@@ -0,0 +1,45 @@
|
||||
# 阶段 0 —— 单节点线路验证(1–2 周)
|
||||
|
||||
**目标**:用 1 台 VPS 跑通 sing-box + REALITY,确认线路质量,再谈一切。
|
||||
**门禁(进入阶段1)**:线路稳定 ≥ 3 天;晚高峰 YouTube 1080p 流畅;REALITY 未被主动探测封锁。
|
||||
|
||||
---
|
||||
|
||||
## 任务清单
|
||||
|
||||
### T0.1 选购 VPS
|
||||
- [ ] 选 1–2 个**冷门小厂** VPS(避开被重点封锁的大厂大段 IP)
|
||||
- [ ] 地区候选:日本 / 香港 / 新加坡 / 美西(就近优先,先测延迟)
|
||||
- [ ] 支持**加密货币付款**、可隐私注册
|
||||
- [ ] 配置:1C2G 起步,带宽优先于 CPU
|
||||
|
||||
### T0.2 服务端部署 sing-box + REALITY
|
||||
- [ ] 安装 sing-box,配置 VLESS + Vision + REALITY
|
||||
- [ ] `dest` 偷用真实大站(如 `www.microsoft.com:443` / `www.apple.com:443`)
|
||||
- [ ] 生成 Reality 密钥对、short_id、UUID
|
||||
- [ ] 开放对应端口,关闭无关端口,禁用 root 密码登录(仅密钥)
|
||||
- [ ] 备线:加一条 Hysteria2(UDP)用于晚高峰对比
|
||||
|
||||
### T0.3 客户端连通(先用三方软件)
|
||||
- [ ] 桌面:v2rayN / Clash Verge 导入
|
||||
- [ ] iOS:Shadowrocket / sing-box;Android:NekoBox / sing-box
|
||||
- [ ] 确认 IP 落地正确、无 DNS 泄露(dnsleaktest)、无 WebRTC 泄露
|
||||
|
||||
### T0.4 线路质量验证(用 vpn-test skill)
|
||||
- [ ] 出海:Cloudflare / Google / YouTube 延迟与下载速度
|
||||
- [ ] 回流:B站 / 爱奇艺 / 优酷 / 百度 延迟(确认回国不绕路)
|
||||
- [ ] **晚高峰(20:00–23:00)** 重点复测,对比 REALITY vs Hysteria2
|
||||
- [ ] 连续观察 3 天,记录是否出现 IP 被封 / 主动探测迹象
|
||||
|
||||
---
|
||||
|
||||
## 交付物
|
||||
- 可复用的 sing-box 服务端配置模板(REALITY + Hysteria2)
|
||||
- 一键部署脚本(幂等、参数化)
|
||||
- 线路质量测试报告(vpn-test 表格 + 3 天观察记录)
|
||||
|
||||
## 验收标准
|
||||
- [ ] 任意终端 5 分钟内导入即用
|
||||
- [ ] 晚高峰 YouTube 1080p 不卡
|
||||
- [ ] 3 天内 IP 未被封、未见探测封锁
|
||||
- [ ] 无 DNS / WebRTC / IP 泄露
|
||||
@@ -0,0 +1,56 @@
|
||||
# 阶段 1 —— 后端面板与商业闭环(2–4 周)
|
||||
|
||||
**目标**:上成熟面板,跑通「注册 → 订阅 → 限速 → 收款」闭环,靠分享订阅 + 三方软件**验证有没有人付费**。
|
||||
**门禁(进入阶段2)**:有 ≥ N 个真实付费用户(自定阈值);订阅/限速/收款全链路可用。
|
||||
|
||||
> 选型已定:**先用成熟面板(XBoard + Marzban),后迁自研 Go**。
|
||||
|
||||
---
|
||||
|
||||
## 任务清单
|
||||
|
||||
### T1.1 控制面部署(境外服务器)
|
||||
- [ ] 部署 **XBoard**(商业前台:套餐 / 下单 / 支付 / 工单 / 邀请返利)
|
||||
- [ ] 部署 **Marzban / Marzneshin**(节点管理:用户 / 订阅 / 流量统计 / 到期)
|
||||
- [ ] PostgreSQL + Redis 就位
|
||||
- [ ] 控制面后台**不暴露公网**(仅 VPN 内网 / IP 白名单 / 改端口 + 强口令 + 2FA)
|
||||
- [ ] 订阅域名套 CDN / REALITY,防"取订阅"被封或被关联
|
||||
|
||||
### T1.2 节点接入
|
||||
- [ ] 阶段0 的节点纳入面板管理
|
||||
- [ ] 再加 1–2 个节点,验证多节点订阅下发
|
||||
- [ ] **IP 分级**:消耗品池(免费)/ 精品池(付费)
|
||||
|
||||
### T1.3 套餐与额度(需求 2)
|
||||
- [ ] 免费:每日 1–2 GB 或限速;预留"看广告提额"的 API 钩子(阶段3 接广告)
|
||||
- [ ] 付费:月 / 季 / 年 + 流量包
|
||||
- [ ] 到期与超额自动断流
|
||||
|
||||
### T1.4 限速(需求 3,两层)
|
||||
- [ ] 节点层:sing-box/Xray 出站按用户打标 + Linux `tc`(HTB),免费用户单独限速队列
|
||||
- [ ] 额度层:面板按日/月配额超额断流
|
||||
- [ ] 验证免费 vs 付费速度差异符合预期
|
||||
|
||||
### T1.5 节点状态(需求 4)
|
||||
- [ ] 控制面定时探测节点:延迟 / 丢包 / 在线 / 负载
|
||||
- [ ] 暴露 `status API` 供客户端取用(为阶段2 信号灯铺路)
|
||||
|
||||
### T1.6 收款(需求 + 交易)
|
||||
- [ ] 接 **USDT(TRC20)** 收款
|
||||
- [ ] 接 **自动发卡(卡密)**,支付宝/微信走可轮换的中转通道
|
||||
- [ ] 收款通道与运营主体**隔离**,可随时更换
|
||||
- [ ] **禁用**绑定真实身份的个人支付宝/微信
|
||||
|
||||
---
|
||||
|
||||
## 交付物
|
||||
- XBoard + Marzban 的 `docker-compose` 部署方案与对接步骤
|
||||
- 套餐 / 限速 / 额度配置说明
|
||||
- 收款通道接入说明(USDT + 发卡)
|
||||
- 一份"用三方软件导入订阅"的用户上手指引
|
||||
|
||||
## 验收标准
|
||||
- [ ] 新用户:注册 → 下单付款 → 拿订阅 → 三方软件导入即用,全程顺畅
|
||||
- [ ] 免费/付费限速生效且有明显区分
|
||||
- [ ] 节点状态可查
|
||||
- [ ] 出现首批真实付费用户
|
||||
@@ -0,0 +1,45 @@
|
||||
# 阶段 2 —— 客户端 MVP(2–4 周)
|
||||
|
||||
**目标**:先用 **sing-box 官方 app 改品牌**,接入登录 / 节点信号灯 / 免费额度,快速出自有客户端;**不**一上来就 Flutter 自研,避免卡进度。
|
||||
**门禁(进入阶段3)**:改品牌客户端日活留存达标;客诉集中在体验而非"连不上"。
|
||||
|
||||
> 最终客户端走 **Flutter 自研 UI**(阶段3),本阶段是过渡。
|
||||
|
||||
---
|
||||
|
||||
## 任务清单
|
||||
|
||||
### T2.1 选基底
|
||||
- [ ] 基于 sing-box 官方 app(SFA/SFI/SFM/SFW)或 FlClash 改造(遵守各自许可证)
|
||||
- [ ] 替换 logo / 配色 / 名称
|
||||
|
||||
### T2.2 账号与订阅打通
|
||||
- [ ] 内置注册 / 登录(邮箱或设备 ID + 卡密)
|
||||
- [ ] 登录后自动拉取该用户订阅,免手动粘贴
|
||||
- [ ] 展示剩余额度 / 到期时间(调阶段1 面板 API)
|
||||
|
||||
### T2.3 小白友好核心(需求 5)
|
||||
- [ ] 首屏一个**大连接按钮** + 当前节点 + 信号灯
|
||||
- [ ] 默认「**智能选择**」(URLTest 自动选最优可用节点)
|
||||
- [ ] 默认开 Kill-switch + 防 DNS / WebRTC 泄露
|
||||
|
||||
### T2.4 节点状态展示(需求 4)
|
||||
- [ ] 接阶段1 的 `status API`,节点列表显示**绿/黄/红信号灯 + 延迟 ms**
|
||||
|
||||
### T2.5 多端打包
|
||||
- [ ] Android APK(官网 + GitHub Releases + 海外 Google Play)
|
||||
- [ ] iOS(海外开发者账号上架 / TestFlight / AltStore;**中国区会下架**)
|
||||
- [ ] 桌面 Win/macOS(就基底支持范围)
|
||||
|
||||
---
|
||||
|
||||
## 交付物
|
||||
- 改品牌的多端客户端安装包
|
||||
- 客户端 ↔ 面板 API 对接说明
|
||||
- 用户上手指引(截图版)
|
||||
|
||||
## 验收标准
|
||||
- [ ] 小白用户:下载 → 登录 → 一键连接,无需任何配置
|
||||
- [ ] 自动选线可用,信号灯准确
|
||||
- [ ] 免费额度 / 看广告提额钩子可用(广告阶段3 接)
|
||||
- [ ] 留存与客诉达门禁要求
|
||||
@@ -0,0 +1,57 @@
|
||||
# 阶段 3 —— 自研与规模化(持续)
|
||||
|
||||
**目标**:切到 **Flutter 自研客户端 + 自研 Go 后端**,接广告变现、多节点智能调度、上线宣传站。
|
||||
|
||||
---
|
||||
|
||||
## A. Flutter 自研客户端
|
||||
|
||||
### 任务
|
||||
- [ ] Flutter 工程脚手架(iOS/Android/Win/macOS/Linux)
|
||||
- [ ] **sing-box libbox(gomobile)桥接 PoC**(FFI / Platform Channel)
|
||||
- [ ] 各端 VPN 壳:iOS NetworkExtension / Android VpnService / 桌面 TUN
|
||||
- [ ] 复刻并超越阶段2 的 UI(品牌、动效、引导)
|
||||
- [ ] 平滑迁移:复用阶段1/2 的订阅格式与 API,老用户无感
|
||||
|
||||
### 验收
|
||||
- [ ] UI ~90% 代码跨端复用
|
||||
- [ ] 连接稳定性、性能不低于改品牌版
|
||||
|
||||
---
|
||||
|
||||
## B. 自研 Go 后端(替换面板)
|
||||
|
||||
### 任务
|
||||
- [ ] Go 服务:鉴权(JWT) / 订阅生成 / 订单支付 / 流量计量 / 节点调度
|
||||
- [ ] PostgreSQL + Redis(限速令牌桶 / 节点状态缓存)
|
||||
- [ ] 节点 Agent:流量 / 在线 / 延迟 上报控制面
|
||||
- [ ] 复用面板的 DB schema 与订阅格式,灰度迁移、可回滚
|
||||
|
||||
### 验收
|
||||
- [ ] 与面板功能对等后切流
|
||||
- [ ] 多节点智能调度(按负载/延迟分配)生效
|
||||
|
||||
---
|
||||
|
||||
## C. 广告变现(免费用户)
|
||||
|
||||
### 任务
|
||||
- [ ] 接海外激励视频广告(AdMob / Unity Ads)
|
||||
- [ ] 看广告 → 客户端调 API 临时提额(对接阶段1 预留钩子)
|
||||
- [ ] 风控:防刷量、频次限制
|
||||
|
||||
---
|
||||
|
||||
## D. 宣传站上线
|
||||
|
||||
详见 [marketing-宣传与获客.md](marketing-宣传与获客.md)。
|
||||
- [ ] Astro/Next SSG + Cloudflare Pages
|
||||
- [ ] 多备用域名 + GitHub/TG 分发入口
|
||||
- [ ] 全站 HTTPS、无第三方追踪
|
||||
|
||||
---
|
||||
|
||||
## E. 规模化运维
|
||||
- [ ] 节点 IP 轮换自动化(被封自动下线 + 补新)
|
||||
- [ ] 监控告警(节点存活、被封探测、容量水位)
|
||||
- [ ] 客服 / 工单 / 退款流程
|
||||
@@ -0,0 +1,50 @@
|
||||
# 横切 —— 运营者安全 / 合规隔离(最高优先级)
|
||||
|
||||
> ⚠️ 这是整个项目**风险最高**的部分。技术(代理/抗封锁)是合法成熟的;
|
||||
> 但在中国境内运营收费翻墙服务属违法经营,**风险在运营者而非用户**,近年已有刑事/行政判例。
|
||||
> 下面的隔离措施请当作和技术同等优先。
|
||||
|
||||
---
|
||||
|
||||
## A. 身份隔离(贯穿全程)
|
||||
|
||||
- [ ] 运营主体、服务器、域名、收款账户一律用**境外身份**
|
||||
- [ ] 与国内真实身份**完全隔离**,不交叉、不复用邮箱/手机号/支付方式
|
||||
- [ ] VPS 用加密货币付款;域名开隐私保护(WHOIS privacy)
|
||||
- [ ] 管理操作走专用环境,不在日常个人设备/网络上做
|
||||
|
||||
## B. 基础设施安全
|
||||
|
||||
- [ ] 管理后台**不暴露公网**:仅 VPN 内网 / IP 白名单 / 改端口 + 强口令 + 2FA
|
||||
- [ ] 服务器仅密钥登录,禁 root 密码,最小化开放端口
|
||||
- [ ] **控制面与数据面隔离**:节点不存用户库,被抄一个节点不暴露全量用户
|
||||
|
||||
## C. 用户隐私(防跟踪,需求 6)
|
||||
|
||||
- [ ] 不收集真实身份;注册仅邮箱 / 设备 ID + 卡密
|
||||
- [ ] 节点 **no-log**(不留连接日志)
|
||||
- [ ] DNS 走 DoH/DoQ,防污染与泄露
|
||||
- [ ] 客户端默认 Kill-switch + 防 DNS / WebRTC 泄露
|
||||
|
||||
## D. 抗封锁(数据面,需求 6)
|
||||
|
||||
- [ ] REALITY 为主(无 TLS 指纹),IP 用冷门小厂、定期轮换
|
||||
- [ ] CDN/WS 中转保底(REALITY IP 被封自动切)
|
||||
- [ ] Hysteria2 端口跳跃抗 UDP QoS
|
||||
- [ ] 订阅域名、控制面 API 也套 CDN/REALITY
|
||||
- [ ] IP 被封自动下线 + 补新(阶段3 自动化)
|
||||
|
||||
## E. 收款隔离(需求 + 交易)
|
||||
|
||||
- [ ] 主推 USDT(TRC20)+ 自动发卡
|
||||
- [ ] 收款通道与运营主体隔离,可随时更换
|
||||
- [ ] **禁用**绑定真实身份的个人支付宝/微信收款
|
||||
|
||||
---
|
||||
|
||||
## 红线清单(任何阶段都不得触碰)
|
||||
- ❌ 用国内真实身份注册任何环节
|
||||
- ❌ 管理后台裸奔公网
|
||||
- ❌ 节点留连接日志
|
||||
- ❌ 收款绑定个人实名账户
|
||||
- ❌ 服务器/域名/支付之间产生可被关联的身份线索
|
||||
Reference in New Issue
Block a user