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, andc33457fguards 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:c33457fthis 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.
This commit is contained in:
+45
-39
@@ -14,13 +14,48 @@ let
|
||||
|| config.sovran_systemsOS.features.haven
|
||||
|| config.sovran_systemsOS.features."nwc-wallets"
|
||||
|| config.sovran_systemsOS.features.element-calling;
|
||||
|
||||
# RTL and Mempool listen on loopback only: Sovran_Bitcoin binds them to
|
||||
# 127.0.0.1, and RTL's unit is sandboxed to loopback besides. Caddy is how
|
||||
# the local network reaches them (:3051 and :60847), so it has to run
|
||||
# wherever they do. That includes Bitcoin Node Only, which has no
|
||||
# domain-based service and so no other reason to run Caddy.
|
||||
#
|
||||
# The Hub is not one of these. It listens on 0.0.0.0:8937 itself, so it is
|
||||
# served on its own port rather than through Caddy: the one service that
|
||||
# runs as root has nothing in front of it that it does not need, and the
|
||||
# public sites on ports 80/443 cannot be asked for it by Host header.
|
||||
servesRtl = config.sovran_systemsOS.services.bitcoin;
|
||||
servesMempool = servesRtl && config.sovran_systemsOS.features.mempool;
|
||||
|
||||
caddyEnabled = needsHttpsPorts || extraVhosts != "" || servesRtl;
|
||||
|
||||
# Sites for the local network, one per loopback-only service. Written after
|
||||
# the public domain sites; each exists only where its service does.
|
||||
bitcoinUiSites =
|
||||
lib.optionalString servesRtl ''
|
||||
|
||||
:3051 {
|
||||
import sovran_lan_only
|
||||
reverse_proxy :3050
|
||||
encode gzip zstd
|
||||
}
|
||||
''
|
||||
+ lib.optionalString servesMempool ''
|
||||
|
||||
:60847 {
|
||||
import sovran_lan_only
|
||||
reverse_proxy :60845
|
||||
encode gzip zstd
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
services.caddy = {
|
||||
# Only enable Caddy when at least one domain-based service needs it or
|
||||
# the operator has defined custom vhosts. This prevents Caddy from
|
||||
# running on Desktop Only installs that have no web services configured.
|
||||
enable = needsHttpsPorts || extraVhosts != "";
|
||||
# Caddy runs when a domain-based service needs it, when the operator has
|
||||
# defined custom vhosts, or when it is the way to reach RTL and Mempool.
|
||||
# Desktop Only has none of those, so Caddy stays off there.
|
||||
enable = caddyEnabled;
|
||||
user = "caddy";
|
||||
group = "root";
|
||||
};
|
||||
@@ -90,7 +125,7 @@ EOF
|
||||
''}
|
||||
|
||||
# ── LAN-only guard ──────────────────────────────
|
||||
# The Hub, RTL and Mempool sites below are meant for this home network
|
||||
# The RTL and Mempool sites below are meant for this home network
|
||||
# only. Forwarding ports 80/443 on the router also lets other clients
|
||||
# reach Caddy, so these sites check where a request comes from, not just
|
||||
# which Host it asks for. Anyone else gets the connection closed.
|
||||
@@ -222,40 +257,11 @@ $LIGHTNING {
|
||||
EOF
|
||||
fi
|
||||
|
||||
# ── Sovran Hub (LAN access via mDNS) ────────────
|
||||
cat >> /run/caddy/Caddyfile <<EOF
|
||||
|
||||
http://sovransystemsos.local {
|
||||
import sovran_lan_only
|
||||
reverse_proxy localhost:8937
|
||||
header {
|
||||
Clear-Site-Data "\"cache\""
|
||||
Cache-Control "no-store, no-cache, must-revalidate, max-age=0"
|
||||
Pragma "no-cache"
|
||||
Expires "0"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# ── RTL (LAN access) ────────────────────────────
|
||||
cat >> /run/caddy/Caddyfile <<EOF
|
||||
|
||||
:3051 {
|
||||
import sovran_lan_only
|
||||
reverse_proxy :3050
|
||||
encode gzip zstd
|
||||
}
|
||||
EOF
|
||||
|
||||
# ── Mempool (LAN access) ────────────────────────
|
||||
cat >> /run/caddy/Caddyfile <<EOF
|
||||
|
||||
:60847 {
|
||||
import sovran_lan_only
|
||||
reverse_proxy :60845
|
||||
encode gzip zstd
|
||||
}
|
||||
EOF
|
||||
# ── RTL and Mempool (local network) ─────────────
|
||||
# Only where those services run; see bitcoinUiSites above.
|
||||
cat >> /run/caddy/Caddyfile <<'LAN_SITES_EOF'
|
||||
${bitcoinUiSites}
|
||||
LAN_SITES_EOF
|
||||
|
||||
# ── Custom vhosts from custom.nix ──────────────
|
||||
cat >> /run/caddy/Caddyfile <<'CUSTOM_VHOSTS_EOF'
|
||||
|
||||
Reference in New Issue
Block a user