Skip to content

Commit 28cd8e1

Browse files
MTSistemiclaude
andcommitted
dashboard: KVM/Terminal use the browser's host (location.hostname), not a guessed IP
The box has two DHCP addresses on enp4s0 (.24 primary, .40 secondary); guessing the IP server-side picked the wrong one. Now the frontend builds KVM/terminal URLs from location.hostname, and status reports the Host you connected with. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c7a8ad2 commit 28cd8e1

2 files changed

Lines changed: 24 additions & 10 deletions

File tree

apps/dashboard/skillfish-dashboardd

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@ def sysinfo():
191191
return ""
192192
info = {}
193193
info["host"] = sh("hostname")
194-
info["ip"] = sh("hostname -I").split()[0] if sh("hostname -I") else ""
194+
# primary LAN IP = source address of the default route (not just the first of
195+
# `hostname -I`, which can be a secondary/stale or docker/lxc address).
196+
info["ip"] = (sh(r"ip -4 route get 1.1.1.1 2>/dev/null | sed -n 's/.*src \([0-9.]*\).*/\1/p'")
197+
or (sh("hostname -I").split()[0] if sh("hostname -I") else ""))
195198
info["kernel"] = sh("uname -r")
196199
try:
197200
with open("/proc/uptime") as f:
@@ -413,9 +416,9 @@ def kvm_start():
413416
"--web", "/usr/share/novnc", str(KVM_PORT), "localhost:5901"],
414417
kill_pat="websockify --cert")
415418
time.sleep(0.8)
416-
ip = sysinfo().get("ip", "")
417-
return {"ok": True, "url": "https://%s:%d/vnc.html?autoconnect=1&resize=scale&password=%s"
418-
% (ip, KVM_PORT, VNC_PASS), "password": VNC_PASS}
419+
# the frontend builds the URL from the host the browser is already using, so we
420+
# never advertise a wrong/secondary IP — just hand back the port + password.
421+
return {"ok": True, "port": KVM_PORT, "password": VNC_PASS}
419422

420423

421424
def kvm_stop():
@@ -435,8 +438,7 @@ def terminal_start():
435438
"-c", "skillfish:" + TTYD_TOKEN, "-W", "-t", "fontSize=14", "--", "su", "-", u],
436439
kill_pat="ttyd --ssl")
437440
time.sleep(0.8)
438-
ip = sysinfo().get("ip", "")
439-
return {"ok": True, "url": "https://%s:%d" % (ip, TTYD_PORT), "user": "skillfish", "token": TTYD_TOKEN}
441+
return {"ok": True, "port": TTYD_PORT, "user": "skillfish", "token": TTYD_TOKEN}
440442

441443

442444
def terminal_stop():
@@ -518,7 +520,9 @@ class Handler(BaseHTTPRequestHandler):
518520
if path == "/api/status":
519521
if not self._user():
520522
return self._json(401, {"error": "auth"})
521-
return self._json(200, sysinfo())
523+
s = sysinfo()
524+
s["you"] = (self.headers.get("Host", "") or "").split(":")[0] # host you actually reached us on
525+
return self._json(200, s)
522526
if path == "/api/telemetry":
523527
if not self._guard("telemetry"):
524528
return

apps/dashboard/web/app.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const RENDER = {
9696
const s = await (await api("/api/status")).json();
9797
const row = (a, b) => `<div class="r"><span>${a}</span><span>${b || "–"}</span></div>`;
9898
$("#srows", card).innerHTML =
99-
row("Host", s.host) + row("IP", s.ip) + row("Kernel", s.kernel) +
99+
row("Sei connesso a", s.you) + row("Host", s.host) + row("IP (rotta)", s.ip) + row("Kernel", s.kernel) +
100100
row("Uptime", s.uptime) + row("CU attive", s.cu) +
101101
row("RAM", s.ram_used_mb ? `${s.ram_used_mb} / ${s.ram_total_mb} MB` : "") +
102102
row("Disco /", s.disk_used ? `${s.disk_used} / ${s.disk_total} (${s.disk_pct})` : "") +
@@ -177,15 +177,25 @@ const RENDER = {
177177
'<div class="stub" id="kvmi" style="margin-top:8px">Schermo, tastiera e mouse della scheda nel browser.</div>';
178178
$("#kvmgo", card).onclick = async () => {
179179
const j = await action("/api/kvm/start", {}, "Desktop pronto");
180-
if (j && j.url) { window.open(j.url, "_blank"); $("#kvmi", card).innerHTML = "Aperto in nuova scheda. Password VNC: <b>" + j.password + "</b>"; }
180+
if (j && j.port) {
181+
const url = `https://${location.hostname}:${j.port}/vnc.html?autoconnect=1&resize=scale&password=${encodeURIComponent(j.password)}`;
182+
window.open(url, "_blank");
183+
$("#kvmi", card).innerHTML = 'Aperto in nuova scheda. Se appare un avviso certificato, accettalo (porta ' + j.port + ').';
184+
}
181185
};
182186
},
183187
terminal(card) {
184188
card.innerHTML = '<h3>⌨️ Terminale</h3><div class="brow"><button class="dbtn" id="tgo">▶ Apri terminale</button></div>' +
185189
'<div class="stub" id="ti" style="margin-top:8px">Shell della scheda nel browser.</div>';
186190
$("#tgo", card).onclick = async () => {
187191
const j = await action("/api/terminal/start", {}, "Terminale pronto");
188-
if (j && j.url) { window.open(j.url, "_blank"); $("#ti", card).innerHTML = "Aperto. Login: utente <b>" + j.user + "</b> · token <b>" + j.token + "</b>"; }
192+
if (j && j.port) {
193+
const url = `https://${location.hostname}:${j.port}`;
194+
window.open(url, "_blank");
195+
$("#ti", card).innerHTML = 'Aperto su <b>' + location.hostname + ':' + j.port + '</b>.<br>' +
196+
'Accetta l\'eventuale avviso certificato, poi nel login inserisci:<br>' +
197+
'utente <b>' + j.user + '</b> · password <b style="user-select:all">' + j.token + '</b>';
198+
}
189199
};
190200
},
191201
_stub(card, mod) {

0 commit comments

Comments
 (0)