fix: run VLESS Reality on Xray instead of sing-box for v2rayN
sing-box Hy2 stays on 8443+; port 443 VLESS uses Xray which pairs reliably with v2rayN/Xray-core clients. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""根据 data/nodes.db 与 .env 生成 Xray VLESS+Reality 配置(443 端口)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(os.environ.get("JIEDIAN_ROOT", Path(__file__).resolve().parents[1]))
|
||||
ENV_FILE = ROOT / ".env"
|
||||
DB_FILE = ROOT / "data" / "nodes.db"
|
||||
OUT_FILE = Path("/usr/local/etc/xray/config.json")
|
||||
ACCESS_LOG = Path("/var/log/xray/access.log")
|
||||
|
||||
|
||||
def load_env(path: Path) -> dict[str, str]:
|
||||
env: dict[str, str] = {}
|
||||
if not path.exists():
|
||||
raise SystemExit(f"缺少 .env: {path}")
|
||||
for line in path.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, _, value = line.partition("=")
|
||||
env[key.strip()] = value.strip()
|
||||
return env
|
||||
|
||||
|
||||
def load_nodes(db_path: Path) -> list[dict]:
|
||||
if not db_path.exists():
|
||||
raise SystemExit(f"缺少节点数据库: {db_path},请先运行 install.sh")
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
rows = conn.execute(
|
||||
"SELECT id, name, uuid, hy2_password FROM nodes WHERE enabled = 1 ORDER BY id"
|
||||
).fetchall()
|
||||
conn.close()
|
||||
if not rows:
|
||||
raise SystemExit("没有可用节点,请在管理面板中添加节点")
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
|
||||
def build_config(env: dict[str, str], nodes: list[dict]) -> dict:
|
||||
required = [
|
||||
"REALITY_PRIVATE_KEY",
|
||||
"REALITY_SHORT_ID",
|
||||
"REALITY_SERVER_NAME",
|
||||
]
|
||||
for key in required:
|
||||
if not env.get(key):
|
||||
raise SystemExit(f".env 缺少 {key}")
|
||||
|
||||
short_id = env["REALITY_SHORT_ID"]
|
||||
clients = [
|
||||
{"id": node["uuid"], "flow": "xtls-rprx-vision", "email": node["uuid"]}
|
||||
for node in nodes
|
||||
]
|
||||
|
||||
return {
|
||||
"log": {
|
||||
"access": str(ACCESS_LOG),
|
||||
"loglevel": "warning",
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"listen": "0.0.0.0",
|
||||
"port": 443,
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": clients,
|
||||
"decryption": "none",
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp",
|
||||
"security": "reality",
|
||||
"realitySettings": {
|
||||
"show": False,
|
||||
"dest": f"{env['REALITY_SERVER_NAME']}:443",
|
||||
"xver": 0,
|
||||
"serverNames": [env["REALITY_SERVER_NAME"]],
|
||||
"privateKey": env["REALITY_PRIVATE_KEY"],
|
||||
"shortIds": ["", short_id],
|
||||
},
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": True,
|
||||
"destOverride": ["http", "tls", "quic"],
|
||||
},
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{"protocol": "freedom", "tag": "direct"},
|
||||
{"protocol": "blackhole", "tag": "block"},
|
||||
],
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"type": "field",
|
||||
"ip": ["geoip:private"],
|
||||
"outboundTag": "block",
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
env = load_env(ENV_FILE)
|
||||
nodes = load_nodes(DB_FILE)
|
||||
config = build_config(env, nodes)
|
||||
|
||||
OUT_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
ACCESS_LOG.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUT_FILE.write_text(json.dumps(config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||
|
||||
xray = subprocess.run(
|
||||
["xray", "run", "-test", "-c", str(OUT_FILE)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if xray.returncode != 0:
|
||||
sys.stderr.write(xray.stderr or xray.stdout)
|
||||
raise SystemExit(xray.returncode)
|
||||
|
||||
print(f"已生成 {OUT_FILE}({len(nodes)} 个 VLESS 用户)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user