a6d42ae602
Co-Authored-By: Claude <noreply@anthropic.com>
189 lines
11 KiB
Markdown
189 lines
11 KiB
Markdown
# setup_caddy_xray_hysteria.sh 实施计划(精简版)
|
||
|
||
> 设计文档:`docs/superpowers/specs/2026-08-23-caddy-xray-hysteria-design.md`
|
||
> 模板原文以仓库根部的 `Caddyfile` / `config.json` / `config.yaml` / `hysteria.nft` /
|
||
> `nftables.conf` 为准,实现时直接读取转成 heredoc,本计划不再逐字复制。
|
||
|
||
**Goal:** 单一自包含 bash 脚本,一键部署 Caddy + Xray(REALITY/WS/XHTTP)+ Hysteria2 +
|
||
nftables 端口跳跃,含交互参数收集、凭据自动生成/持久化、配置校验、自检、分享链接输出与卸载。
|
||
|
||
**Architecture:** 分阶段函数 `preflight → collect_params → system_prepare → install_caddy →
|
||
install_xray → generate_xray_secrets → install_hysteria → render_all_configs → setup_nftables →
|
||
validate_configs → save_env → enable_services → self_check → print_summary`;模板 quoted heredoc +
|
||
`__VAR__` 占位符,bash 参数展开替换(非 sed);`DRY_RUN=1` 渲染全部文件到 `DRY_RUN_DIR`、
|
||
跳过一切系统变更,是 dev 机可测试的核心机制。
|
||
|
||
## Global Constraints
|
||
|
||
- 脚本注释用**中文**;禁止 `sudo`(直接要求 root);`apt-get` + `DEBIAN_FRONTEND=noninteractive`
|
||
- 占位符严格 `__VARNAME__` 与变量同名;替换用 bash 参数展开;随机值限 hex 字符集
|
||
- 每任务完成必须过:`bash -n`、`shellcheck`、`tests/run_tests.sh` → commit
|
||
- 供应链:允许 cloudsmith apt 源、Xray/hy2 官方安装脚本;头部注释说明与
|
||
setup_warp_zerotrust.sh 的约束差异
|
||
- `/etc/nftables.conf` 只**幂等追加** include 行(先 grep 再 append);其余四个配置整体覆盖
|
||
- xray 模板第 15 行 `""uuid-uuid` 多引号笔误在 heredoc 中修正;xray heredoc 内**不写
|
||
`//` 注释**,产出必须是合法 JSON(`python3 -m json.tool` 可验证)
|
||
- Caddyfile 伪装反代 `@notpaths` 排除列表必须包含 XHTTP 路径
|
||
|
||
## 文件结构
|
||
|
||
- **Create** `setup_caddy_xray_hysteria.sh` — 主脚本(唯一交付物)
|
||
- **Create** `tests/run_tests.sh` — DRY_RUN 集成测试
|
||
- **Modify** `README.md` / `CLAUDE.md`
|
||
- **Move** 5 个手写模板原件 → `docs/templates-original/` 存档
|
||
|
||
## 全局接口约定(各任务共享,不得改名)
|
||
|
||
```bash
|
||
info / warn / die
|
||
gen_hex_bytes N # → 2N 位小写 hex
|
||
prompt_var VAR_NAME "提示语" # 仅交互模式;已有值作默认值
|
||
render # stdin 模板 → stdout,按 RENDER_VARS 替换 __X__
|
||
write_file PATH MODE CONTENT # DRY_RUN 时写到 $DRY_RUN_DIR/<basename>
|
||
|
||
RENDER_VARS="DOMAIN BASE_DOMAIN EMAIL CF_API_TOKEN CDN_DOMAIN
|
||
XRAY_UUID XRAY_WS_UUID XRAY_XHTTP_UUID XRAY_PRIVATE_KEY XRAY_PUBLIC_KEY XRAY_SHORT_ID
|
||
XHTTP_PATH XHTTP_PORT XPADDING_HEADER XPADDING_KEY
|
||
HY2_PASSWORD HY2_MASQUERADE_URL"
|
||
|
||
# 环境变量:ACTION(install/uninstall) DRY_RUN DRY_RUN_DIR(默认 ./dry-run-output)
|
||
# SKIP_CADDY SKIP_XRAY SKIP_HYSTERIA SKIP_NFTABLES DIST_UPGRADE PURGE KEEP_ENV
|
||
# ENV_FILE=/etc/caddy-xray-hy2/setup.env NFTABLES_CONF=/etc/nftables.conf
|
||
# INTERACTIVE BASE_DOMAIN XRAY_PUBLIC_KEY(全局,跨函数共享)
|
||
|
||
# 阶段函数(Task 1 为 no-op 桩,后续逐个替换):
|
||
preflight collect_params system_prepare install_caddy install_xray
|
||
generate_xray_secrets install_hysteria render_all_configs setup_nftables
|
||
validate_configs save_env enable_services self_check print_summary uninstall main
|
||
```
|
||
|
||
## Task 1:脚本骨架与工具函数
|
||
|
||
**Files:** Create `setup_caddy_xray_hysteria.sh`
|
||
|
||
- 头部中文注释:用途、架构(Caddy 127.0.0.1:8003 PROXY protocol 收 REALITY 回落;
|
||
Xray 443 REALITY + 54442 WS + 8080 XHTTP;hy2 8443/UDP + CF DNS-01 泛域名证书;
|
||
nftables UDP 20000-30000→8443)、用法/环境变量、供应链说明
|
||
- 上述全部工具函数、全局变量、阶段函数桩、main 分发(ACTION=uninstall → uninstall)
|
||
- `preflight`:root 检查(DRY_RUN 跳过)、apt 系发行版检查
|
||
- **测试**:`bash -n`、`shellcheck`、`DRY_RUN=1` 冒烟(桩不报错、无 tty 时跳过交互)
|
||
- **Commit**: `feat: add setup_caddy_xray_hysteria.sh skeleton`
|
||
|
||
## Task 2:collect_params + system_prepare + save_env + 测试脚手架
|
||
|
||
**Files:** Modify 主脚本;Create `tests/run_tests.sh`
|
||
|
||
- `collect_params`:`[ -f "$ENV_FILE" ] && source` 作默认值;`prompt_var` 仅当变量为空且有
|
||
/dev/tty 时交互;`DOMAIN` 正则 `^([A-Za-z0-9-]+\.)+[A-Za-z]{2,}$`,无 tty 且无值 die;
|
||
`BASE_DOMAIN="${DOMAIN#*.}"`;默认 `EMAIL="admin@$BASE_DOMAIN"`;
|
||
UUID×3 用 `/proc/sys/kernel/random/uuid`;`XRAY_SHORT_ID=$(gen_hex_bytes 4)`;
|
||
`XHTTP_PATH="/$(gen_hex_bytes 4)"`;`XHTTP_PORT=8080`;
|
||
`XPADDING_HEADER="X-$(gen_hex_bytes 2)"`;`XPADDING_KEY="_$(gen_hex_bytes 2)"`;
|
||
`HY2_PASSWORD=$(openssl rand -hex 16)`;`HY2_MASQUERADE_URL` 默认
|
||
`https://www.people.com`;`CDN_DOMAIN` 可选默认空(空则不渲染 CDN 站点块);
|
||
`CF_API_TOKEN` 在未设 SKIP_HYSTERIA 时必填
|
||
- `system_prepare`:`apt-get update -qq`;`DIST_UPGRADE=1` → `apt-get dist-upgrade -y`
|
||
- `save_env`:umask 077;`mkdir -p /etc/caddy-xray-hy2`;printf 全部变量写 ENV_FILE mode 600
|
||
- `tests/run_tests.sh`:注入固定测试值(DOMAIN=test.example.com 等)→ DRY_RUN 跑 →
|
||
断言 `$DRY_RUN_DIR/setup.env` 存在且含 DOMAIN、BASE_DOMAIN=example.com
|
||
- **Commit**: `feat: parameter collection, env persistence, test scaffold`
|
||
|
||
## Task 3:install_caddy + render_caddyfile
|
||
|
||
**Files:** Modify 主脚本 + tests
|
||
|
||
- `install_caddy`(SKIP_CADDY/DRY_RUN 跳过):cloudsmith gpg key
|
||
`curl ... | gpg --batch --yes --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg`;
|
||
写 `/etc/apt/sources.list.d/caddy-stable.list`;`apt-get update -qq && apt-get install -y caddy`
|
||
- `render_caddyfile`:heredoc 内嵌仓库 `Caddyfile`,`xxx.yyy.zzz`→`__DOMAIN__`、
|
||
email→`__EMAIL__`;新增 `@xhttppaths path __XHTTP_PATH__ __XHTTP_PATH__/*` 且
|
||
**`@notpaths` 必须同时排除 xhttp 路径**,`reverse_proxy @xhttppaths 127.0.0.1:__XHTTP_PORT__`;
|
||
`CDN_DOMAIN` 非空时追加第二站点块(仅 xhttp + /scilad + 伪装反代)
|
||
- **断言**:渲染含测试 domain/email、`@xhttppaths path /xh88ab`、`@notpaths` 行含
|
||
`/xh88ab`、`reverse_proxy @xhttppaths 127.0.0.1:8080`;CDN_DOMAIN=cdn.example.com 时含两站点块
|
||
- **Commit**: `feat: caddy install + Caddyfile render`
|
||
|
||
## Task 4:install_xray + generate_xray_secrets + render_xray_config
|
||
|
||
**Files:** Modify 主脚本 + tests
|
||
|
||
- `install_xray`(SKIP_XRAY/DRY_RUN 跳过):官方脚本
|
||
`bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install`
|
||
- `generate_xray_secrets`:UUID 空则 `xray uuid`(回退 /proc uuid)补齐;
|
||
`XRAY_PRIVATE_KEY` 空则 `xray x25519` 生成,否则 `xray x25519 -i $KEY` 推公钥;
|
||
解析私钥 `grep -i 'private'`、公钥 `grep -iE 'public|password'`,失败 die;
|
||
DRY_RUN 回退 `XRAY_PUBLIC_KEY=DRYRUN_PUBLIC_KEY`
|
||
- `render_xray_config`:heredoc 内嵌仓库 `config.json`(修正第 15 行多引号;不写 `//` 注释):
|
||
443 REALITY(dest "8003"、xver 1、serverNames `__DOMAIN__`、privateKey/shortIds/uuid 替换);
|
||
54442 WS(127.0.0.1,/scilad);8080 XHTTP(127.0.0.1,path `__XHTTP_PATH__`,mode auto,
|
||
`extra` 块:xPaddingObfsMode/tokenish/queryInHeader/`__XPADDING_HEADER__`/`__XPADDING_KEY__`);
|
||
outbounds/dns/routing 保留模板原样(geoip:cn、私有网段、tg-out、域名阻断、bittorrent)
|
||
- **断言**:`python3 -m json.tool` 通过;含 3 个测试 UUID、privateKey、shortId `3f9a2b1c`、
|
||
serverNames、`"network": "xhttp"`、`"port": 8080`、`"xPaddingObfsMode": true`、
|
||
`"xPaddingHeader": "X-testpad"`、`"path": "/xh88ab"`
|
||
- **Commit**: `feat: xray install, keypair generation, config render`
|
||
|
||
## Task 5:install_hysteria + render_hysteria_config
|
||
|
||
**Files:** Modify 主脚本 + tests
|
||
|
||
- `install_hysteria`(SKIP_HYSTERIA/DRY_RUN 跳过):`bash <(curl -fsSL https://get.hy2.sh/)`
|
||
- `render_hysteria_config`:heredoc 内嵌仓库 `config.yaml`:`listen: :8443`;acme dns
|
||
cloudflare,domains `["*.__BASE_DOMAIN__"]`、email `__EMAIL__`、
|
||
`cloudflare_api_token: __CF_API_TOKEN__`、`dir: /etc/hysteria/acme_certs`;
|
||
auth password `__HY2_PASSWORD__`;masquerade proxy url `__HY2_MASQUERADE_URL__`
|
||
rewriteHost true
|
||
- 非 DRY_RUN:`chown -R hysteria:hysteria /etc/hysteria/`
|
||
- **断言**:渲染含 `:8443`、`*.example.com`、测试 token、密码、masquerade url
|
||
- **Commit**: `feat: hysteria2 install + config render`
|
||
|
||
## Task 6:setup_nftables + validate_configs + enable_services
|
||
|
||
**Files:** Modify 主脚本 + tests
|
||
|
||
- `setup_nftables`(SKIP_NFTABLES 跳过):写 `/etc/nftables/hysteria.nft`
|
||
(仓库 `hysteria.nft` 原样:`table inet hysteria_nat`,udp dport 20000-30000 redirect
|
||
to :8443);`$NFTABLES_CONF` grep 无 include 行才追加(幂等);
|
||
非 DRY_RUN:`systemctl enable --now nftables`
|
||
- `validate_configs`(DRY_RUN 跳过):`caddy validate --config /etc/caddy/Caddyfile`、
|
||
`xray run -test -config /usr/local/etc/xray/config.json`;hy2 无离线校验,靠启动后
|
||
`systemctl is-active`
|
||
- `enable_services`(DRY_RUN 跳过):按 SKIP_* `systemctl enable --now`/`restart`
|
||
caddy xray hysteria-server → `is-active` 检查,失败 die
|
||
- **断言**:DRY_RUN 目录 `hysteria.nft` 含 `20000-30000`、`:8443`;渲染的 nftables.conf
|
||
含 include 行;include 追加逻辑跑两次不重复
|
||
- **Commit**: `feat: nftables port hopping, validation, service enablement`
|
||
|
||
## Task 7:self_check + print_summary + uninstall
|
||
|
||
**Files:** Modify 主脚本 + tests
|
||
|
||
- `self_check`(DRY_RUN 跳过,失败仅 warn):`curl -skI "https://$DOMAIN"`、
|
||
`ss -lun | grep :8443`、`nft list table inet hysteria_nat`
|
||
- `print_summary`:参数表 + 分享链接:
|
||
- REALITY:`vless://$XRAY_UUID@$DOMAIN:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=$DOMAIN&fp=chrome&pbk=$XRAY_PUBLIC_KEY&sid=$XRAY_SHORT_ID&type=tcp#...`
|
||
- WS:`vless://$XRAY_WS_UUID@$DOMAIN:443?...&type=ws&path=%2Fscilad#...`
|
||
- XHTTP:`vless://$XRAY_XHTTP_UUID@$DOMAIN:443?...&type=xhttp&path=$XHTTP_PATH&mode=auto#...`
|
||
- CDN 变体(CDN_DOMAIN 非空):host/sni 换 CDN_DOMAIN
|
||
- Hysteria2:`hysteria2://$HY2_PASSWORD@$DOMAIN:8443/?mport=20000-30000&sni=www.$BASE_DOMAIN#...`
|
||
- `uninstall`:`systemctl disable --now` 三服务(容忍不存在);删 Caddyfile/config.json/
|
||
config.yaml;sed 删 include 行 + 删 hysteria.nft + `nft delete table inet hysteria_nat`;
|
||
`PURGE=1`:apt purge caddy xray、hy2 官方卸载、删 cloudsmith 源/keyring;
|
||
默认保留 ENV_FILE,PURGE=1 且未设 KEEP_ENV 时删除
|
||
- **断言**:DRY_RUN 摘要含 5 条链接与端口/UUID;`ACTION=uninstall DRY_RUN=1` 不报错
|
||
- **Commit**: `feat: self-check, client summary, uninstall`
|
||
|
||
## Task 8:README + CLAUDE.md + 模板归档
|
||
|
||
**Files:** Modify README.md、CLAUDE.md;Move 5 模板 → `docs/templates-original/`
|
||
|
||
- README.md 追加中文小节:一键命令、必填/可选环境变量表、DRY_RUN、卸载、架构简述
|
||
- CLAUDE.md "What this repo is" 提及第二个脚本
|
||
- `git mv` 5 个模板并加存档 README("原始手工模板,已内嵌进脚本 heredoc")
|
||
- **测试**:最终 `bash -n` + `shellcheck` + `tests/run_tests.sh` 全绿
|
||
- **Commit**: `docs: usage docs, archive original templates`
|
||
|
||
## 执行方式
|
||
|
||
内联逐 Task 执行(executing-plans),每 Task 完成跑测试并 commit 后继续。
|