From 837596a9e7622521f4aaa06dddb24f366fcf9e59 Mon Sep 17 00:00:00 2001 From: Roland Tannous Date: Fri, 13 Feb 2026 10:23:12 +0000 Subject: [PATCH 1/2] feat: show external IP in startup banner --- studio/backend/run.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/studio/backend/run.py b/studio/backend/run.py index 8945d438bb..36d4653e21 100644 --- a/studio/backend/run.py +++ b/studio/backend/run.py @@ -57,11 +57,26 @@ def run_server( time.sleep(3) if not silent: + # Resolve actual IP when binding to 0.0.0.0 + display_host = host + if host == "0.0.0.0": + import socket + try: + # UDP connect trick — gets the machine's outbound IP without sending data + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + display_host = s.getsockname()[0] + s.close() + except Exception: + display_host = "localhost" + print("") print("=" * 50) - print(f"🦥 Unsloth UI Backend is running on port {port}") - print(f" API: http://{host}:{port}/api") - print(f" Health: http://{host}:{port}/api/health") + print(f"🦥 Unsloth Studio is running on port {port}") + print(f" Local: http://localhost:{port}") + print(f" External: http://{display_host}:{port}") + print(f" API: http://{display_host}:{port}/api") + print(f" Health: http://{display_host}:{port}/api/health") print("=" * 50) return app From 5f155010f6c82cbad12f0a1178606d39be3adaa8 Mon Sep 17 00:00:00 2001 From: Roland Tannous Date: Fri, 13 Feb 2026 10:28:20 +0000 Subject: [PATCH 2/2] read external ips with fallback to standard notation 0.0.0.0 --- cli/commands/ui.py | 4 ++- studio/backend/run.py | 64 +++++++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/cli/commands/ui.py b/cli/commands/ui.py index aee2d21d08..6eaeeb793e 100644 --- a/cli/commands/ui.py +++ b/cli/commands/ui.py @@ -15,7 +15,9 @@ def ui( from studio.backend.run import run_server if not silent: - typer.echo(f"Starting Unsloth UI on http://{host}:{port}") + from studio.backend.run import _resolve_external_ip + display_host = _resolve_external_ip() if host == "0.0.0.0" else host + typer.echo(f"Starting Unsloth Studio on http://{display_host}:{port}") run_server( host=host, diff --git a/studio/backend/run.py b/studio/backend/run.py index 36d4653e21..3567401feb 100644 --- a/studio/backend/run.py +++ b/studio/backend/run.py @@ -11,6 +11,51 @@ if str(backend_dir) not in sys.path: sys.path.insert(0, str(backend_dir)) +def _resolve_external_ip() -> str: + """ + Resolve the machine's external IP address. + + Tries (in order): + 1. GCE metadata server (instant, works on Google Cloud VMs) + 2. ifconfig.me (works anywhere with internet) + 3. LAN IP via UDP socket trick (fallback) + """ + import urllib.request + import socket + + # 1. Try GCE metadata server (responds in <10ms on GCE, times out fast elsewhere) + try: + req = urllib.request.Request( + "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip", + headers={"Metadata-Flavor": "Google"}, + ) + with urllib.request.urlopen(req, timeout=1) as resp: + ip = resp.read().decode().strip() + if ip: + return ip + except Exception: + pass + + # 2. Try public IP service + try: + with urllib.request.urlopen("https://ifconfig.me", timeout=3) as resp: + ip = resp.read().decode().strip() + if ip: + return ip + except Exception: + pass + + # 3. Fallback: LAN IP via UDP socket trick + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + ip = s.getsockname()[0] + s.close() + return ip + except Exception: + return "0.0.0.0" + + def run_server( host: str = "0.0.0.0", port: int = 8000, @@ -57,26 +102,15 @@ def run_server( time.sleep(3) if not silent: - # Resolve actual IP when binding to 0.0.0.0 - display_host = host - if host == "0.0.0.0": - import socket - try: - # UDP connect trick — gets the machine's outbound IP without sending data - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.connect(("8.8.8.8", 80)) - display_host = s.getsockname()[0] - s.close() - except Exception: - display_host = "localhost" + display_host = _resolve_external_ip() if host == "0.0.0.0" else host print("") print("=" * 50) print(f"🦥 Unsloth Studio is running on port {port}") - print(f" Local: http://localhost:{port}") + print(f" Local: http://localhost:{port}") print(f" External: http://{display_host}:{port}") - print(f" API: http://{display_host}:{port}/api") - print(f" Health: http://{display_host}:{port}/api/health") + print(f" API: http://{display_host}:{port}/api") + print(f" Health: http://{display_host}:{port}/api/health") print("=" * 50) return app