# 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/ 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 后继续。