docs, hub, installer: say Server + Desktop makes the home IP public
Server + Desktop publishes services under the operator's own domain, and the DNS record for that domain points at the home connection, so anyone can look up the home IP address. None of the places that offer Server + Desktop said so. - README: new section "Server + Desktop and your home IP address" (what becomes public, what does not, the alternatives, and what happens technically), plus a note on the role table and in the security overview. - SECURITY.md: a matching section, the consequence noted next to "Public web services exposed only when enabled by the operator", and the supported versions row no longer pins 1.0.x. - ISO installer: the Server + Desktop role card ends with the warning. - Hub: the domain setup text (onboarding, feature setup and domain reconfiguration share renderDomainNeedsHtml) and the upgrade dialog carry the same notice. - Add tests/test_exposure_guards.py. It fails if one of these places loses the notice or the README anchor stops resolving.
This commit is contained in:
@@ -202,7 +202,7 @@ Bitcoin and self-hosting infrastructure runs on the machine.
|
||||
|---|---|---|
|
||||
| **Desktop** | Everyday users and computers with modest hardware | Sparrow, Bisq, and Bisq 2 for self-custody and peer-to-peer Bitcoin use |
|
||||
| **Node** | People ready to verify and operate their own Bitcoin infrastructure | Everything in Desktop, plus the full Bitcoin stack: Bitcoin Core, Electrs, LND, Ride The Lightning, BTCPay Server, and wallet-to-node connections |
|
||||
| **Server + Desktop** | Bitcoiners who want the same sovereignty over their communications, cloud, passwords, and web services | The complete Node stack, plus the private self-hosted services |
|
||||
| **Server + Desktop** | Bitcoiners who want the same sovereignty over their communications, cloud, passwords, and web services | The complete Node stack, plus the private self-hosted services. **Makes your home IP address public:** [read this first](#server--desktop-and-your-home-ip-address) |
|
||||
|
||||
**Desktop: start with your keys.** Desktop is not a reduced or Bitcoin-free
|
||||
edition. It is a complete, private everyday computer with a clean GNOME
|
||||
@@ -237,6 +237,66 @@ communications, identity, and services.
|
||||
> provider allows port forwarding. Most home routers and providers already
|
||||
> support this. If you are unsure, a quick search for your router model and
|
||||
> "port forwarding" will usually turn up a step-by-step guide.
|
||||
>
|
||||
> **This mode also makes your home IP address public.** Read
|
||||
> [what that means](#server--desktop-and-your-home-ip-address) before you
|
||||
> choose it.
|
||||
|
||||
### Server + Desktop and your home IP address
|
||||
|
||||
> **⚠️ Server + Desktop makes your home IP address public.**
|
||||
> Public services need a domain name that points at your home internet
|
||||
> connection. When you finish the guided domain setup, Sovran_SystemsOS puts
|
||||
> your home's public IP address in a Dynamic DNS record at
|
||||
> [Njal.la](https://njal.la) and keeps it up to date, and you forward ports 80
|
||||
> and 443 on your router to this computer. From then on:
|
||||
>
|
||||
> - **Anyone can look up your domain and see your home IP address.** An IP
|
||||
> address typically reveals your internet provider and your approximate
|
||||
> location, and it ties everything you publish on that domain to your home
|
||||
> connection.
|
||||
> - **Domain privacy does not hide it.** Registrar privacy protects the
|
||||
> registrant's identity, not the IP address in your DNS records.
|
||||
> - **Your connection is open to the whole internet on those ports.** Scanners
|
||||
> and bots constantly probe public IP addresses, so expect automated probing
|
||||
> and login attempts against every service you publish.
|
||||
> - **Your service names are discoverable.** Public HTTPS certificates are
|
||||
> listed in public Certificate Transparency logs, so hostnames such as
|
||||
> `vault.yourdomain.com` can be found, and then resolved to your IP address,
|
||||
> even if you never share them.
|
||||
|
||||
Nothing is published until you finish domain setup and port forwarding, but that
|
||||
setup is the point of this mode, so assume your IP address will be public.
|
||||
**Desktop** publishes nothing. **Node** publishes nothing unless you turn on a
|
||||
feature that needs a domain: *Put BTCPay Server Online* or *Lightning Wallet
|
||||
Connections*.
|
||||
|
||||
**If you do not want your home IP address to be public,** choose Desktop or
|
||||
Node. Advanced users can put a VPS, reverse proxy, or tunnel in front of their
|
||||
services so DNS points there instead of at their home. Sovran_SystemsOS does not
|
||||
set this up for you, and the Hub's domain checks currently expect DNS to point
|
||||
at your home IP address.
|
||||
|
||||
<details>
|
||||
<summary><strong>What happens technically</strong></summary>
|
||||
|
||||
- You create a **Dynamic** DNS record at Njal.la and paste its update command
|
||||
into the Hub. The Hub only accepts `njal.la` update URLs.
|
||||
- The `sovran-ddns-update` timer asks Njal.la to point your record at the
|
||||
address the request came from. It does this right after you save a domain,
|
||||
two minutes after boot, and then every 15 minutes.
|
||||
- Njal.la reports that address back, and Sovran_SystemsOS keeps it for Element
|
||||
calling and the Hub. Nothing else looks up your public IP address: no STUN
|
||||
server, public DNS resolver, or "what is my IP" service is involved. See
|
||||
`modules/core/njalla.nix`.
|
||||
- Once a service that needs a domain is turned on, the firewall opens TCP and
|
||||
UDP ports 80 and 443 for Caddy, which requests public HTTPS certificates for
|
||||
the domains you configure. See `modules/core/caddy.nix`.
|
||||
- Optional features can need more ports. Element calling, for example, needs
|
||||
TCP 7881 and UDP 3478, 7882, and 40000–40099. The Hub lists the ports each
|
||||
feature needs.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
@@ -730,7 +790,9 @@ Sovran_SystemsOS uses layered controls:
|
||||
- Separate service users, systemd sandboxing, and loopback bindings where practical
|
||||
- Tor enforcement for supported Bitcoin services
|
||||
- Restricted, time-limited support access with scoped `sudo`
|
||||
- Operator-controlled public service exposure
|
||||
- Operator-controlled public service exposure (Server + Desktop
|
||||
[makes your home IP address public](#server--desktop-and-your-home-ip-address)
|
||||
once you set up a domain)
|
||||
|
||||
See [`SECURITY.md`](SECURITY.md) for the threat model, limitations, reporting,
|
||||
and operator guidance. No operating system can protect funds after recovery
|
||||
|
||||
+20
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
| Release | Supported |
|
||||
|---|:---:|
|
||||
| Latest `1.0.x` stable release | Yes |
|
||||
| Latest stable release | Yes |
|
||||
| `main` / `staging-dev` | Development only |
|
||||
| Older than `1.0.0` | No |
|
||||
|
||||
@@ -35,6 +35,23 @@ 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.
|
||||
|
||||
### Public services and your home IP address
|
||||
|
||||
Server + Desktop publishes services under your own domain. The Dynamic DNS
|
||||
record at Njal.la then points at your home's public IP address, which anyone
|
||||
can look up (domain privacy does not hide it), and ports 80 and 443 are open
|
||||
to the whole internet. Public HTTPS certificates also list your service
|
||||
hostnames in Certificate Transparency logs. Desktop publishes nothing. Node
|
||||
publishes nothing unless *Put BTCPay Server Online* or *Lightning Wallet
|
||||
Connections* is on. See
|
||||
[Server + Desktop and your home IP address](README.md#server--desktop-and-your-home-ip-address)
|
||||
for what this means and the alternatives.
|
||||
|
||||
Sovran_SystemsOS does not ask a STUN server, public DNS resolver, or “what is
|
||||
my IP” service for your address. The DDNS update asks Njal.la to use the
|
||||
address the request came from, and the address Njal.la reports back is the one
|
||||
Element calling and the Hub use.
|
||||
|
||||
### Bitcoin stack
|
||||
|
||||
Bitcoin and Lightning modules are maintained in the standalone
|
||||
@@ -64,7 +81,8 @@ change both the system and local configuration.
|
||||
- Separate service users and systemd sandboxing where supported
|
||||
- Administrative service ports bound to loopback where practical
|
||||
- Tor enforced for supported Bitcoin traffic and onion services
|
||||
- Public web services exposed only when enabled by the operator
|
||||
- Public web services exposed only when enabled by the operator (this makes
|
||||
your home IP address public)
|
||||
|
||||
Tor reduces network exposure for configured Bitcoin services. It is not a
|
||||
guarantee against every IP leak, application bug, or traffic-analysis attack.
|
||||
|
||||
@@ -43,6 +43,11 @@ function renderDomainNeedsHtml(opts) {
|
||||
+ '<a href="https://njal.la" target="_blank" rel="noopener noreferrer" style="color:var(--accent-color);">Njal.la</a>'
|
||||
+ " and connecting your services. Just follow the steps below.</p>";
|
||||
}
|
||||
// Every variant above ends with a domain that points at the user's home
|
||||
// connection. Say what that publishes (README: "Server + Desktop and your
|
||||
// home IP address").
|
||||
html += "<p>⚠️ <strong>Heads-up:</strong> your domain points at your home internet connection, "
|
||||
+ "so anyone can look up your home IP address. Domain privacy does not hide it.</p>";
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
@@ -476,6 +476,10 @@
|
||||
<li>To make your services available outside your home, complete one router task: forward ports <strong>80 and 443</strong> to this computer</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p class="support-desc">
|
||||
⚠️ <strong>Heads-up:</strong> your domain points at your home internet connection,
|
||||
so anyone can look up your home IP address. Domain privacy does not hide it.
|
||||
</p>
|
||||
<p class="support-desc">
|
||||
The Hub guides you through every step.
|
||||
</p>
|
||||
|
||||
+1
-1
@@ -471,7 +471,7 @@ class InstallerWindow(Adw.ApplicationWindow):
|
||||
# Role cards
|
||||
roles = [
|
||||
("Server + Desktop",
|
||||
"Full sovereignty: host your own websites, cloud, chat, passwords, and Bitcoin services instead of relying on Big Tech. Sovran_SystemsOS walks you through getting your domain from Njal.la and connecting everything. One router task is required: forward ports 80 and 443 to this computer.",
|
||||
"Full sovereignty: host your own websites, cloud, chat, passwords, and Bitcoin services instead of relying on Big Tech. Sovran_SystemsOS walks you through getting your domain from Njal.la and connecting everything. One router task is required: forward ports 80 and 443 to this computer. Heads-up: this makes your home IP address public.",
|
||||
"Server+Desktop"),
|
||||
("Desktop Only",
|
||||
"A beautiful, easy-to-use desktop without the background server applications.",
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
"""Guards for the home-IP warnings.
|
||||
|
||||
Server + Desktop publishes the home IP address (the domain points at it), so every
|
||||
place that offers Server + Desktop must say so, and the README section they point
|
||||
at must exist.
|
||||
|
||||
These read the shipped source files like the nix-file checks in test_security.py:
|
||||
nothing is run and nothing touches the network.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import unittest
|
||||
|
||||
_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
_PHRASE = "home ip address"
|
||||
|
||||
|
||||
def _read(*parts):
|
||||
with open(os.path.join(_ROOT, *parts), encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def _github_slug(heading):
|
||||
slug = re.sub(r"[^\w\- ]", "", heading.strip().lower())
|
||||
return slug.replace(" ", "-")
|
||||
|
||||
|
||||
class HomeIpWarnings(unittest.TestCase):
|
||||
|
||||
def test_installer_role_card(self):
|
||||
src = _read("iso", "installer.py")
|
||||
card = re.search(r'\("Server \+ Desktop",\s*"((?:[^"\\]|\\.)*)"', src, re.S)
|
||||
self.assertIsNotNone(card, "Server + Desktop role card not found")
|
||||
self.assertIn(_PHRASE, card.group(1).lower())
|
||||
|
||||
def test_hub_domain_setup_text(self):
|
||||
# domain-prereqs.js is the single source for onboarding, feature setup
|
||||
# and domain reconfiguration; the notice must follow every variant.
|
||||
js = _read("app", "sovran_systemsos_web", "static", "js", "domain-prereqs.js")
|
||||
body = js[js.index("function renderDomainNeedsHtml"):]
|
||||
body = body[:body.index("\n}\n")]
|
||||
self.assertIn(_PHRASE, body.lower())
|
||||
self.assertGreater(body.lower().index(_PHRASE), body.rindex("} else {"),
|
||||
"the notice must come after the last variant, not inside one")
|
||||
|
||||
def test_hub_upgrade_dialog(self):
|
||||
html = _read("app", "sovran_systemsos_web", "templates", "index.html")
|
||||
dialog = html[html.index('id="upgrade-modal"'):html.index("Security Reset overlay")]
|
||||
self.assertIn(_PHRASE, " ".join(dialog.lower().split()))
|
||||
|
||||
def test_readme_and_security_policy(self):
|
||||
self.assertIn(_PHRASE, _read("README.md").lower())
|
||||
self.assertIn(_PHRASE, " ".join(_read("SECURITY.md").lower().split()))
|
||||
|
||||
def test_links_to_the_readme_section_resolve(self):
|
||||
readme = _read("README.md")
|
||||
slugs = {_github_slug(m.group(2))
|
||||
for m in re.finditer(r"^(#{1,6})\s+(.+?)\s*$", readme, re.M)}
|
||||
links = re.findall(r"\]\(#(server--desktop[^)]*)\)", readme)
|
||||
links += re.findall(r"README\.md#(server--desktop[^)\s]*)", _read("SECURITY.md"))
|
||||
self.assertTrue(links, "expected links to the home-IP section")
|
||||
for anchor in links:
|
||||
self.assertIn(anchor, slugs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user