{"id":49721746,"url":"https://github.com/superchaospc/xray-relay","last_synced_at":"2026-06-27T06:05:31.448Z","repository":{"id":351428652,"uuid":"1210960339","full_name":"superchaospc/xray-relay","owner":"superchaospc","description":"🚀 Xray VLESS+REALITY 一键部署脚本，支持 VPS 直连和住宅 SOCKS5 中转双模式 | One-click Xray VLESS+REALITY deployment with multi-node SOCKS5 relay, traffic stats, BBR, rollback, monitoring alerts and QR code import","archived":false,"fork":false,"pushed_at":"2026-06-22T02:48:00.000Z","size":856,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T04:23:26.171Z","etag":null,"topics":["bbr","gfw","multi-node","one-click-install","proxy","reality","relay","residential-proxy","shadowrocket","shell-script","sing-box","socks5","v2ray","v2rayn","v2rayng","vless","vps","xray","xray-core","xtls-rprx-vision"],"latest_commit_sha":null,"homepage":"https://github.com/superchaospc/xray-relay","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/superchaospc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-14T23:53:04.000Z","updated_at":"2026-06-22T02:47:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/superchaospc/xray-relay","commit_stats":null,"previous_names":["superchaospc/xray-relay"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/superchaospc/xray-relay","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superchaospc%2Fxray-relay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superchaospc%2Fxray-relay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superchaospc%2Fxray-relay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superchaospc%2Fxray-relay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/superchaospc","download_url":"https://codeload.github.com/superchaospc/xray-relay/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superchaospc%2Fxray-relay/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34843153,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bbr","gfw","multi-node","one-click-install","proxy","reality","relay","residential-proxy","shadowrocket","shell-script","sing-box","socks5","v2ray","v2rayn","v2rayng","vless","vps","xray","xray-core","xtls-rprx-vision"],"created_at":"2026-05-09T02:26:53.499Z","updated_at":"2026-06-27T06:05:31.439Z","avatar_url":"https://github.com/superchaospc.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🚀 xray-relay - Xray VLESS+REALITY 一键部署中转脚本\n\n\u003e One-click Xray VLESS+REALITY deployment with residential SOCKS5 multi-hop relay support\n\n![GitHub repo size](https://img.shields.io/github/repo-size/superchaospc/xray-relay?style=flat-square)\n![GitHub last commit](https://img.shields.io/github/last-commit/superchaospc/xray-relay?style=flat-square)\n![GitHub License](https://img.shields.io/github/license/superchaospc/xray-relay?style=flat-square)\n![Shell Script](https://img.shields.io/badge/Shell-Bash-4EAA25?style=flat-square\u0026logo=gnu-bash\u0026logoColor=white)\n![Platform](https://img.shields.io/badge/Platform-Linux-FCC624?style=flat-square\u0026logo=linux\u0026logoColor=black)\n![Xray](https://img.shields.io/badge/Core-Xray-2F6FED?style=flat-square)\n\nVPS 上一键部署 **Xray VLESS + REALITY** 的 Bash 脚本。既支持 **VPS 直连线路**，也支持 **VPS 入口 → 住宅 SOCKS5 出口** 的中转线路；支持单条添加、批量生成住宅 SOCKS5 中转节点、批量生成 VPS 直连节点、固定端口→节点映射、配置自动校验回滚、流量统计、监控报警，以及生成的 VLESS 链接自动渲染终端二维码，方便 Shadowrocket / V2rayN / V2rayNG / Neobox 直接扫码导入。\n\n\u003e ⚠️ **免责声明**：本项目仅供学习研究网络协议与系统运维使用。请用户遵守所在国家/地区的法律法规，自行承担使用后果。作者不对使用本脚本造成的任何直接或间接损失负责。\n\n---\n\n## ✨ 功能特性\n\n- 🔐 **VLESS + REALITY + XTLS-Vision** 满血配置，默认伪装目标为 `www.cloudflare.com`，可用环境变量覆盖\n- 🌉 **中转架构**：VPS 入口 → 前置 SOCKS5（住宅 IP）出口，也支持纯 VPS 直连模式\n- 🎯 **固定端口映射**：每个前置节点绑定独立监听端口，客户端可精确选择出口，不做负载均衡\n- 🧩 **多节点管理**：菜单化添加、删除节点，修改端口和节点名称\n- 🏘️ **批量住宅节点**：一次最多导入 20 个住宅 SOCKS5 节点，自动生成端口、线路名称、链接和二维码\n- 🚀 **批量直连节点**：一次最多生成 30 个 VPS 直连节点，自动命名为 `VPS-Direct-1` 起并刷新订阅\n- 🛟 **安全写配置**：生成临时 JSON → `xray run -test` 校验 → 备份旧配置 → 原子替换 → 启动失败自动回滚\n- 🧱 **自动防火墙放行**：依次尝试 `ufw` / `firewalld` / `nftables` / `iptables`，nftables 会识别真实 input 链，尽量持久化规则，并对云厂商安全组给出提醒\n- 🛡️ **REALITY 回落滥用防护**（默认开）：用独立 nftables 表对所有对外 REALITY 端口做「每源 IP 并发上限 + 新连接速率限制 + IP 黑名单」，封顶未认证连接刷爆 dest 回落带宽（回落流量不计入 xray 统计，曾导致单机 2 天被刷 700G）；菜单 `17` 可随时刷新规则、封禁/解封 IP、查看 Top 来源 IP\n- 🔒 **供应链保护**：默认固定 Xray 官方安装脚本 commit 并校验 sha256，也支持显式切回 `main`\n- ⚡ **BBR 加速**：自动开启 BBR 拥塞控制并写入内核调优参数\n- 📊 **流量统计**：基于 Xray API 的累计上行/下行流量查看\n- 🩺 **排错诊断**：一键检查服务、配置、端口、防火墙、前置连通性、BBR、系统资源和错误日志\n- 🚨 **监控报警**：可选配置邮件告警（Gmail/QQ/163 等 SMTP），每分钟巡检，异常自动发信\n- 📱 **终端二维码**：节点生成后直接在终端渲染 VLESS 二维码，主流客户端扫码即导入\n- 🐧 **多发行版支持**：Debian / Ubuntu / CentOS / AlmaLinux / Rocky / Fedora\n\n---\n\n## 🆕 v2.2.23 协议混用提示\n\n本脚本是 **Vision (tcp + xtls-rprx-vision)** 版。如果同一台机器先后被本脚本和 [XHTTP 版脚本](https://github.com/superchaospc/xray-xhttp-relay) 都操作过，配置里就会混入 `network: xhttp` 的线路——而本脚本的链接/订阅生成只会按 Vision 格式输出 `type=tcp`，导致那些 xhttp 线路的分享链接错误、客户端连不上。\n\n这个版本在启动预检里新增 `check_protocol_mismatch`：进菜单前扫描 `config.json`，发现 xhttp 线路就打印红字警告并点名端口/备注，提示改用 XHTTP 版脚本管理它们或删除。**仅警告，不读 stdin、不阻断**，非交互喂菜单号的用法完全不受影响；配置缺失或解析失败时静默跳过。\n\n\u003e 反向的对称提示（XHTTP 版检测到 Vision 线路时警告）见 xray-xhttp-relay v1.0.5。\n\n---\n\n## 🆕 v2.2.22 REALITY 回落滥用防护\n\n### 背景：回落（fallback）会烧掉「看不见」的流量\n\nREALITY 的 `dest`（默认 `www.cloudflare.com:443`）是一个真实外网站点，用于防主动探测——**任何未通过 REALITY 认证的连接都会被透明转发到这个外网 dest**。正常情况下这只是零星探测，但一旦端口被扫描盯上、或被人当成「到该外网站点的中继」反复拉数据，这些**回落流量不计入 Xray 的入站统计、也不留代理日志**，却实打实消耗 VPS 计费带宽。实测曾出现单机 **2 天被刷掉 ~700GB**、而 Xray 账面只有几 GB 的情况。\n\n### 这个版本做了什么\n\n默认开启一套基于 nftables 的 **回落限速 guard**（独立表 `inet xray_guard`，不干扰放行规则）：\n\n- 对所有**对外** REALITY 业务端口（自动从配置读取，排除 `api-in` 与仅监听 `127.0.0.1` 的内部 inbound）施加：\n  - **每源 IP 并发连接上限**（默认 600，防 fd 耗尽 / 连接洪流）\n  - **每源 IP 新连接速率限制**（默认 50/s，突发 100）\n  - **IP 黑名单**（v4/v6）即时丢弃\n- 阈值刻意放宽，不影响正常重度用户；规则文件自带 `add/delete table` 前缀，可重复加载、幂等\n- 持久化到 `/etc/nftables-xray-guard.nft` 并 `include` 进 `nftables.conf`，重启自动生效\n- **安装、添加节点（单/批量）、修改端口后自动刷新**；卸载时清理\n- 仅在系统有 `nft` 时生效，否则优雅跳过并提示「本地落地根治」\n\n新增菜单 **`17) 回落限速/封禁防护`**：重新应用规则、封禁/解封 IP、查看当前连接数最多的来源 IP。\n\n### 环境变量\n\n| 变量 | 默认 | 说明 |\n|---|---|---|\n| `XRAY_REALITY_GUARD` | `1` | `1` 启用 / `0` 关闭 |\n| `XRAY_GUARD_CONN_MAX` | `600` | 每源 IP 并发连接上限 |\n| `XRAY_GUARD_RATE` | `50` | 每源 IP 新连接速率（个/秒） |\n| `XRAY_GUARD_BURST` | `100` | 速率突发额度（包） |\n| `XRAY_GUARD_BLOCK_IPS` | 空 | 逗号分隔的额外封禁 IP（v4/v6） |\n| `XRAY_GUARD_BLOCKLIST_FILE` | `/root/.xray_guard_blocklist` | 黑名单文件（每行一个 IP） |\n| `XRAY_GUARD_NFT_FILE` | `/etc/nftables-xray-guard.nft` | 持久化规则文件 |\n\n### 限速 vs 根治\n\n限速 guard 能**封顶**滥用，但回落本身仍会被转发到外网 dest。若你的 VPS 流量计费很敏感，推荐**根治**——把 REALITY 的 `dest` 指向本机自签 TLS 落地，回落从此留在本地、零外网带宽：\n\n```bash\n# 1) 本机起一个仅监听 127.0.0.1 的轻量 TLS 落地（以 nginx 为例）\napt-get update \u0026\u0026 apt-get install -y nginx-light\nopenssl req -x509 -newkey rsa:2048 -nodes -days 3650 \\\n  -keyout /etc/nginx/reality-dummy.key -out /etc/nginx/reality-dummy.crt \\\n  -subj \"/CN=www.cloudflare.com\"\nrm -f /etc/nginx/sites-enabled/default\ncat \u003e /etc/nginx/conf.d/reality-dest.conf \u003c\u003c'EOF'\nserver {\n    listen 127.0.0.1:9443 ssl http2;     # nginx ≥1.25.1 改用单独的 http2 on;\n    server_name www.cloudflare.com;\n    ssl_certificate     /etc/nginx/reality-dummy.crt;\n    ssl_certificate_key /etc/nginx/reality-dummy.key;\n    ssl_protocols TLSv1.2 TLSv1.3;\n    location / { return 200 \"ok\"; }\n}\nEOF\nsystemctl restart nginx \u0026\u0026 systemctl enable nginx\n\n# 2) 部署时让 dest 指向本机（serverNames 保持不变，已发出去的客户端链接无需改）\nREALITY_DEST=127.0.0.1:9443 bash xray_deploy.sh\n```\n\n\u003e 代价：主动探测者会看到自签证书（而非真 CF 证书），隐蔽性略降；但相比流量被刷爆 / VPS 被限速封停，通常很划算。XHTTP 变体 `xray-xhttp-relay` 已把这套本机落地做成 `REALITY_DEST_LOCAL=1` 开关。\n\n---\n\n## 🆕 v2.2.21 关键改动\n\n- 排错诊断 `[8/8] 最近错误日志` 不再把目标域名含 `error`/`fail` 字样的访问日志**成功行**（如 `accepted tcp:errortracking.deepl.com:443`）误判为错误：新增 `xray_filter_recent_errors`，先剔除 `accepted tcp/udp:` 成功行再匹配真实错误标志（`[error]`/`failed`/`rejected`/`refused`/`no route to host`/`deadline exceeded`/`i/o timeout`/`panic`）\n- 诊断时间窗口从写死的「1 小时」改为本次 Xray 服务启动时刻（新增 `xray_journal_since`），不再把上次运行 / 安装期的历史日志算进来\n- 新增 `test_diagnostic_error_filter.sh` 与 `test_diagnostic_journal_window.sh` 覆盖上述两点\n\n---\n\n## 🆕 v2.2.20 关键改动\n\n- 修复中文/超长节点名导致的流量统计表格列错位：填充改为按终端显示宽度（东亚全角字符算 2 列）计算，而非按 Unicode 码点数\n- 增强 `test_traffic_show.sh`：加入中文备注与超长名用例，并断言每个表格行按显示宽度与分隔线等宽\n\n---\n\n## 🆕 v2.2.19 关键改动\n\n- 菜单 `6) 流量统计` 新增“节点名称”列，会直接显示每个端口对应的节点 `_remark`，多端口环境下更容易对照查看\n- 实时统计和历史统计都拆分为“节点名称 / 入口出口 / 上行 / 下行 / 合计”表格；没有备注时回退为 `VPS-Direct` 或 `Port-端口`\n- 历史统计继续按 `(tag, port)` 聚合，旧端口或已删除节点仍标记为 `(已删除)`，避免改端口后的历史流量混淆\n- 增强 `test_traffic_show.sh`，覆盖流量统计中节点名称展示的回归场景\n\n---\n\n## 🆕 v2.2.18 关键改动\n\n- 卸载时同步清理 `/root/.xray_traffic_record.lock`，避免流量统计锁文件在完全卸载后残留\n- 根据真实 Debian 13 全链路验证反馈补齐清理项；不影响已有配置、订阅或节点管理逻辑\n\n---\n\n## 🆕 v2.2.17 关键改动\n\n- 新增 `16) 批量删除节点`：可一次选择多个住宅 SOCKS5 或 VPS 直连节点删除，支持 `1,3,5-7` 这类编号输入\n- 批量删除继续走「写临时文件 → `xray run -test` 校验 → 原子替换 → 重启失败回滚」流程，并在成功后逐个回收被删节点端口的防火墙规则\n- 删除后自动刷新 `/root/xray_nodes_info.txt` 与 `/root/xray_subscription.txt`\n- 新增 `test_batch_delete_nodes.sh`，覆盖批量选择解析、共享 outbound 保留、未引用 outbound 删除和菜单入口\n\n---\n\n## 🆕 v2.2.16 关键改动\n\n- 修复菜单 `6) 流量统计` 手动触发记录与 5 分钟 cron 同时运行时的竞态：记录脚本新增 `flock` 非阻塞锁，避免两个进程同时 append / truncate / rewrite `/root/.xray_traffic_db` 导致历史行丢失\n- 流量记录 delta 基线同步改为按 `(tag, port)` 记录，和 v2.2.15 的历史展示聚合口径保持一致，避免同 tag 改端口后的历史行影响当前端口 delta\n- 注意：节点改端口后，新 `(tag, port)` 的首个 5 分钟记录周期会先建立基线，期间流量不计入历史；这是为了优先保证旧端口历史不会污染新端口\n- 增强 `test_traffic_record.sh`，覆盖同 tag 不同端口历史行不会干扰当前端口增量计算\n\n## 🆕 v2.2.15 关键改动\n\n- 修复菜单 `6) 流量统计` 历史区段（过去 1 小时 / 今天 / 过去 7 天 / 过去 30 天）的聚合错误：原来按 `tag` 单字段累加，若曾经用菜单 4 改过端口，旧端口和新端口共享同一个 `vless-in-N` tag，会显示两行一模一样的数字，并且旧端口被错误地标上「当前出口 IP」\n- 改为按 `(tag, port)` 双字段聚合；不在当前 `inbounds` 里的 `(tag, port)` 标记为「(已删除)」，保留历史可追溯\n- 新增 `test_traffic_show.sh` 覆盖改端口后的历史聚合场景\n\n---\n\n## 🆕 v2.2.14 关键改动\n\n- 修复菜单 `7) 排错诊断` 第 `[8/8]` 步：journal 里发现 `error/fail/refused` 时未累加 `ERRORS`，导致总结行可能在屏幕已显示「发现错误」的情况下仍打印 `✓ 所有检查通过`\n- 同步菜单顶部横幅版本号到 v2.2.14（v2.2.13 release 包内仍显示 v2.2.12 的小瑕疵）\n\n---\n\n## 🆕 v2.2.13 关键改动\n\n- 新增 `15) 修改节点名称`：菜单 1-14 编号保持不变，可选择任意住宅 SOCKS5 或 VPS 直连节点并更新 `_remark`、`/root/xray_nodes_info.txt` 与 `/root/xray_subscription.txt`，无需重启 Xray\n- 改名走「写临时文件 → `xray run -test` 校验 → 原子替换」流程，编号非法或参数错误会自动放弃改动并保留原配置\n- 节点列表统一显示业务节点（住宅 SOCKS5 与 VPS 直连），便于在多节点环境下精确选择\n- 新增 `test_rename_node.sh`，覆盖住宅 / 直连节点 `_remark` 改名以及旧 `INFO_FILE` 名称的覆盖刷新\n\n---\n\n## 🆕 v2.2.12 关键改动\n\n- 修复 `prompt_read` 在 v2.2.11 中保留首尾空白的回归，菜单编号、数字输入和 `y/n` 确认会重新按原行为自动修剪空白\n- 卸载时同步清理 `/root/.xray_public_key`，避免 public key 缓存残留\n- 为批量防火墙延迟持久化状态补充全局变量注释和显式声明，降低后续维护误改风险\n- 新增 `test_prompt_read_trim.sh`，覆盖带首尾空白的交互输入\n\n---\n\n## 🆕 v2.2.11 关键改动\n\n- 统一单条 VPS 直连和批量 VPS 直连的端口占用检查，都会同时避开系统占用端口和现有配置端口\n- 批量 VPS 直连添加端口时，nftables / iptables 规则改为批量结束后统一持久化，减少重复落盘\n- Reality public key 会缓存到 `/root/.xray_public_key`，后续刷新订阅/添加节点优先读取缓存，减少重复派生\n- 清理 shellcheck 质量问题：`prompt_read` 固定 `read -r`、移除未使用变量、备份清理不再使用 `ls | tail`\n- 统一更多 Python 片段通过 `CONFIG_FILE` 环境变量读取配置，便于测试和自定义路径\n\n---\n\n## 🆕 v2.2.10 关键改动\n\n- 新增批量添加 VPS 直连节点：输入数量后自动创建 `VPS-Direct-1` 起的直连线路，最多一次 30 个\n- 批量直连成功后会逐条输出 VLESS 链接和终端二维码，并自动刷新 `/root/xray_subscription.txt`\n- 批量直连操作会直接打印订阅 Data URL，方便客户端一次性导入\n- 新增 `test_batch_direct_nodes.sh`，覆盖批量直连配置写入、direct 路由和菜单入口\n\n---\n\n## 🆕 v2.2.9 关键改动\n\n- 修复 nftables 回收旧端口时 handle 提取接口不匹配的问题，改端口/删节点会正确删除旧端口规则\n- nftables 新增规则会写入 `xray-relay-managed` comment，回收时优先只删除脚本管理的规则\n- 兼容清理 v2.2.8 及更早版本创建的 legacy 精确端口规则；若同端口存在 managed 规则，则不会碰 legacy 规则\n- 卸载时会从当前配置读取端口，并尝试回收带 managed comment 的脚本管理防火墙规则\n- 新增 `test_nft_firewall_revoke.sh`，覆盖 managed/legacy handle 删除、同端口防误删和端口集合防误删\n\n---\n\n## 🆕 v2.2.8 关键改动\n\n- SMTP 密码/授权码明文保存提醒前移到密码输入之前，用户可在输入敏感信息前决定是否继续\n- `config.json` 权限归一化失败时会明确报错并中止安装/回滚流程，避免脚本误判成功\n- apt/apt-get 依赖安装统一添加 `--no-install-recommends`，减少推荐包体积\n- 新增 SMTP 明文提醒顺序回归测试\n\n---\n\n## 🆕 v2.2.7 关键改动\n\n- 修复回滚后 `config.json` 从备份恢复为 `600 root:root`，导致非 root Xray 无法读取配置的问题\n- `systemctl restart xray` 直接返回非零时仍会继续进入回滚流程，不再被 `set -e` 提前打断\n- 监控邮件的 `tls_trust_file` 会自动探测 Debian/RHEL/Fedora 常见 CA bundle 路径\n- SMTP 端口会去掉前导零并校验 `1-65535` 范围，`0465` 会按 `465` 正确生成 `tls_starttls off`\n- msmtp 安装失败会立即中止配置流程，并明确提示 SMTP 密码/授权码会明文保存在 `/root/.msmtprc`（权限 `600`）\n- 新增回滚权限恢复和跨发行版 CA bundle 回归测试\n\n---\n\n## 🆕 v2.2.6 关键改动\n\n- `config.json` 改为 `root:\u003cXray 服务用户主组\u003e` + `640`，避免本地非服务用户读取 UUID/REALITY 私钥\n- 监控邮件配置不再直接 `source`，改用受限 `KEY=VALUE` 解析，并收紧邮箱字符集以阻断 shell 注入\n- nftables 默认不再覆盖既有 `/etc/nftables.conf`；如确认需要用当前 ruleset 覆盖，可设置 `XRAY_NFTABLES_OVERWRITE=1`\n- 卸载清理 cron 前会先确认存在 `xray_traffic_record`，避免无匹配项时写入空 crontab\n- `get_ip` 会校验自动获取和缓存内容必须是合法 IP，避免 HTML/错误页进入 VLESS 链接\n- UFW 放行改为显式 `${port}/tcp`\n- Xray 官方安装脚本默认值从 `main` 改为固定 commit + sha256 校验\n- 新增 SMTP 注入、非法公网 IP、卸载 cron 清理等回归测试\n\n---\n\n## 🆕 v2.2.5 关键改动\n\n- 修复删除节点时 `socks5-out-1` 会误匹配 `socks5-out-10` 的问题，避免产生孤儿 outbound\n- nftables 端口规则检测改用 `nft -j -a` JSON 解析，避免 `tcp dport 80-90 accept` 被误判为某个单端口已放行\n- nftables 旧端口回收同样使用精确解析，避免误删端口集合或端口范围规则\n- `update_system` 对临时软件源抖动更宽容，依赖安装失败不会立刻打断脚本；仍会硬校验必需的 `python3`\n- `update_xray` 查询 GitHub 最新版本增加 10 秒超时，并改用 JSON 解析 `tag_name`\n- `generate_config` 生成失败时会清理临时配置文件\n- `get_ip` 在自动获取失败且 stdin EOF 时会返回失败，调用方不再带着空 `VPS_IP` 继续生成链接\n- 新增删除节点 outbound 精确匹配、`get_ip` EOF、nftables 端口范围误判回归测试\n\n---\n\n## 🆕 v2.2.4 关键改动\n\n- 所有面向用户的交互提示在 stdin EOF 时都会优雅取消并退出 0，避免非交互管道触发 `set -e` 退出 1\n- 新增 `test_prompt_read_eof.sh` 覆盖 EOF 取消路径\n- 历史防火墙孤儿规则不在全新安装时自动扫描删除，避免误删用户手工规则；仍可通过修改端口/删除节点路径做针对性回收\n\n---\n\n## 🆕 v2.2.3 关键改动\n\n- 批量添加成功后输出链接时，`format_vless_host` 只执行一次，避免最多 20 次重复启动 `python3`\n- 修改端口时如果新旧端口相同，会提示“无需修改”，不再因为当前监听端口被占用而误报\n- firewalld 回收旧端口前会先查询规则是否存在；不存在时提示无需回收，不再报失败\n- 给 `FORMAT_VLESS_HOST_PY` 的 `exec` 契约补充注释，避免未来误传用户输入\n\n---\n\n## 🆕 v2.2.2 关键改动\n\n- 修改节点端口后会尽量回收旧端口的 `ufw` / `firewalld` / `nftables` / `iptables` 放行规则\n- 删除节点后会尽量回收被删除节点的防火墙端口规则，减少长期运行后的失效规则堆积\n- 订阅文件改为临时文件 + 原子替换写入，避免静态 Web 服务读到截断内容\n- `format_vless_host` 的 IPv6 包裹逻辑统一由同一段 Python helper 提供，避免 Bash / Python 双份实现漂移\n- 空订阅不再打印空 Data URL\n- `test_public_key_and_ports.sh` 使用 `XRAY_BIN` 指向 fake xray，macOS 未安装真实 xray 时也能稳定测试\n\n---\n\n## 🆕 v2.2.1 关键改动\n\n- 修复订阅文件只在批量添加时刷新导致的配置漂移；首次安装、单条添加、直连添加、改端口、删节点、查看状态都会同步刷新 `/root/xray_subscription.txt`\n- 卸载时同步清理 `/root/xray_subscription.txt`\n- 防火墙端口放行调整到 Xray 重启成功后执行，避免回滚时留下新端口规则\n- 批量粘贴时空行只会被忽略，不再提前结束录入；请用 `done` 结束\n- 默认不再打印超长 Data URL；如确需终端输出，可设置 `XRAY_PRINT_SUB_DATA_URL=1`\n- 新增订阅文件生成测试，测试套件覆盖到批量订阅相关代码\n\n---\n\n## 🆕 v2.2.0 关键改动\n\n- 新增 **批量添加住宅 SOCKS5 节点** 菜单，一次最多导入 20 个 `host:port:user:pass` 节点\n- 批量导入时线路名称自动使用 IP/host，无需逐条输入备注\n- 批量添加成功后自动逐条输出 VLESS 链接和终端二维码\n- 自动生成 base64 订阅内容到 `/root/xray_subscription.txt`\n- 首次部署与菜单添加共用同一套 SOCKS5 解析逻辑，减少格式校验分叉\n\n---\n\n## 🆕 v2.1.1 关键改动\n\n- 修复 nftables 只存在 fail2ban 表/链时被误判为「端口未放行」的问题\n- nftables 不再硬编码 `inet filter input`，会自动扫描实际存在的 input base chain\n- 当 nftables input 链默认策略为 `accept` 时，脚本会提示无需额外放行；只有默认 `drop` / `reject` 时才自动插入端口放行规则\n- 新增 nftables 防火墙识别测试，覆盖 fail2ban `f2b-table/f2b-chain` 与默认 drop 链场景\n\n---\n\n## 🆕 v2.1 关键改动\n\n- 配置写入采用「临时文件 → `xray run -test` → 备份 → 原子替换 → 重启失败回滚」流程\n- Xray 官方安装脚本默认跟随 `main`，新 VPS 可直接一键部署；生产环境仍建议显式 pin commit 和 sha256\n- SOCKS5 支持常见 `host:port:user:pass` 与 URL 格式，并拒绝控制字符注入\n- 防火墙规则支持 `ufw` / `firewalld` / `nftables` / `iptables`，nftables 与 iptables 会尝试自动持久化\n- 节点备注写入配置元数据 `_remark`，修改端口或重建 `INFO_FILE` 后仍能保留原名称\n- systemd drop-in 自动提升 Xray 文件描述符上限到 `65535`\n- 默认只安装必要依赖，不做整机 `apt upgrade`；需要时可用 `XRAY_FULL_UPGRADE=1`\n- 敏感文件统一 `600` 权限，终端输出可用 `XRAY_REDACT=1` 隐藏 UUID / 密钥中段\n- `config.json` 写入后强制 `644 root:root`，避免老文件错误权限被新写入继承导致 Xray (nobody) 启动失败\n\n---\n\n## 🧰 系统要求\n\n- 🖥️ Linux x86_64 VPS，root 权限\n- 📦 以下任一包管理器：`apt` / `dnf` / `yum`\n- ⚙️ 内核 ≥ 4.9（支持 BBR，绝大多数现代发行版默认满足）\n- 🌐 出站 443 可访问 GitHub（用于首次下载官方 Xray 安装脚本）\n\n脚本会自动检测并安装依赖：`xray-core`、`python3`、`curl`、`iproute2`、`ca-certificates`、`qrencode`、`msmtp`（仅配置邮件时）。\n\n\u003e 注意：脚本默认只安装必要依赖，不会整机 `apt upgrade`。如果确实想顺带升级系统，可用 `XRAY_FULL_UPGRADE=1` 运行。\n\n### 环境变量\n\n常见用法示例：\n\n```bash\nCLIENT_FP=ios REALITY_SERVER_NAME=www.apple.com REALITY_DEST=www.apple.com:443 /root/xray_deploy.sh\n```\n\n| 变量 | 默认值 | 说明 |\n| --- | --- | --- |\n| `XRAY_INSTALL_REF` | `e741a4f56d368afbb9e5be3361b40c4552d3710d` | `XTLS/Xray-install` 的 ref；默认固定 commit，需要追新可显式设为 `main` |\n| `XRAY_INSTALL_SHA256` | `7f70c95f6b418da8b4f4883343d602964915e28748993870fd554383afdbe555` | `install-release.sh` 的 sha256；设置后会强制校验，追新 `main` 时需显式置空 |\n| `XRAY_FULL_UPGRADE` | `0` | 设为 `1` 时才执行整机升级 |\n| `XRAY_REDACT` | `0` | 设为 `1` 时隐藏终端输出里的 UUID / 密钥中段 |\n| `XRAY_PRINT_SUB_DATA_URL` | `0` | 设为 `1` 时在终端打印订阅 Data URL |\n| `XRAY_NFTABLES_OVERWRITE` | `0` | 设为 `1` 时允许用当前 ruleset 覆盖既有 `NFTABLES_CONF` |\n| `NFTABLES_CONF` | `/etc/nftables.conf` | nftables 持久化配置文件路径，通常无需修改 |\n| `CLIENT_FP` | `chrome` | 客户端指纹；iOS / Shadowrocket 可考虑 `ios` 或 `safari` |\n| `REALITY_SERVER_NAME` | `www.cloudflare.com` | VLESS 链接里的 SNI |\n| `REALITY_DEST` | `${REALITY_SERVER_NAME}:443` | Xray REALITY 回源目标 |\n| `IP_CACHE_TTL` | `3600` | VPS 公网 IP 缓存秒数，EIP 切换后可临时调小 |\n\n---\n\n## ⚡ 快速开始\n\n\u003e 🎉 **最新版本：[v2.2.20](https://github.com/superchaospc/xray-relay/releases/tag/v2.2.20)** — 修复中文/超长节点名导致的流量统计表格列错位（按终端显示宽度对齐）。下面的命令默认拉取 `main` 分支，即包含该修复的最新版。\n\n### 推荐方式：下载后运行\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/superchaospc/xray-relay/main/xray_deploy.sh -o /root/xray_deploy.sh\nchmod +x /root/xray_deploy.sh\n/root/xray_deploy.sh\n```\n\n如需锁定到固定版本（可复现），把 URL 里的 `main` 换成对应 tag，例如 `v2.2.20`：\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/superchaospc/xray-relay/v2.2.20/xray_deploy.sh -o /root/xray_deploy.sh\nchmod +x /root/xray_deploy.sh\n/root/xray_deploy.sh\n```\n\n首次选择 `1) 全新安装` 或 `8) 更新 Xray` 时，脚本默认使用已固定的 Xray 官方安装脚本 commit，并校验 `install-release.sh` 的 sha256，降低上游脚本变化带来的供应链风险。\n\n### 生产安全模式\n\n默认已经采用固定 commit + sha256。需要升级固定版本时，可先查询 `XTLS/Xray-install` 的新 commit，并计算对应 sha256：\n\n```bash\ngit ls-remote https://github.com/XTLS/Xray-install.git refs/heads/main\n\ncurl -L https://raw.githubusercontent.com/XTLS/Xray-install/\u003cCOMMIT\u003e/install-release.sh | sha256sum\n```\n\n然后编辑脚本顶部，替换默认值：\n\n```bash\nXRAY_INSTALL_REF_DEFAULT=\"\u003cCOMMIT\u003e\"\nXRAY_INSTALL_SHA256_DEFAULT=\"\u003csha256\u003e\"\n```\n\n### 显式追新模式\n\n如需主动跟随官方安装脚本 `main` 分支，可在运行时显式覆盖 ref，并把 sha256 校验置空：\n\n```bash\nXRAY_INSTALL_REF=main XRAY_INSTALL_SHA256= /root/xray_deploy.sh\n```\n\n也可以一行运行远端脚本：\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/superchaospc/xray-relay/main/xray_deploy.sh -o /tmp/xray_deploy.sh \\\n  \u0026\u0026 chmod +x /tmp/xray_deploy.sh \\\n  \u0026\u0026 XRAY_INSTALL_REF=main XRAY_INSTALL_SHA256= /tmp/xray_deploy.sh\n```\n\n### 🛠️ 首次部署 VPS 直连\n\n1. 运行脚本，选择 **`1) 全新安装`**\n2. 在 SOCKS5 节点录入阶段输入 `done`\n3. 按提示输入 `y` 创建 443 端口的 VPS 直连节点\n4. 输入节点备注名称（回车默认 `VPS-Direct`）\n5. 脚本自动完成：依赖检查 → Xray 检查/安装 → 密钥生成 → 配置校验下发 → BBR → 防火墙 → 服务启动\n6. 部署完成后会输出 VLESS 链接和二维码\n\n### 🛠️ 批量添加 VPS 直连\n\n已有配置后运行脚本，选择 **`14) 批量添加 VPS 直连节点`**，再输入要搭建的数量即可。单次最多 30 个，脚本会自动从当前可用端口继续分配，并按 `VPS-Direct-1`、`VPS-Direct-2`、`VPS-Direct-3` 的格式命名。\n\n批量直连添加成功后，脚本会逐条输出 VLESS 链接和二维码，同时刷新 `/root/xray_subscription.txt` 并打印订阅 Data URL。\n\n### 🛠️ 首次部署住宅 SOCKS5 中转\n\n1. 运行脚本，选择 **`1) 全新安装`**\n2. 按提示输入 SOCKS5 前置节点，常见推荐格式：\n   - `IP:端口:用户名:密码`\n   - 例如：`161.77.77.5:12324:user01:pass01`\n   - 这种格式中密码不能包含 `:`\n3. 如果用户名或密码有特殊字符，请使用 URL 格式：\n   - `socks5://user:pass@host:port` 或 `socks://user:pass@host:port`\n   - 特殊字符请按 URL 编码，例如 `:` 写成 `%3A`，`@` 写成 `%40`\n   - 按 `done` 或直接回车结束录入\n4. 脚本会为每个节点分配独立入口端口，客户端连接不同端口即可选择不同出口。首次安装时第 1 个节点默认监听 `443`，第 2 个开始为 `8444`、`8445`...；后续菜单添加节点会从 `8443` 起寻找空闲端口。\n\n### 📲 导入客户端\n\n脚本在每个节点生成完毕后会自动打印二维码。扫码方式：\n\n- 🍎 **Shadowrocket (iOS)** — 首页右上角扫一扫\n- 🪟 **V2rayN (Windows)** — `Ctrl+Shift+Alt+S` 从屏幕扫码，或从剪贴板导入\n- 🤖 **V2rayNG (Android)** — 加号 → 扫描二维码（对着另一台屏幕）\n- 📦 **Neobox (Android)** — 导入配置 → 扫描屏幕二维码\n\n\u003e 💡 扫码成功率与终端背景相关。白底或纯色主题最佳，避免透明/渐变背景。\n\n### 📦 批量添加住宅 SOCKS5\n\n菜单选择 **`13) 批量添加住宅 SOCKS5 节点`**，每行粘贴一个节点，最多 20 个：\n\n```text\n192.204.3.26:12324:14ae356118cc6:cb67514644\n192.204.0.126:12324:14ae356118cc6:cb67514644\n168.158.45.45:12324:14ae356118cc6:cb67514644\n```\n\n粘贴完成后输入 `done` 结束。空行会被忽略，避免复制时多余换行提前终止录入。脚本会自动用 IP/host 作为线路名称，批量写入配置，重启成功后逐条输出 VLESS 链接和二维码，并生成 base64 订阅内容到 `/root/xray_subscription.txt`。\n\n如果你确实需要在终端直接打印 Data URL，可这样运行：\n\n```bash\nXRAY_PRINT_SUB_DATA_URL=1 bash xray_deploy.sh\n```\n\n---\n\n## 🧭 菜单功能\n\n| 选项 | 功能 |\n| --- | --- |\n| 1 | 全新安装（首次部署完整流程） |\n| 2 | 添加住宅 SOCKS5 节点 |\n| 3 | 删除节点 |\n| 4 | 修改节点监听端口 |\n| 5 | 查看状态（Xray 运行状态 / BBR / 节点信息） |\n| 6 | 流量统计（基于 Xray API） |\n| 7 | 排错诊断 |\n| 8 | 更新 Xray 到最新版 |\n| 9 | 重启 Xray |\n| 10 | 监控报警（邮件通知配置） |\n| 11 | 卸载 |\n| 12 | 添加 VPS 直连节点（不经住宅 IP） |\n| 13 | 批量添加住宅 SOCKS5 节点（最多 20 个） |\n| 14 | 批量添加 VPS 直连节点（最多 30 个） |\n| 15 | 修改节点名称（住宅 SOCKS5 / VPS 直连均支持） |\n| 16 | 批量删除节点（支持逗号 / 空格 / 范围选择） |\n| 0 | 退出 |\n\n---\n\n## 🏗️ 架构说明\n\n```mermaid\nflowchart LR\n    client[\"客户端\u003cbr/\u003eShadowrocket\u003cbr/\u003eV2rayN / V2rayNG / NekoBox\"]\n\n    subgraph vps[\"VPS · Xray VLESS + REALITY\"]\n        inA[\"入口端口 A\"] --\u003e socks1[\"SOCKS5 节点 1\"]\n        inB[\"入口端口 B\"] --\u003e socks2[\"SOCKS5 节点 2\"]\n        inC[\"入口端口 C\"] --\u003e direct[\"VPS 直连出口\"]\n    end\n\n    client --\u003e inA\n    client --\u003e inB\n    client --\u003e inC\n\n    socks1 --\u003e home1[\"住宅 IP 1\"]\n    socks2 --\u003e home2[\"住宅 IP 2\"]\n    direct --\u003e dc[\"机房 IP\"]\n```\n\n- 每个入口端口对应一个出口（一对一固定映射），客户端通过连接不同端口选择出口节点\n- 前端 VLESS+REALITY 保证中转链路不被 GFW 识别\n- 后端 SOCKS5 可接入任意住宅 IP 提供商（支持带账号密码认证）\n\n---\n\n## 📁 配置文件位置\n\n| 文件 | 用途 |\n| --- | --- |\n| `/usr/local/etc/xray/config.json` | Xray 主配置 |\n| `/root/xray_nodes_info.txt` | 所有节点的 VLESS 链接备份 |\n| `/root/xray_subscription.txt` | base64 订阅内容 |\n| `/root/.xray_vps_ip` | VPS 公网 IP 缓存 |\n| `/root/.xray_traffic_db` | 流量统计数据库 |\n| `/root/.xray_traffic_record.sh` | 流量采集脚本（cron 每 5 分钟运行一次） |\n| `/etc/sysctl.d/99-xray.conf` | BBR 与内核调优参数 |\n| `/etc/systemd/system/xray.service.d/limits.conf` | Xray 文件描述符上限配置 |\n| `/root/.xray_monitor.conf` | 监控告警配置（如启用） |\n| `/root/.xray_monitor.sh` | 监控巡检脚本 |\n| `/root/.msmtprc` | msmtp 邮件发送配置（如启用监控邮件） |\n| `/var/log/xray/` | Xray 运行日志 |\n\n`/usr/local/etc/xray/config.json` 由脚本写入或回滚后会强制设置为 `640 root:\u003cXray 服务用户主组\u003e`。这样可以避免 `600 root:root` 导致非 root Xray 服务用户读取失败，也避免 `644` 让本地非服务用户读取 UUID/REALITY 私钥。\n\n\u003e 说明：脚本会在 Xray inbound 内写入 `_remark` 字段作为节点名称元数据。当前 Xray 会忽略未知字段；该字段只供脚本在修改节点名称、修改端口、删除节点、重建 `/root/xray_nodes_info.txt` 时恢复节点备注使用。\n\n---\n\n## 🔐 安全与副作用\n\n脚本需要 root 权限，会对系统做以下改动：\n\n- 安装必要依赖与 Xray core；默认不执行整机升级\n- 写入 `/usr/local/etc/xray/config.json`，并保留最近 5 份 `config.json.bak.*` 备份\n- 写入 `/etc/sysctl.d/99-xray.conf` 开启 BBR 与网络参数优化\n- 如果系统没有 swap 且不存在 `/swapfile`，会创建 1G swap\n- 修改系统防火墙规则，并尽量持久化到对应后端\n- 配置监控报警时会写入 `/root/.msmtprc` 与 `/root/.xray_monitor.conf`，权限为 `600`；SMTP 密码/授权码会以明文保存在 `/root/.msmtprc`\n- 启用监控时会写入 `xray-monitor.service` / `xray-monitor.timer`，timer 每分钟运行一次\n\n---\n\n## 🧪 测试\n\n仓库内置轻量测试套件：\n\n```bash\nbash run_all_tests.sh\n```\n\n当前覆盖：\n\n- `bash -n xray_deploy.sh`\n- `shellcheck -S error xray_deploy.sh`（未安装则跳过）\n- `test_parser.py`：SOCKS5 输入解析，包括 URL 端口非法、IPv6、密码特殊字符\n- `test_prompt_read_eof.sh`：交互提示在 stdin EOF 时优雅退出\n- `test_prompt_read_trim.sh`：交互输入自动修剪首尾空白\n- `test_get_ip_eof.sh`：公网 IP 获取在 EOF 场景下返回失败\n- `test_next_port.sh`：入站端口计算，包括端口耗尽时返回非 0\n- `test_public_key_and_ports.sh`：public key 派生失败、业务端口过滤与端口修改链接备注\n- `test_atomic_config.sh`：配置原子写入与回滚流程\n- `test_restart_rollback_permissions.sh`：重启失败回滚后恢复 `config.json` 权限\n- `test_info_parse.sh`：节点信息解析\n- `test_subscription_file.sh`：订阅文件生成与刷新\n- `test_smtp_validate.sh`：SMTP 输入校验\n- `test_firewall_capture.sh`：防火墙返回码捕获链路\n- `test_nft_firewall.sh`：nftables input 链识别，包括 fail2ban 默认 accept 链与默认 drop 链\n- `test_nft_firewall_revoke.sh`：nftables managed/legacy 端口规则回收与防误删\n- `test_crontab_cleanup.sh`：卸载时清理流量统计 cron\n- `test_delete_node_outbound_match.sh`：删除节点时 outbound 精确匹配\n- `test_traffic_record.sh`：流量统计首次记录 delta=0\n- `test_monitor_alert.sh`：监控告警按故障详情去重\n- `test_config_remarks.sh`：节点备注写入配置并可恢复\n- `test_rename_node.sh`：住宅与直连节点名称可修改并刷新订阅\n- `test_batch_direct_nodes.sh`：批量 VPS 直连节点写入与菜单入口\n- `test_batch_delete_nodes.sh`：批量删除节点选择解析、路由和 outbound 清理\n\n当前测试结果：\n\n```text\n通过: 25  失败: 0  跳过: 0\n```\n\n如果系统未安装 `shellcheck`，静态检查会自动跳过该项。\n\n---\n\n## ❓ 常见问题\n\n**Q: 脚本提示 `Xray 安装脚本来源未配置`，是不是坏了？**\n\nA: 通常是你手动把脚本里的安装来源改成了空值。当前脚本默认固定 `XTLS/Xray-install` 的 commit 并校验 sha256，新 VPS 可直接安装。如需主动追新，也可以显式使用：\n\n```bash\nXRAY_INSTALL_REF=main XRAY_INSTALL_SHA256= /root/xray_deploy.sh\n```\n\n**Q: 部署后客户端连不上？**\n\nA: 运行菜单 `7) 排错诊断`，会依次检查：\n\n- Xray 服务状态与版本\n- 配置文件是否存在、JSON 是否合法、业务节点是否有 privateKey\n- 业务端口监听\n- 防火墙放行状态\n- SOCKS5 落地节点连通性\n- BBR 状态\n- 内存、磁盘、CPU 负载\n- 最近 1 小时 Xray 错误日志\n\n还需要确认云厂商安全组已放行对应 TCP 端口，例如 443、8443 等。脚本只能修改 VPS 系统内的防火墙，不能自动修改云厂商控制台里的安全组。\n\n如果系统使用 nftables，脚本会自动识别实际 input 链名。像 fail2ban 创建的 `f2b-table/f2b-chain` 且默认策略为 `accept` 的场景，不需要额外添加 `inet filter input` 规则；真正默认 `drop` / `reject` 的 input 链才需要插入端口放行规则。\n\n常用排查命令：\n\n```bash\nsystemctl status xray --no-pager -l\njournalctl -u xray -n 30 --no-pager\nxray run -test -config /usr/local/etc/xray/config.json\n```\n\n如果刚改配置后启动失败，脚本会自动尝试回滚。也可以手动查看备份：\n\n```bash\nls -1t /usr/local/etc/xray/config.json.bak.*\n```\n\n**Q: 安装 Xray 时卡在下载？**\n\nA: 脚本依赖 GitHub 下载官方 Xray 安装脚本，国内部分机器可能被墙。解决方案：\n- 给 VPS 临时配置 `8.8.8.8` / `1.1.1.1` DNS\n- 使用代理：`export https_proxy=http://...` 后再运行脚本\n- 或手动下载脚本后本地执行\n\n**Q: SOCKS5 密码里有 `:` 或 `|` 怎么办？**\n\nA: 大多数代理商给的是 `host:port:user:pass`，例如：\n\n```text\n161.77.48.218:12324:14aaddb22c3ae:8b9027e676\n```\n\n这种可以直接粘贴。只有当密码里有 `:`、`@`、`#` 等特殊字符时，才建议使用 `socks5://user:pass@host:port` 或 `socks://user:pass@host:port` 格式，并对特殊字符做 URL 编码：\n\n- `:` → `%3A`\n- `@` → `%40`\n- `#` → `%23`\n\n常见格式 `host:port:user:pass` 中，密码不能包含 `:`。\n\n**Q: `xray run -test` 报 `Failed to get format`？**\n\nA: 新版 Xray 对配置文件格式识别更严格，临时配置文件需要 `.json` 后缀。当前脚本已将临时配置统一写成 `/tmp/.xray_config.new.XXXXXX.json`。\n\n**Q: 启动失败并提示 `permission denied` 读取 `config.json`？**\n\nA: 这通常是 Xray service 以 `nobody` 等非 root 用户运行，但配置文件被写成了 `root:root 600`。当前脚本会强制把新写入或回滚恢复的 `config.json` 设为 `640 root:\u003cXray 服务用户主组\u003e`，确保 Xray 服务用户可读，同时避免本地其他用户读取 UUID/REALITY 私钥。\n\n历史教训：早期版本曾尝试「继承现有文件 owner/group」，但一旦初始文件意外是 `600 root:root`（比如 root umask 077 下用 Python `open('w')` 写出来的），后续每次写新配置都会延续这个错误，nobody 永远读不到。详见 [commit f28238c](https://github.com/superchaospc/xray-relay/commit/f28238c)。\n\n**Q: 如何升级到新版本脚本？**\n\nA: 重新下载覆盖即可。现有配置（Xray config、节点信息、监控配置）均独立保存，不会丢失。\n\n**Q: 监控、流量统计日志在哪里？**\n\nA: 常用位置：\n\n- 流量数据库：`/root/.xray_traffic_db`\n- 流量采集脚本：`/root/.xray_traffic_record.sh`（cron 每 5 分钟运行一次）\n- 监控日志：`/var/log/xray/monitor.log`\n- 监控配置：`/root/.xray_monitor.conf`\n- 监控脚本：`/root/.xray_monitor.sh`（systemd timer 每分钟运行一次）\n\n同类监控告警有 30 分钟冷却时间，短时间内不会重复刷屏。\n\n---\n\n## 🙏 致谢\n\n- [XTLS/Xray-core](https://github.com/XTLS/Xray-core) — 核心代理引擎\n- [XTLS/Xray-install](https://github.com/XTLS/Xray-install) — 官方安装脚本\n\n---\n\n## 📄 License\n\nMIT\n\n---\n\n## ⚠️ 免责声明（再次强调）\n\n本工具仅用于学习网络协议、系统运维与安全研究。使用者应对自己的行为负全部责任，并遵守所在国家/地区的相关法律法规。严禁用于任何违反当地法律的用途。作者不对使用本脚本导致的任何后果负责。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuperchaospc%2Fxray-relay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuperchaospc%2Fxray-relay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuperchaospc%2Fxray-relay/lists"}