此修订修复了“地址已被使用”崩溃循环的根本原因:直接(非Tor)入站和nginx都试图绑定 8080 端口,而nginx 同时 监听3000端口——在只转发一个外部端口到容器的平台上,第二个绑定会导致崩溃。
📐 架构
flowchart LR
subgraph Public["🌍 公网"]
C[客户端]
end
subgraph Container["容器 — 仅端口3000被暴露"]
N["nginx :3000\n(唯一公共绑定)"]
D["xray 直接入站\n127.0.0.1:8080"]
P["3x-ui 面板\n127.0.0.1:2053"]
subgraph Countries["每个国家隔离的栈(仅已验证)"]
direction TB
I1["xray 入站 /in1\n127.0.0.1:8081"] --> T1["Tor 实例:德国\nSOCKS 127.0.0.1:9052"]
I2["xray 入站 /in2\n127.0.0.1:8082"] --> T2["Tor 实例:法国\nSOCKS 127.0.0.1:9053"]
end
N -->|"/" "/direct"| D
N -->|"/managepanel/"| P
N -->|"/in1"| I1
N -->|"/in2"| I2
end
C --> N
为什么这修复了“直接配置不工作”的问题(点击展开)
之前:nginx 监听 3000 端口,同时 xray 直接入站也尝试 listen 0.0.0.0:8080。在只转发一个外部端口到容器的平台上,第二个绑定会导致崩溃。
错误 - XRAY:启动失败:... 无法监听地址:0.0.0.0:8080
... 绑定:地址已被使用
之后:nginx 是唯一绑定到 0.0.0.0 的进程,端口为 3000。直接入站绑定到 127.0.0.1:8080(仅本地回环),nginx 的 / 和 /direct 位置反向代理到它。每个容器都正常工作。
✨ 此修订的变更内容
| 领域 | 之前 | 之后 |
|---|---|---|
| 公共端口 | nginx 在3000端口且直接xray入站尝试8080端口 → 崩溃循环 | 仅端口3000 是公共的;直接入站为 127.0.0.1:8080,由nginx代理 |
| 国家发现 | 顺序执行,1个提供商超时路径,最多15次重试 × (10秒 + 15秒) 睡眠 ≈ 每个国家数分钟 | 所有国家并行,4个地理IP提供商 + 5个IP回声服务 |
| 失败国家 | 大多数已排除,但不一致 | 单一真相来源(is_location_verified()):失败的国家没有入站、没有客户端、没有出站、没有出口节点 |
| 面板中的命名 | 入站标签/备注为 Tor-Germany,出站标签为 tor-de | 标签/备注仅使用国家——Germany / de。单词“Tor”不出现在任何入站、客户端… |
| IP轮换 | 轮换器存在但为单个硬编码循环 | 相同的轮换器,现在清晰地记录为每个已验证国家的自动IP切换,可调间隔,错误国家自愈… |
| nginx配置 | 10个国家块硬编码,即使失败/移除国家也始终存在 | 国家位置块从已验证国家列表在容器启动时动态生成 |
🚀 部署
- 将此仓库部署到Railway(或任何单端口容器主机)。
- 可选环境变量:
| 变量 | 用途 | 默认值 |
|---|---|---|
XUI_USERNAME | 面板用户名 | admin |
XUI_PASSWORD | 面板密码 | admin |
XUI_API_TOKEN | 令牌,跳过表单登录(如果设置) | (未设置) |
PUBLIC_DOMAIN | 覆盖自动检测的公共域名 | 自动检测 |
- 其他所有内容——公共端口、轮换间隔、重试/超时调优,以及国家列表本身——都在
config.json中。
📡 端点
所有端点通过 单一公共端口(3000) 由nginx提供。
| 路径 | 类型 | 说明 |
|---|---|---|
/ | 🌐 直接 | 默认——服务器自身IP,无Tor |
/direct | 🌐 直接 | 与/相同,显式路径 |
/in1 … /in10 | 🔒 国家出口 | 仅在该国家通过发现时存在——查看config.json以了解哪个路径映射到哪个国家 |
/managepanel/ | — | 3x-ui 管理面板 |
/tor-status/all.json | — | 所有配置国家的实时状态 |
/tor-status/<code>.json | — | 单个国家的实时状态(exit_ip、verified、checked_at等) |
/health, /ping | — | 存活检查 |
默认国家列表(config.json中配置了10个)
| 路径 | 国家 |
|---|---|
/in1 | 🇨🇦 加拿大 |
/in2 | 🇹🇷 土耳其 |
/in3 | 🇩🇪 德国 |
/in4 | 🇫🇷 法国 |
/in5 | 🇸🇪 瑞典 |
/in6 | 🇨🇭 瑞士 |
/in7 | 🇫🇮 芬兰 |
/in8 | 🇬🇧 英国 |
/in9 | 🇪🇸 西班牙 |
/in10 | 🇷🇴 罗马尼亚 |
通过编辑config.json中的tor.countries数组添加、移除或重新分配任何这些——脚本中没有任何内容硬编码到特定列表长度或路径。
🔎 国家发现现在如何工作
sequenceDiagram
participant S as start.sh
participant T as Tor实例(每个国家)
participant G as Geo-IP提供商(×4)
par 所有国家并行
S->>T:启动 + 等待Bootstrapped 100%
loop 最多verify_max_retries次
S->>T:获取出口IP(×5回声服务,第一个有效者胜出)
S->>G:将IP解析为国家(第一个响应的提供商胜出)
alt 国家匹配
S-->>S:✅ 已验证,写入状态JSON
else 不匹配或查找失败
S->>T:发送SIGNAL NEWNYM(强制新电路)
S-->>S:短暂有界睡眠,重试
end
end
end
S->>S:从所有状态文件构建VERIFIED_CODES[]
S->>S:渲染nginx位置 + 交给panel-bootstrap.sh
config.json中tor.*下的所有内容无需修改脚本即可调优:
"tor": {
"bootstrap_timeout": 240, // Tor达到100%的最大等待时间
"verify_max_retries": 15, // 尝试找到匹配国家出口的次数
"verify_retry_sleep": 4, // 尝试之间的秒数
"circuit_settle_sleep": 6, // 新电路后的稳定时间
"parallel_bootstrap": true, // 并行引导和验证所有国家
"parallel_verify": true
}
🔁 自动IP切换
每个已验证国家有自己的后台轮换周期(tor.rotate_seconds,默认300秒):
SIGNAL NEWNYM发送到该国家自己的ControlPort——请求一个新的Tor电路,因此新的出口IP。- 新出口IP通过用于发现的相同多提供商地理IP查找重新解析。
- 如果新IP仍在正确国家,状态文件更新,客户端继续工作不中断。
- 如果第一次轮换落在错误国家,立即再尝试一次;如果也失败,该国家被标记为不可达直到下一个计划轮换(它不被拆除)…
这完全在start.sh(rotate_and_verify())内运行——没有外部cron,没有额外进程。
🔒 安全与命名
- 直接连接是
/和/direct的默认方式——不涉及Tor。 - 国家连接在它们的
/inN路径上可用,但仅对通过发现的国家。 - 严格出口节点强制执行——每个Tor实例用
ExitNodes {cc}+StrictNodes 1固定;架构上无法从其他地方出口。 - 排除区域——
config.json中的tor.exclude_countries(压迫政权和高风险司法管辖区)从每个实例的可能出口集中排除,而不仅仅是目标国家本身… - 面板中无“Tor”——入站标签、备注、出站标签和路由规则仅使用国家代码/标签。面板截图、导出的客户端链接和xray JSON配置从不包含…
- 仅nginx是公共的——面板、直接入站、每个国家入站和每个Tor SOCKS/Control端口仅绑定到
127.0.0.1。
📋 日志
| 文件 | 内容 |
|---|---|
/var/log/panel-bootstrap.log | 面板引导:入站/客户端/路由创建和拆除 |
/var/log/tor/rotate.log | 自动IP切换周期 |
/var/log/tor/<code>-stdout.log | 该国家Tor进程的原始stdout/stderr |
/var/log/tor/<code>/notices.log | Tor通知级别日志(引导进度、电路事件) |
/var/log/tor/<code>/warnings.log | Tor警告级别日志 |
/var/www/tor-status/<code>.json | 该国家的实时可机读状态 |
/var/www/tor-status/all.json | 所有国家组合 |
/var/www/tor-status/setup-progress.json | 总体 {total, verified, complete} 进度 |
🗂️ 文件映射
.
├── Dockerfile # 镜像构建;仅EXPOSE端口3000 + 健康检查
├── config.json # 端口、国家、调优的单一真相来源
├── nginx.conf.template # 在容器启动时渲染(envsubst + 动态位置)
├── start.sh # 入口点:启动Tor、发现、轮换、渲染nginx、执行nginx
├── panel-bootstrap.sh # 与3x-ui API通信:为已验证国家创建入站/客户端/路由
└── torrc.reference # 仅文档;任何脚本都不读取