diff --git a/assets/clash/clash.yaml b/assets/clash/clash.yaml index 80ce49a..8a64d93 100644 --- a/assets/clash/clash.yaml +++ b/assets/clash/clash.yaml @@ -19,7 +19,7 @@ lgbm-url: "https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/ proxy-providers: sub: type: http - url: https://${DOMAIN}/${SUB_PATH}/ + url: https://${DOMAIN}/${SUB_PATH}/${SUB_ID} path: ./proxy_providers/base64.yml interval: 3600 health-check: diff --git a/assets/diagnostics/mtr-backend.py b/assets/diagnostics/mtr-backend.py index c46e4ac..8e2a39c 100644 --- a/assets/diagnostics/mtr-backend.py +++ b/assets/diagnostics/mtr-backend.py @@ -180,10 +180,38 @@ class Handler(BaseHTTPRequestHandler): return ip def do_GET(self): - if self.path == "/health": + parsed = urlparse(self.path) + + if parsed.path == "/health": self._send_json(200, {"ok": True}) - else: - self._send_json(404, {"error": "not found"}) + return + + # ── Clash subscription generator ─────────────────────────────────────── + if parsed.path == "/api/clash" or parsed.path.endswith("/api/clash"): + tpl_path = "/var/www/subpage/clash.yaml.tpl" + if not os.path.isfile(tpl_path): + self._send_json(404, {"error": "clash template not found"}) + return + params = parse_qs(parsed.query) + sub_id = params.get("sub_id", [""])[0].strip() + try: + with open(tpl_path, "r", encoding="utf-8") as f: + content = f.read() + content = content.replace("${SUB_ID}", sub_id) + payload = content.encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "text/yaml; charset=utf-8") + self.send_header("Content-Length", str(len(payload))) + self.send_header("Content-Disposition", "attachment; filename=clash.yaml") + self.send_header("Cache-Control", "no-store") + self.end_headers() + self.wfile.write(payload) + except Exception as exc: + log.error("clash template error: %s", exc) + self._send_json(500, {"error": "internal error"}) + return + + self._send_json(404, {"error": "not found"}) def do_POST(self): parsed = urlparse(self.path) diff --git a/x-ui-latest.sh b/x-ui-latest.sh index eaf229d..d94bd3e 100644 --- a/x-ui-latest.sh +++ b/x-ui-latest.sh @@ -307,19 +307,25 @@ EOF # Shared proxy locations for xray inbounds (included by both vhosts) cat > /etc/nginx/snippets/includes.conf <[^/]*)$ { if (\$hack = 1) { return 404; } - if (\$is_clash_client = 1) { rewrite ^ /__clash_sub last; } + if (\$is_clash_client = 1) { + proxy_pass http://127.0.0.1:${mtr_backend_port}/api/clash?sub_id=\$clash_sub_id; + break; + } proxy_redirect off; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; @@ -501,16 +507,6 @@ server { add_header Content-Disposition "attachment" always; } - # ── Clash subscription — internal static file served by UA routing ────────── - location = /__clash_sub { - internal; - default_type text/plain; - alias /var/www/subpage/clash.yaml; - add_header Content-Type "text/yaml; charset=utf-8" always; - add_header Content-Disposition "attachment; filename=clash.yaml" always; - add_header Cache-Control "no-store" always; - } - include /etc/nginx/snippets/includes.conf; } EOF @@ -875,12 +871,13 @@ EOF install_clash_sub() { local clash_dir="/var/www/subpage" mkdir -p "${clash_dir}" - if curl -fsSL "${GITHUB_RAW}/assets/clash/clash.yaml" -o "${clash_dir}/clash.yaml"; then - sed -i "s|\${DOMAIN}|${domain}|g" "${clash_dir}/clash.yaml" - sed -i "s|\${SUB_PATH}|${sub_path}|g" "${clash_dir}/clash.yaml" + if curl -fsSL "${GITHUB_RAW}/assets/clash/clash.yaml" -o "${clash_dir}/clash.yaml.tpl"; then + # Substitute domain and sub_path; leave ${EMAIL} for mtr-backend to fill per-request + sed -i "s|\${DOMAIN}|${domain}|g" "${clash_dir}/clash.yaml.tpl" + sed -i "s|\${SUB_PATH}|${sub_path}|g" "${clash_dir}/clash.yaml.tpl" chown -R www-data:www-data "${clash_dir}" 2>/dev/null || true - chmod 644 "${clash_dir}/clash.yaml" - msg_ok "Clash subscription config installed." + chmod 644 "${clash_dir}/clash.yaml.tpl" + msg_ok "Clash subscription template installed." else msg_err "Failed to download clash.yaml from GitHub." fi