mirror of
https://github.com/andrey271192/PCA_Phobos.git
synced 2026-09-21 12:01:56 +00:00
fix: harden router installs and failover sync
This commit is contained in:
96
app.py
96
app.py
@@ -7,7 +7,7 @@ Management panel: clients, sessions, labels, subscriptions, Telegram alerts.
|
|||||||
import json, os, subprocess, threading, time, secrets, hashlib, re, fcntl
|
import json, os, subprocess, threading, time, secrets, hashlib, re, fcntl
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from flask import Flask, request, redirect, url_for, session, make_response
|
from flask import Flask, request, redirect, url_for, session, make_response, send_from_directory
|
||||||
|
|
||||||
_settings_lock = threading.Lock()
|
_settings_lock = threading.Lock()
|
||||||
|
|
||||||
@@ -481,6 +481,7 @@ prev_session_keys = None
|
|||||||
prev_server_status = {}
|
prev_server_status = {}
|
||||||
_down_streak = {}
|
_down_streak = {}
|
||||||
_last_fanout = 0
|
_last_fanout = 0
|
||||||
|
_last_peer_sync = 0
|
||||||
server_stats_cache = {}
|
server_stats_cache = {}
|
||||||
server_handshakes_cache = {}
|
server_handshakes_cache = {}
|
||||||
|
|
||||||
@@ -809,6 +810,7 @@ def _ssh_run(access, cmd, timeout=20):
|
|||||||
"""Try SSH: tunnel IP first, then static IP as fallback."""
|
"""Try SSH: tunnel IP first, then static IP as fallback."""
|
||||||
ssh_user = access.get("ssh_user", "root")
|
ssh_user = access.get("ssh_user", "root")
|
||||||
ssh_pass = access.get("ssh_pass", "")
|
ssh_pass = access.get("ssh_pass", "")
|
||||||
|
ssh_port = str(access.get("ssh_port", "22") or "22")
|
||||||
ips_to_try = []
|
ips_to_try = []
|
||||||
if access.get("ssh_ip"):
|
if access.get("ssh_ip"):
|
||||||
ips_to_try.append(access["ssh_ip"])
|
ips_to_try.append(access["ssh_ip"])
|
||||||
@@ -820,7 +822,7 @@ def _ssh_run(access, cmd, timeout=20):
|
|||||||
try:
|
try:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["sshpass", "-p", ssh_pass, "ssh",
|
["sshpass", "-p", ssh_pass, "ssh",
|
||||||
"-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=3",
|
"-p", ssh_port, "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=3",
|
||||||
f"{ssh_user}@{ip}", cmd],
|
f"{ssh_user}@{ip}", cmd],
|
||||||
capture_output=True, text=True, timeout=timeout
|
capture_output=True, text=True, timeout=timeout
|
||||||
)
|
)
|
||||||
@@ -847,7 +849,7 @@ def push_config_to_router(client_id):
|
|||||||
|
|
||||||
|
|
||||||
def session_monitor():
|
def session_monitor():
|
||||||
global prev_session_keys, prev_server_status, server_stats_cache, _last_fanout, _down_streak
|
global prev_session_keys, prev_server_status, server_stats_cache, _last_fanout, _last_peer_sync, _down_streak
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
s = load_settings()
|
s = load_settings()
|
||||||
@@ -911,6 +913,13 @@ def session_monitor():
|
|||||||
for _c in get_clients():
|
for _c in get_clients():
|
||||||
fanout_router_config(_c.get("client_id", ""))
|
fanout_router_config(_c.get("client_id", ""))
|
||||||
|
|
||||||
|
# periodic peer repair to secondaries. This is what makes router
|
||||||
|
# server-failover work without pressing "Sync" after old clients
|
||||||
|
# or newly added secondary servers.
|
||||||
|
if time.time() - _last_peer_sync >= 300:
|
||||||
|
_last_peer_sync = time.time()
|
||||||
|
sync_missing_peers_to_secondaries()
|
||||||
|
|
||||||
check_expiry()
|
check_expiry()
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -1565,13 +1574,14 @@ def _render_install_commands():
|
|||||||
if not tokens:
|
if not tokens:
|
||||||
return '<p style="color:#64748b;font-size:.85em">Нет активных токенов. Добавьте клиента.</p>'
|
return '<p style="color:#64748b;font-size:.85em">Нет активных токенов. Добавьте клиента.</p>'
|
||||||
|
|
||||||
|
port = panel_port()
|
||||||
lines = ""
|
lines = ""
|
||||||
for t in tokens:
|
for t in tokens:
|
||||||
client = t.get("client", "?")
|
client = t.get("client", "?")
|
||||||
token = t.get("token", "")
|
token = t.get("token", "")
|
||||||
expires = t.get("expires", 0)
|
expires = t.get("expires", 0)
|
||||||
exp_str = datetime.fromtimestamp(expires).strftime("%Y-%m-%d %H:%M") if expires else "?"
|
exp_str = datetime.fromtimestamp(expires).strftime("%Y-%m-%d %H:%M") if expires else "?"
|
||||||
cmd = f"wget -O - http://{SERVER_IP}/init/{token}.sh | sh"
|
cmd = install_command(token, port)
|
||||||
lines += f"""
|
lines += f"""
|
||||||
<div style="margin-bottom:10px">
|
<div style="margin-bottom:10px">
|
||||||
<span style="color:#a5b4fc;font-size:.85em">{client}</span>
|
<span style="color:#a5b4fc;font-size:.85em">{client}</span>
|
||||||
@@ -1596,6 +1606,36 @@ def save_servers(servers):
|
|||||||
json.dump(servers, f, indent=2)
|
json.dump(servers, f, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
def panel_port():
|
||||||
|
try:
|
||||||
|
return open(os.path.join(PANEL_DIR, ".port")).read().strip() or "8443"
|
||||||
|
except Exception:
|
||||||
|
return "8443"
|
||||||
|
|
||||||
|
|
||||||
|
def install_command(token, port=None):
|
||||||
|
port = port or panel_port()
|
||||||
|
urls = [f"http://{SERVER_IP}:{port}/init/{token}.sh", f"http://{SERVER_IP}/init/{token}.sh"]
|
||||||
|
return ("tmp=/tmp/phobos-init-$$.sh; ok=0; "
|
||||||
|
f"for u in {' '.join(urls)}; do "
|
||||||
|
"rm -f $tmp; "
|
||||||
|
"(wget -q -O $tmp $u || curl -fsSL -o $tmp $u) 2>/dev/null || continue; "
|
||||||
|
"grep -qi '<html' $tmp && continue; "
|
||||||
|
"head -1 $tmp | grep -q '^#!' || continue; "
|
||||||
|
"sh $tmp; ok=1; break; "
|
||||||
|
"done; rm -f $tmp; [ $ok -eq 1 ] || echo 'ERROR: install script download failed (got HTML/proxy page or timeout)'")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/init/<path:name>")
|
||||||
|
def serve_init(name):
|
||||||
|
return send_from_directory(f"{PHOBOS_DIR}/www/init", name, mimetype="application/x-sh")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/packages/<path:name>")
|
||||||
|
def serve_package(name):
|
||||||
|
return send_from_directory(f"{PHOBOS_DIR}/www/packages", name, mimetype="application/octet-stream")
|
||||||
|
|
||||||
|
|
||||||
def get_main_server_info():
|
def get_main_server_info():
|
||||||
env = _load_server_env()
|
env = _load_server_env()
|
||||||
return {
|
return {
|
||||||
@@ -1667,6 +1707,30 @@ def sync_peer_to_all_servers(public_key, allowed_ips, action="add"):
|
|||||||
sync_peer_to_server(srv, public_key, allowed_ips, action)
|
sync_peer_to_server(srv, public_key, allowed_ips, action)
|
||||||
|
|
||||||
|
|
||||||
|
def sync_missing_peers_to_secondaries(server=None):
|
||||||
|
"""Best-effort peer repair: every secondary must already know every client.
|
||||||
|
Router failover can only work if the target server has the client's WG peer.
|
||||||
|
"""
|
||||||
|
servers = [server] if server else [srv for srv in load_servers() if srv.get("enabled", True)]
|
||||||
|
clients = get_clients()
|
||||||
|
synced = 0
|
||||||
|
for srv in servers:
|
||||||
|
health = check_server_health(srv)
|
||||||
|
if health.get("status") not in ("ok", None):
|
||||||
|
continue
|
||||||
|
remote_keys = set(health.get("peer_keys", []) or [])
|
||||||
|
for c in clients:
|
||||||
|
pub = c.get("public_key", "")
|
||||||
|
tip = (c.get("tunnel_ip_v4") or "").split("/")[0]
|
||||||
|
if not pub or not tip or pub in remote_keys:
|
||||||
|
continue
|
||||||
|
res = sync_peer_to_server(srv, pub, f"{tip}/32", "add")
|
||||||
|
if res.get("status") == "ok":
|
||||||
|
synced += 1
|
||||||
|
remote_keys.add(pub)
|
||||||
|
return synced
|
||||||
|
|
||||||
|
|
||||||
@app.route("/download/apk")
|
@app.route("/download/apk")
|
||||||
@auth_required
|
@auth_required
|
||||||
def download_apk():
|
def download_apk():
|
||||||
@@ -1834,9 +1898,10 @@ def api_client_ensure():
|
|||||||
os.chmod(f"{_www}/packages/{token}", 0o755)
|
os.chmod(f"{_www}/packages/{token}", 0o755)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
install_url = f"http://{SERVER_IP}/init/{token}.sh" if token else ""
|
install_url = f"http://{SERVER_IP}:{panel_port()}/init/{token}.sh" if token else ""
|
||||||
return json.dumps({
|
return json.dumps({
|
||||||
"ok": True, "client_id": cid, "install_url": install_url, "token": token,
|
"ok": True, "client_id": cid, "install_url": install_url, "token": token,
|
||||||
|
"install_command": install_command(token) if token else "",
|
||||||
"pull_token": pull_token, "tunnel_ip": tip, "assigned_server": assigned,
|
"pull_token": pull_token, "tunnel_ip": tip, "assigned_server": assigned,
|
||||||
}), 200, {"Content-Type": "application/json"}
|
}), 200, {"Content-Type": "application/json"}
|
||||||
|
|
||||||
@@ -1916,11 +1981,12 @@ def servers_page():
|
|||||||
api_key = request.form.get("api_key", "").strip()
|
api_key = request.form.get("api_key", "").strip()
|
||||||
ssh_user = request.form.get("ssh_user", "root").strip() or "root"
|
ssh_user = request.form.get("ssh_user", "root").strip() or "root"
|
||||||
ssh_pass = request.form.get("ssh_pass", "").strip()
|
ssh_pass = request.form.get("ssh_pass", "").strip()
|
||||||
|
ssh_port = request.form.get("ssh_port", "22").strip() or "22"
|
||||||
if ip:
|
if ip:
|
||||||
servers.append({
|
servers.append({
|
||||||
"ip": ip, "api_key": api_key, "enabled": True,
|
"ip": ip, "api_key": api_key, "enabled": True,
|
||||||
"last_seen": "", "wg_public_key": "", "obfuscator_key": "", "ports": "",
|
"last_seen": "", "wg_public_key": "", "obfuscator_key": "", "ports": "",
|
||||||
"ssh_user": ssh_user, "ssh_pass": ssh_pass
|
"ssh_user": ssh_user, "ssh_pass": ssh_pass, "ssh_port": ssh_port
|
||||||
})
|
})
|
||||||
save_servers(servers)
|
save_servers(servers)
|
||||||
order = s.get("server_order", [])
|
order = s.get("server_order", [])
|
||||||
@@ -1928,7 +1994,8 @@ def servers_page():
|
|||||||
order.append(ip)
|
order.append(ip)
|
||||||
s["server_order"] = order
|
s["server_order"] = order
|
||||||
save_settings(s)
|
save_settings(s)
|
||||||
msg = f'<div class="alert alert-ok">Сервер {ip} добавлен</div>'
|
synced = sync_missing_peers_to_secondaries(servers[-1])
|
||||||
|
msg = f'<div class="alert alert-ok">Сервер {ip} добавлен, синхронизировано {synced} клиентов</div>'
|
||||||
|
|
||||||
elif action == "remove":
|
elif action == "remove":
|
||||||
ip = request.form.get("ip", "").strip()
|
ip = request.form.get("ip", "").strip()
|
||||||
@@ -2004,8 +2071,9 @@ def servers_page():
|
|||||||
ssh_static = request.form.get(f"ssh_static_{cid}", "").strip()
|
ssh_static = request.form.get(f"ssh_static_{cid}", "").strip()
|
||||||
ssh_user = request.form.get(f"ssh_user_{cid}", "root").strip() or "root"
|
ssh_user = request.form.get(f"ssh_user_{cid}", "root").strip() or "root"
|
||||||
ssh_pass = request.form.get(f"ssh_pass_{cid}", "").strip()
|
ssh_pass = request.form.get(f"ssh_pass_{cid}", "").strip()
|
||||||
|
ssh_port = request.form.get(f"ssh_port_{cid}", "22").strip() or "22"
|
||||||
if ssh_ip or ssh_pass:
|
if ssh_ip or ssh_pass:
|
||||||
ra[cid] = {"ssh_ip": ssh_ip, "ssh_static": ssh_static, "ssh_user": ssh_user, "ssh_pass": ssh_pass, "ssh_ok": ra.get(cid, {}).get("ssh_ok", False)}
|
ra[cid] = {"ssh_ip": ssh_ip, "ssh_static": ssh_static, "ssh_user": ssh_user, "ssh_pass": ssh_pass, "ssh_port": ssh_port, "ssh_ok": ra.get(cid, {}).get("ssh_ok", False)}
|
||||||
elif cid in ra and not ssh_ip and not ssh_pass:
|
elif cid in ra and not ssh_ip and not ssh_pass:
|
||||||
del ra[cid]
|
del ra[cid]
|
||||||
s["router_access"] = ra
|
s["router_access"] = ra
|
||||||
@@ -2025,7 +2093,7 @@ def servers_page():
|
|||||||
try:
|
try:
|
||||||
r = subprocess.run(
|
r = subprocess.run(
|
||||||
["sshpass", "-p", acc.get("ssh_pass", ""), "ssh",
|
["sshpass", "-p", acc.get("ssh_pass", ""), "ssh",
|
||||||
"-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=5",
|
"-p", str(acc.get("ssh_port", "22") or "22"), "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=5",
|
||||||
f"{acc.get('ssh_user','root')}@{ip}", "echo OK"],
|
f"{acc.get('ssh_user','root')}@{ip}", "echo OK"],
|
||||||
capture_output=True, text=True, timeout=10
|
capture_output=True, text=True, timeout=10
|
||||||
)
|
)
|
||||||
@@ -2079,10 +2147,12 @@ def servers_page():
|
|||||||
ip = srv["ip"]
|
ip = srv["ip"]
|
||||||
su = request.form.get(f"srv_ssh_user_{ip}", "").strip()
|
su = request.form.get(f"srv_ssh_user_{ip}", "").strip()
|
||||||
sp = request.form.get(f"srv_ssh_pass_{ip}", "").strip()
|
sp = request.form.get(f"srv_ssh_pass_{ip}", "").strip()
|
||||||
|
sport = request.form.get(f"srv_ssh_port_{ip}", "22").strip() or "22"
|
||||||
if su:
|
if su:
|
||||||
srv["ssh_user"] = su
|
srv["ssh_user"] = su
|
||||||
if sp:
|
if sp:
|
||||||
srv["ssh_pass"] = sp
|
srv["ssh_pass"] = sp
|
||||||
|
srv["ssh_port"] = sport
|
||||||
save_servers(servers)
|
save_servers(servers)
|
||||||
msg = '<div class="alert alert-ok">SSH доступ к серверам сохранён</div>'
|
msg = '<div class="alert alert-ok">SSH доступ к серверам сохранён</div>'
|
||||||
|
|
||||||
@@ -2216,6 +2286,7 @@ def servers_page():
|
|||||||
ssh_static = acc.get("ssh_static", "")
|
ssh_static = acc.get("ssh_static", "")
|
||||||
ssh_user = acc.get("ssh_user", "root")
|
ssh_user = acc.get("ssh_user", "root")
|
||||||
ssh_pass = acc.get("ssh_pass", "")
|
ssh_pass = acc.get("ssh_pass", "")
|
||||||
|
ssh_port = acc.get("ssh_port", "22")
|
||||||
ssh_ok = acc.get("ssh_ok", False)
|
ssh_ok = acc.get("ssh_ok", False)
|
||||||
ssh_tested = acc.get("ssh_tested", "")
|
ssh_tested = acc.get("ssh_tested", "")
|
||||||
if ssh_ok:
|
if ssh_ok:
|
||||||
@@ -2232,6 +2303,7 @@ def servers_page():
|
|||||||
<td><input type="text" name="ssh_ip_{cid}" value="{ssh_ip}" placeholder="{tunnel_ip}" style="width:120px;padding:4px" title="WG tunnel IP"></td>
|
<td><input type="text" name="ssh_ip_{cid}" value="{ssh_ip}" placeholder="{tunnel_ip}" style="width:120px;padding:4px" title="WG tunnel IP"></td>
|
||||||
<td><input type="text" name="ssh_static_{cid}" value="{ssh_static}" placeholder="static" style="width:120px;padding:4px" title="Static/public IP (optional)"></td>
|
<td><input type="text" name="ssh_static_{cid}" value="{ssh_static}" placeholder="static" style="width:120px;padding:4px" title="Static/public IP (optional)"></td>
|
||||||
<td><input type="text" name="ssh_user_{cid}" value="{ssh_user}" placeholder="root" style="width:60px;padding:4px"></td>
|
<td><input type="text" name="ssh_user_{cid}" value="{ssh_user}" placeholder="root" style="width:60px;padding:4px"></td>
|
||||||
|
<td><input type="number" name="ssh_port_{cid}" value="{ssh_port}" placeholder="22" min="1" max="65535" style="width:70px;padding:4px"></td>
|
||||||
<td><input type="password" name="ssh_pass_{cid}" value="{ssh_pass}" placeholder="pass" style="width:100px;padding:4px"></td>
|
<td><input type="password" name="ssh_pass_{cid}" value="{ssh_pass}" placeholder="pass" style="width:100px;padding:4px"></td>
|
||||||
<td><span class="badge {badge_cls}" style="font-size:.7em">{badge_txt}</span></td>
|
<td><span class="badge {badge_cls}" style="font-size:.7em">{badge_txt}</span></td>
|
||||||
</tr>"""
|
</tr>"""
|
||||||
@@ -2265,6 +2337,7 @@ def servers_page():
|
|||||||
<input type="text" name="ip" placeholder="{tr('IP сервера','Server IP')}" required>
|
<input type="text" name="ip" placeholder="{tr('IP сервера','Server IP')}" required>
|
||||||
<input type="text" name="api_key" placeholder="API key" style="width:160px">
|
<input type="text" name="api_key" placeholder="API key" style="width:160px">
|
||||||
<input type="text" name="ssh_user" placeholder="root" style="width:70px" value="root">
|
<input type="text" name="ssh_user" placeholder="root" style="width:70px" value="root">
|
||||||
|
<input type="number" name="ssh_port" placeholder="22" value="22" min="1" max="65535" style="width:80px">
|
||||||
<input type="password" name="ssh_pass" placeholder="SSH pass" style="width:140px">
|
<input type="password" name="ssh_pass" placeholder="SSH pass" style="width:140px">
|
||||||
<button class="btn btn-primary" type="submit">{tr("Добавить сервер","Add Server")}</button>
|
<button class="btn btn-primary" type="submit">{tr("Добавить сервер","Add Server")}</button>
|
||||||
{hlp("Добавить новый VPN-сервер в пул резервирования. Нужны: IP, API-ключ агента (порт 8444) и SSH-пароль для первичной настройки.", "Add a new VPN server to the failover pool. Needs: IP, agent API key (port 8444) and SSH password for initial setup.")}
|
{hlp("Добавить новый VPN-сервер в пул резервирования. Нужны: IP, API-ключ агента (порт 8444) и SSH-пароль для первичной настройки.", "Add a new VPN server to the failover pool. Needs: IP, agent API key (port 8444) and SSH password for initial setup.")}
|
||||||
@@ -2276,7 +2349,7 @@ def servers_page():
|
|||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="save_router_access">
|
<input type="hidden" name="action" value="save_router_access">
|
||||||
<table>
|
<table>
|
||||||
<tr><th>{tr("Клиент","Client")}</th><th>Tunnel IP</th><th>{tr("Статич. IP","Static IP")}</th><th>{tr("Пользователь","User")}</th><th>{tr("Пароль","Pass")}</th><th>{tr("Статус","Status")}</th></tr>
|
<tr><th>{tr("Клиент","Client")}</th><th>Tunnel IP</th><th>{tr("Статич. IP","Static IP")}</th><th>{tr("Пользователь","User")}</th><th>{tr("Порт","Port")}</th><th>{tr("Пароль","Pass")}</th><th>{tr("Статус","Status")}</th></tr>
|
||||||
{access_rows}
|
{access_rows}
|
||||||
</table>
|
</table>
|
||||||
<button class="btn btn-primary" type="submit" style="margin-top:10px">{tr("Сохранить SSH","Save SSH")}</button>
|
<button class="btn btn-primary" type="submit" style="margin-top:10px">{tr("Сохранить SSH","Save SSH")}</button>
|
||||||
@@ -2305,10 +2378,11 @@ def servers_page():
|
|||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="save_server_access">
|
<input type="hidden" name="action" value="save_server_access">
|
||||||
<table>
|
<table>
|
||||||
<tr><th>Server</th><th>SSH User</th><th>SSH Pass</th><th></th></tr>
|
<tr><th>Server</th><th>SSH User</th><th>SSH Port</th><th>SSH Pass</th><th></th></tr>
|
||||||
{"".join(f'''<tr>
|
{"".join(f'''<tr>
|
||||||
<td>{srv.get("ip","")}</td>
|
<td>{srv.get("ip","")}</td>
|
||||||
<td><input type="text" name="srv_ssh_user_{srv.get('ip','')}" value="{srv.get('ssh_user','root')}" placeholder="root" style="width:80px;padding:4px"></td>
|
<td><input type="text" name="srv_ssh_user_{srv.get('ip','')}" value="{srv.get('ssh_user','root')}" placeholder="root" style="width:80px;padding:4px"></td>
|
||||||
|
<td><input type="number" name="srv_ssh_port_{srv.get('ip','')}" value="{srv.get('ssh_port','22')}" placeholder="22" min="1" max="65535" style="width:80px;padding:4px"></td>
|
||||||
<td><input type="password" name="srv_ssh_pass_{srv.get('ip','')}" value="{srv.get('ssh_pass','')}" placeholder="pass" style="width:150px;padding:4px"></td>
|
<td><input type="password" name="srv_ssh_pass_{srv.get('ip','')}" value="{srv.get('ssh_pass','')}" placeholder="pass" style="width:150px;padding:4px"></td>
|
||||||
<td><span class="badge {'badge-on' if srv.get('ssh_pass') else 'badge-off'}">{'OK' if srv.get('ssh_pass') else '—'}</span></td>
|
<td><span class="badge {'badge-on' if srv.get('ssh_pass') else 'badge-off'}">{'OK' if srv.get('ssh_pass') else '—'}</span></td>
|
||||||
</tr>''' for srv in servers)}
|
</tr>''' for srv in servers)}
|
||||||
|
|||||||
@@ -344,20 +344,40 @@ action_link() {
|
|||||||
ln -s "$PACKAGES_DIR/phobos-$id.tar.gz" "$link_dir/phobos-$id.tar.gz"
|
ln -s "$PACKAGES_DIR/phobos-$id.tar.gz" "$link_dir/phobos-$id.tar.gz"
|
||||||
|
|
||||||
mkdir -p "$WWW_DIR/init"
|
mkdir -p "$WWW_DIR/init"
|
||||||
local script_url="http://${SERVER_PUBLIC_IP_V4}:${HTTP_PORT:-80}/packages/$token/phobos-$id.tar.gz"
|
local panel_port="${HTTP_PORT:-}"
|
||||||
|
if [[ -z "$panel_port" && -f /opt/phobos-panel/.port ]]; then
|
||||||
|
panel_port=$(cat /opt/phobos-panel/.port 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
panel_port="${panel_port:-80}"
|
||||||
|
local primary_url="http://${SERVER_PUBLIC_IP_V4}:${panel_port}/packages/$token/phobos-$id.tar.gz"
|
||||||
|
local fallback_url="http://${SERVER_PUBLIC_IP_V4}:80/packages/$token/phobos-$id.tar.gz"
|
||||||
|
|
||||||
cat > "$WWW_DIR/init/$token.sh" <<EOF
|
cat > "$WWW_DIR/init/$token.sh" <<EOF
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
url="$script_url"
|
urls="$primary_url $fallback_url"
|
||||||
dir="/tmp/phobos_install_\$\$"
|
dir="/tmp/phobos_install_\$\$"
|
||||||
mkdir -p "\$dir"
|
mkdir -p "\$dir"
|
||||||
echo "Downloading..."
|
echo "Downloading..."
|
||||||
|
ok=0
|
||||||
|
for url in \$urls; do
|
||||||
|
rm -f "\$dir/package.tar.gz"
|
||||||
if command -v curl >/dev/null; then
|
if command -v curl >/dev/null; then
|
||||||
curl -L -s -o "\$dir/package.tar.gz" "\$url"
|
curl -L -s -o "\$dir/package.tar.gz" "\$url" 2>/dev/null || continue
|
||||||
else
|
else
|
||||||
wget -q -O "\$dir/package.tar.gz" "\$url"
|
wget -q -O "\$dir/package.tar.gz" "\$url" 2>/dev/null || continue
|
||||||
fi
|
fi
|
||||||
if [ ! -f "\$dir/package.tar.gz" ]; then echo "Download failed"; exit 1; fi
|
if grep -qi '<html' "\$dir/package.tar.gz" 2>/dev/null; then
|
||||||
|
echo "Bad response from \$url (HTML/proxy page), trying next..."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
tar tzf "\$dir/package.tar.gz" >/dev/null 2>&1 || {
|
||||||
|
echo "Bad package from \$url, trying next..."
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ok=1
|
||||||
|
break
|
||||||
|
done
|
||||||
|
[ "\$ok" = "1" ] || { echo "Download failed: no valid package"; exit 1; }
|
||||||
cd "\$dir"
|
cd "\$dir"
|
||||||
tar xzf package.tar.gz
|
tar xzf package.tar.gz
|
||||||
cd "phobos-$id"
|
cd "phobos-$id"
|
||||||
@@ -372,7 +392,9 @@ EOF
|
|||||||
chmod 755 "$PACKAGES_DIR" 2>/dev/null
|
chmod 755 "$PACKAGES_DIR" 2>/dev/null
|
||||||
chmod 644 "$PACKAGES_DIR/phobos-$id.tar.gz" 2>/dev/null
|
chmod 644 "$PACKAGES_DIR/phobos-$id.tar.gz" 2>/dev/null
|
||||||
|
|
||||||
local cmd="curl -s http://${SERVER_PUBLIC_IP_V4}:${HTTP_PORT:-80}/init/$token.sh | sh"
|
local init_primary="http://${SERVER_PUBLIC_IP_V4}:${panel_port}/init/$token.sh"
|
||||||
|
local init_fallback="http://${SERVER_PUBLIC_IP_V4}:80/init/$token.sh"
|
||||||
|
local cmd="tmp=/tmp/phobos-init-\$\$.sh; ok=0; for u in $init_primary $init_fallback; do rm -f \$tmp; (wget -q -O \$tmp \$u || curl -fsSL -o \$tmp \$u) 2>/dev/null || continue; grep -qi '<html' \$tmp && continue; head -1 \$tmp | grep -q '^#!' || continue; sh \$tmp; ok=1; break; done; rm -f \$tmp; [ \$ok -eq 1 ] || echo 'ERROR: install script download failed (got HTML/proxy page or timeout)'"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=================================================="
|
echo "=================================================="
|
||||||
|
|||||||
Reference in New Issue
Block a user