fix: node installer refuses a non-empty server before touching it and reports active only after xray stays up

The install script now checks for a foreign proxy (xray directory, docker marzban/xray) and busy ports
before adding the management key or writing anything, and tells the panel the node is active only after
xray has stayed up with its port listening for three checks in a row.
This commit is contained in:
Savsis? 2026-10-04 04:48:39 +05:00
parent 4791c5ca2b
commit 6372d649da
2 changed files with 39 additions and 2 deletions

View file

@ -61,6 +61,9 @@ jobs:
} }
script = nodeprov.render_install_script(node) script = nodeprov.render_install_script(node)
assert "PRIVKEY" in script assert "PRIVKEY" in script
assert "PREFLIGHT_FAIL" in script and "443 2053 2087" in script, "node install must refuse a non-empty server before touching it"
assert script.index("PREFLIGHT_FAIL") < script.index("authorized_keys"), "preflight must run before the management key is added"
assert "OK=$((OK+1))" in script and "STATUS=failed" in script, "node must report active only after xray stays up"
assert len(script) > 500 assert len(script) > 500
print("node install script rendered OK,", len(script), "bytes") print("node install script rendered OK,", len(script), "bytes")
PYEOF PYEOF

View file

@ -71,6 +71,28 @@ set -e
echo "== MBS Panel node install ==" echo "== MBS Panel node install =="
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
PREFLIGHT_FAIL=0
if ! {{ [ -f /usr/local/etc/xray/config.json ] && grep -q mbs-grpc /usr/local/etc/xray/config.json; }}; then
if [ -d /usr/local/bin/xray ]; then
echo "СТОП: /usr/local/bin/xray это каталог, на сервере уже стоит чужой прокси (Marzban-node и подобное)"
PREFLIGHT_FAIL=1
fi
if command -v docker >/dev/null 2>&1 && docker ps --format '{{{{.Names}}}}' 2>/dev/null | grep -qiE 'marzban|xray|remnawave|v2ray|hysteria'; then
echo "СТОП: в Docker на этом сервере уже крутится прокси"
PREFLIGHT_FAIL=1
fi
for p in {ports}; do
if ss -ltn 2>/dev/null | awk '{{print $4}}' | grep -qE "[:.]$p$"; then
echo "СТОП: порт $p уже занят другим процессом"
PREFLIGHT_FAIL=1
fi
done
fi
if [ "$PREFLIGHT_FAIL" = "1" ]; then
echo "Нужен чистый сервер. Ничего не установлено и не изменено, ключ панели не добавлен."
exit 1
fi
mkdir -p /root/.ssh mkdir -p /root/.ssh
chmod 700 /root/.ssh chmod 700 /root/.ssh
curl -Ls https://{panel}/mgmt-pubkey.txt >> /root/.ssh/authorized_keys curl -Ls https://{panel}/mgmt-pubkey.txt >> /root/.ssh/authorized_keys
@ -91,9 +113,19 @@ XRAYCFG
command -v ufw >/dev/null 2>&1 && {{ ufw allow 22/tcp || true; {ufw_rules} }} command -v ufw >/dev/null 2>&1 && {{ ufw allow 22/tcp || true; {ufw_rules} }}
systemctl enable xray >/dev/null 2>&1 || true systemctl enable xray >/dev/null 2>&1 || true
systemctl restart xray systemctl restart xray
OK=0
for i in 1 2 3 4 5 6 7 8; do
sleep 1 sleep 1
STATUS=$(systemctl is-active xray) if systemctl is-active --quiet xray && ss -ltn 2>/dev/null | awk '{{print $4}}' | grep -qE "[:.]{first_port}$"; then
OK=$((OK+1))
else
OK=0
fi
if [ "$OK" -ge 3 ]; then break; fi
done
if [ "$OK" -ge 3 ]; then STATUS=active; else STATUS=failed; fi
echo "xray status: $STATUS" echo "xray status: $STATUS"
if [ "$STATUS" != "active" ]; then journalctl -u xray -n 15 --no-pager 2>/dev/null || true; fi
{hysteria_block} {hysteria_block}
MY_IP=$(curl -s https://api.ipify.org || echo unknown) MY_IP=$(curl -s https://api.ipify.org || echo unknown)
@ -234,9 +266,11 @@ def render_install_script(node: dict) -> str:
sni=node["sni"], sni=node["sni"],
) )
ports = " ".join(str(t["port"]) for t in transports)
return SELF_INSTALL_SCRIPT.format( return SELF_INSTALL_SCRIPT.format(
panel=PANEL_DOMAIN, token=node["provision_token"], config_json=config_json, panel=PANEL_DOMAIN, token=node["provision_token"], config_json=config_json,
certbot_block=certbot_block, hysteria_block=hysteria_block, ufw_rules=ufw_rules, certbot_block=certbot_block, hysteria_block=hysteria_block, ufw_rules=ufw_rules,
ports=ports, first_port=transports[0]["port"],
) )