From 78bfc5b408308369856f2d5aa6ecb59a4fa97c1c Mon Sep 17 00:00:00 2001 From: Security Fix Date: Fri, 2 Oct 2026 07:07:28 +0000 Subject: [PATCH] hub: serve the Hub on its own port instead of through Caddy Caddy fronted the Hub at http://sovransystemsos.local, but the Hub already listens on 0.0.0.0:8937 itself, and nothing Caddy added is something it needs: - Not the name. That is avahi's: mDNS advertises a hostname, not a port, so the name resolves wherever the Hub listens. - Not TLS (the site was plain http), not authentication, not cache headers. The header block duplicated NoCacheMiddleware, and its Clear-Site-Data ("cache") overrode the app's stronger ("cache", "storage"). - Not access control, and this is the point. With ports 80/443 forwarded for public services, a Host header on those ports reached the Hub. That second door is how the reported bug happened, and c33457f guards it with an address check instead of closing it. The Hub is now served on port 8937 only, at http://sovransystemsos.local:8937, and Caddy has no site for it. The only thing Caddy answers on 80/443 is the public sites. Caddy keeps Ride The Lightning (:3051) and Mempool (:60847), because those do need it: Sovran_Bitcoin binds both to 127.0.0.1 and RTL's unit is sandboxed to loopback besides, so Caddy is how the local network reaches them. - caddy.nix: no Hub site. Caddy runs wherever RTL and Mempool do, which includes Bitcoin Node Only. There it did not run at all (enable was needsHttpsPorts || extraVhosts != ""), so :3051 and :60847 were open in the firewall with nothing listening. Ports 80/443 still follow needsHttpsPorts alone, so Node Only does not open them. The two sites are written only where their service exists; they were unconditional. - sovran-hub.nix: 8937 follows the new hub.directPort, 60847 follows Mempool. It used to be `[ 8937 60847 ]` on every role, Desktop Only included. - roles.nix: hub.directPort defaults to !roles.desktop: open on Server + Desktop and Bitcoin Node Only, closed on Desktop Only, where the Hub is reached from the machine itself through the desktop window on localhost. - The bind stays 0.0.0.0, which is IPv4 only: with that bind [::1]:8937 is refused and "localhost" falls back to 127.0.0.1. That is on purpose and is now said in the comment. An IPv6 listener would let in clients whose global addresses the Hub cannot tell from a stranger's, which is the question the previous commit declines to answer by guessing. - README, SECURITY.md and two strings in index.html give the new URL. Behaviour changes: the Hub's address gains :8937, and http://sovransystemsos.local on port 80 no longer reaches it. Bitcoin Node Only now runs Caddy. Evaluated with nix eval (nixpkgs as flake.lock pins it, Sovran_Bitcoin at the locked revision), firewall TCP ports per role: c33457f this commit Server + Desktop 22 80 443 3051 8937 60847 22 80 443 3051 8937 Bitcoin Node Only 22 3051 8937 60847 22 3051 8937 60847 (Caddy now runs) Desktop Only 22 8937 60847 22 Port 22 is open on every role although sshd listens on loopback only; the last commit of this series deals with that. The Caddyfile the module really generates (the evaluated generator script, run, then `caddy validate` with Caddy 2.9.1): Node Only gets the two sites and nothing else; Server + Desktop with every domain configured gets the seven domain sites plus :3051 and :60847 and no mention of the Hub; with Bitcoin off there are no local-network sites; Node Only with Bitcoin off and no domains leaves Caddy off. Add tests/test_hub_direct.py and keep tests/test_caddy_lan_only.py for the two sites it still covers. --- README.md | 23 +-- SECURITY.md | 37 ++++- app/sovran_systemsos_web/templates/index.html | 4 +- modules/core/caddy.nix | 84 +++++----- modules/core/roles.nix | 21 +++ modules/core/sovran-hub.nix | 15 +- tests/test_caddy_lan_only.py | 16 +- tests/test_hub_direct.py | 155 ++++++++++++++++++ 8 files changed, 287 insertions(+), 68 deletions(-) create mode 100644 tests/test_hub_direct.py diff --git a/README.md b/README.md index 57158d2..695e4e4 100644 --- a/README.md +++ b/README.md @@ -316,8 +316,8 @@ the tools of your selected mode already in place. Prefer to keep using Windows, macOS, Linux, Android, or iOS? Install Sovran_SystemsOS on a separate computer and let it run quietly on your local network, with or without a monitor. From any other device on the same network, -open a browser, visit `http://sovransystemsos.local`, and manage everything -from [The Sovran Hub](#the-sovran-hub). +open a browser, visit `http://sovransystemsos.local:8937`, and manage +everything from [The Sovran Hub](#the-sovran-hub). Your existing devices stay familiar. Sovran_SystemsOS provides the independent infrastructure behind them. @@ -354,7 +354,7 @@ From one place, the Hub helps you: │ │ │ Windows laptop Phone or tablet Mac or Linux │ │ │ - └──────── Browser: sovransystemsos.local ────┘ + └─────── Browser: sovransystemsos.local:8937 ─┘ │ ▼ ┌──────────────────────────┐ @@ -376,9 +376,10 @@ Keep using the devices you already own. Sovran_SystemsOS becomes the private Bitcoin and digital infrastructure behind them. > **Local access:** the Hub is available at -> `http://sovransystemsos.local` to devices connected to the same local -> network. It is protected by authentication and is not automatically exposed -> to the public internet. +> `http://sovransystemsos.local:8937` to devices connected to the same local +> network (not on Desktop, which publishes nothing). It is protected by +> authentication, answers only your local network, and is not automatically +> exposed to the public internet. --- @@ -536,18 +537,20 @@ Open the Hub directly from the Sovran_SystemsOS desktop, or from any other device on the same local network at: ```text -http://sovransystemsos.local +http://sovransystemsos.local:8937 ``` -Sign in with your Sovran_SystemsOS credentials. +Sign in with your Sovran_SystemsOS credentials. Desktop does not publish the Hub +on the network, so in that mode open it from the desktop.
-If sovransystemsos.local does not open +If sovransystemsos.local:8937 does not open 1. Make sure the Sovran_SystemsOS machine is powered on, and allow it a few minutes to finish starting. 2. Make sure both devices are connected to the same local network, and that - you entered the full address `http://sovransystemsos.local`. + you entered the full address `http://sovransystemsos.local:8937`, + including the `:8937`. 3. Avoid guest Wi-Fi networks, which may prevent devices from seeing one another. 4. Temporarily disconnect any VPN that may interfere with local-network diff --git a/SECURITY.md b/SECURITY.md index fd8f8aa..8b3b340 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -35,21 +35,40 @@ external networks and are outside a “fully offline” model. The local Hub currently uses HTTP. Authentication does not encrypt local network traffic, so use a trusted LAN and avoid public or guest Wi-Fi. -Caddy serves the Hub (`sovransystemsos.local`), Ride The Lightning (port 3051), -and Mempool (port 60847) only to this computer and to clients on your local -network (private, link-local, and VPN addresses), even when ports 80 and 443 are -forwarded to this computer for public services. Other IPv4 clients get the -connection closed. IPv6 global addresses are not filtered. +The Hub is served on port 8937, on its own: Caddy does not front it. Server + +Desktop and Bitcoin Node Only open that port in the firewall, so other devices +on your local network reach the Hub at `http://sovransystemsos.local:8937`. +Forwarding ports 80 and 443 for public services does not put the Hub in front of +the internet, because the only thing Caddy answers on those ports is the public +sites. + +On Desktop Only the Hub is not published at all. It is reachable only from the +machine itself, through the desktop application window on localhost. Desktop +Only is the role most likely to be used away from home, and a root-capable admin +UI has no business listening on a coffee-shop network. +`sovran_systemsOS.hub.directPort = true` in `custom.nix` opens port 8937 if you +do want to reach a Desktop Only Hub from another device. The Hub also checks every client itself, before it shows a login page. It runs as root, so it answers only this computer and the local network (loopback, private, VPN and link-local addresses) and turns everyone else away, however -they reached it. Global IPv6 addresses are turned away too: a laptop on your -network and a stranger on the internet look the same by address alone. If your -devices use addresses outside the local ranges, list their networks in -`sovran_systemsOS.hub.extraLanNetworks` in `custom.nix`; +they reached it. The Hub listens on IPv4 only, so IPv6 clients do not reach it +at all; if that ever changes, global IPv6 addresses would be turned away, +because a laptop on your network and a stranger on the internet look the same +by address alone. If your devices use addresses outside the local ranges, list +their networks in `sovran_systemsOS.hub.extraLanNetworks` in `custom.nix`; `sovran_systemsOS.hub.lanOnly = false` turns the check off. +The check goes by the address a connection comes from. A router that rewrites +that address when it forwards a port makes an outsider look local, so the check +is a second lock and not a reason to forward port 8937: don't. + +Caddy serves Ride The Lightning (port 3051) and Mempool (port 60847) only to +this computer and to clients on your local network (private, link-local, and VPN +addresses), even when ports 80 and 443 are forwarded to this computer for public +services. Other IPv4 clients get the connection closed. IPv6 global addresses +are not filtered. + ### Public services and your home IP address Server + Desktop publishes services under your own domain. The Dynamic DNS diff --git a/app/sovran_systemsos_web/templates/index.html b/app/sovran_systemsos_web/templates/index.html index 45468d5..4bd9a01 100644 --- a/app/sovran_systemsos_web/templates/index.html +++ b/app/sovran_systemsos_web/templates/index.html @@ -264,7 +264,7 @@

Network

LAN…
WAN…
-
sovransystemsos.local
+
sovransystemsos.local:8937
@@ -520,7 +520,7 @@
 

✍️ Write this down now.
- You will need it to log in to your computer
and the Sovran Hub at sovransystemsos.local. + You will need it to log in to your computer
and the Sovran Hub at sovransystemsos.local:8937.