Restructures /docs/ by reader purpose (tutorials, how-to, reference, design), adds the new-user-progression and operator-recipe content the prior layout lacked, runs an accuracy pass against current source across the pre-existing design docs, and rewrites the gateway feature-set documentation end-to-end around its actual operational profile (a niche feature designed for systems already serving DHCP/DNS to a LAN, with two independent halves — outbound LAN→mesh, inbound mesh→LAN — sharing one nftables table, one binary, and one control socket). Top-level README and getting-started rewritten around two equally-weighted deployment modes (overlay on existing IP networks; ground-up over non-IP transports). ## Additions - 11 new tutorials in docs/tutorials/: an 8-step new-user progression from single-daemon test-mesh peering through to a ground-up two-device mesh, an IPv6-adapter side-trip walkthrough, an Advanced Tutorials index, and a hand-held OpenWrt walk-through for fips-gateway deployment that exercises both halves of the feature. - 12 new how-tos in docs/how-to/: firewall activation, Nostr discovery (resolve / advertise / open across five scenarios), Tor onion (directory + control_port modes), UDP buffer tuning, unprivileged-user setup, persistent identity, host aliases, Bluetooth LE peering, MTU diagnostics, manual Linux-host gateway deployment (covers both halves), gateway troubleshooting (organised by half), and a section index. - 9 new reference docs in docs/reference/: configuration, wire formats, control-socket protocol, four CLI references (fips, fipsctl, fipstop, fips-gateway), security posture matrix, and Nostr events catalog. Configuration and wire-formats are renamed-and-extended from prior design/ versions; the other seven are net-new. - 6 new design docs: fips-concepts, fips-architecture, and fips-prior-work split out of the deleted fips-intro.md; consolidated fips-mmp and fips-mtu aggregations; and a new generic port-advertisement-and-nat-traversal doc (Nostr-signaled port advertisement plus UDP NAT-traversal protocol, FIPS as an example implementation, suitable for eventual NIP submission). - Top-level docs/getting-started.md walking through the binary-installer-only Install story. - packaging/common/hosts pre-populated with the eight public test-mesh nodes so shortnames resolve out of the box on every fresh install. ## Changes - 23 wire-format diagrams relocated to reference/diagrams/ alongside the wire-formats move. - 4 design diagrams corrected against source code (fips-protocol-stack, fips-identity-derivation, fips-coordinate-discovery, fips-routing-decision). - 10 pre-existing design docs reconciled with current source. Numeric corrections: stale link-MMP report bounds (now [1s, 5s] with 200 ms cold-start floor); UDP default MTU (now 1280, IPv6 minimum); node_addr formula (SHA-256(pubkey)[..16]); Noise patterns (IK at link, XK at session); peer-ACL semantics (strict allowlist requires ALL in peers.deny); daemon DNS upstream ([::1]:5354); on-the-wire bloom-filter size (1,071 bytes); obsolete Cargo-feature references (PR #79 dropped them) removed. - Transport framing tightened across the docs: TCP is for UDP-filtered networks (not NAT traversal); Tor is a deployment mode (not failover); WebSocket dropped (not a shipped FIPS transport); WiFi promoted to Implemented via Ethernet in infrastructure mode; classic-Bluetooth row removed (BLE is the only Bluetooth-mode transport). - docs/design/fips-gateway.md rewritten end-to-end to lead with the niche-feature framing and the two-halves structure. Title moved from "FIPS Outbound LAN Gateway" to "FIPS Gateway"; architecture section describes the common machinery (the fips-gateway service, the nftables table, the control socket) before splitting into separate "Outbound Half" and "Inbound Half" sections of equal weight; security considerations split per-half; no Future Work section (speculative directions live in the project tracker, not in protocol design docs). Inbound port forwarding is a first-class half rather than a buried "Implemented Extensions" subsection. - Gateway terminology unified across all gateway docs as a separate Linux service running alongside the fips daemon (its own systemd unit / OpenWrt init script). Container- pattern terms (sidecar) are reserved for the Docker/Kubernetes sidecar deployment examples — the testing/sidecar/ tree, examples/k8s-sidecar/, examples/sidecar-nostr-relay/, examples/wireguard-sidecar-macos/, and the related CHANGELOG / top-level README entries — where the term carries its standard container meaning. - Net-new design body content: rekey section in fips-mesh-layer (Noise IK msg1/msg2 over the established link, K-bit cutover, drain window, smaller-NodeAddr-wins tie-breaker on dual-init); Mesh Size Estimation and Antipoison FPR Cap sections in fips-bloom-filters; Mesh-Interface Query Filter subsection in fips-ipv6-adapter; failure-suppression knobs and clock- skew tolerance in fips-nostr-discovery; loop-rejection and mid-chain ancestor swap added to spanning-tree propagation / stability rules; Priority Chain in fips-mesh-operation renumbered to match the routing-decision diagram. - Top-level README: dropped the stale nostr-discovery cargo-feature parenthetical. docs/README.md and the four section READMEs (tutorials, how-to, reference, design) refreshed for the new structure; index rows reflect both halves of the gateway feature and the new fips-gateway CLI reference. - Cargo.toml [package.metadata.deb] assets path updated for the fips-security.md move; .gitignore /reference/ rule anchored to repo root so docs/reference/ is trackable. - packaging/openwrt-ipk/files/etc/fips/fips.yaml configuration-doc URL updated to the new docs/reference/configuration.md location. ## Deletions - docs/design/fips-intro.md (split into the three new intro design docs). - docs/design/document-relationships.svg (orphan, no longer referenced). - docs/proposals/ tree removed; the only proposal it contained (the Nostr UDP hole-punch protocol) was rewritten as the new generic design/port-advertisement-and-nat-traversal.md.
7.9 KiB
Deploy a Tor Onion Service for FIPS
This guide covers running a Tor onion service that accepts inbound FIPS peer connections.
For the Tor transport's design and the bridge-node pattern (running
Tor and UDP simultaneously), see
../design/fips-transport-layer.md.
For the full transports.tor.* config knob inventory, see
../reference/configuration.md.
Inbound modes
FIPS supports two inbound Tor modes. (A third mode, socks5, is
outbound-only and not covered here.)
directorymode (recommended). Tor manages the onion service viaHiddenServiceDirandHiddenServicePortdirectives intorrc. FIPS reads the resulting.onionhostname from a file and binds a local TCP listener for Tor to forward inbound connections to. No control-port interaction is required, which makes this mode compatible with Tor'sSandbox 1seccomp-bpf hardening.torrcrequires:HiddenServiceDir+HiddenServicePort.
control_portmode. FIPS speaks to Tor's control port to create an ephemeral onion service at startup (ADD_ONION). The onion key lives only for the lifetime of the FIPS daemon's control-port session. This mode is incompatible withSandbox 1— the sandbox forbids control-port-driven onion service management.torrcrequires:ControlPort(typically the Unix socket/run/tor/control) and a usable auth method (CookieAuthentication 1is the common choice).
Pick directory unless you have a specific reason to prefer
control_port. The rest of this guide covers directory mode
end-to-end.
Prerequisites
- Tor daemon installed and running (Debian/Ubuntu:
apt install tor) - FIPS daemon configured and able to start
- Operator access to
/etc/tor/torrc(or a drop-in under/etc/tor/torrc.d/)
Step 1: Configure Tor's HiddenServiceDir
Add the following to /etc/tor/torrc:
HiddenServiceDir /var/lib/tor/fips
HiddenServicePort 8443 127.0.0.1:8444
HiddenServiceDir tells Tor where to store the onion service's
private key and hostname file. HiddenServicePort declares that
inbound TCP traffic to port 8443 of the onion address should be
forwarded to 127.0.0.1:8444 on the local host — that is where FIPS
will bind its listener.
The external port (8443 here) is what peers will connect to over
Tor; the internal target (127.0.0.1:8444) is purely local and is
not directly reachable from the network.
Step 2: Reload Tor and read the onion hostname
sudo systemctl reload tor@default # or `tor` on systems without instance support
After Tor processes the new config, the hostname file appears:
sudo cat /var/lib/tor/fips/hostname
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion
Tor regenerates the onion key only on first run (or if you remove
HiddenServiceDir). The hostname value is stable across daemon
restarts as long as HiddenServiceDir is preserved.
Step 3: Verify HiddenServiceDir permissions
The directory must be readable only by the Tor user (Tor refuses to start otherwise):
ls -la /var/lib/tor/fips
# drwx------ debian-tor debian-tor ...
With the shipped Debian systemd unit, FIPS runs as root and reads
the hostname file directly — no permission adjustment is needed.
Non-default deployments
If you run FIPS as an unprivileged user (custom packaging,
hardened deployment, etc.), the FIPS daemon user needs read access
to hostname. Options:
- Add the FIPS user to the
debian-torgroup and loosen group read onHiddenServiceDir(Tor still requires the directory itself to be0700, so this typically means makinghostnameitself group-readable rather than the directory). - Read
hostnameonce at startup as root, then drop privileges. - Copy the hostname into a path the FIPS user can read, refreshed whenever the onion key changes.
Step 4: Configure the FIPS Tor transport
In /etc/fips/fips.yaml, configure transports.tor with mode: directory:
transports:
tor:
mode: directory
socks5_addr: "127.0.0.1:9050"
connect_timeout_ms: 120000
mtu: 1400
advertised_port: 8443
directory_service:
hostname_file: "/var/lib/tor/fips/hostname"
bind_addr: "127.0.0.1:8444"
The bind_addr must match the target of the HiddenServicePort
directive in torrc. The hostname_file path must match
HiddenServiceDir plus /hostname.
advertised_port is the virtual onion port peers dial — i.e. the
first number on the HiddenServicePort line, not the local
target. The default is 443; this guide uses 8443 on both sides
to match the HiddenServicePort 8443 127.0.0.1:8444 example
above. Setting this explicitly is important if you ever flip
advertise_on_nostr: true: the published advert otherwise
defaults to tor:<hash>.onion:443, which won't match the actual
onion port.
The socks5_addr is the Tor SOCKS5 proxy used for outbound
connections to other onion services or clearnet endpoints (separate
from inbound onion service handling).
Optional monitoring knobs: control_addr and control_auth (e.g.
/run/tor/control and cookie) let the daemon read Tor's status
through the control port even in directory mode. They are
non-fatal on failure — the onion service still works without them.
See ../reference/configuration.md
for the full key list and examples.
Step 5: Reload the FIPS daemon
sudo systemctl reload-or-restart fips
At startup the daemon reads the .onion hostname from
hostname_file, binds 127.0.0.1:8444, and announces the onion
endpoint internally. From this point inbound connections to
<your-onion>.onion:8443 arrive at FIPS over Tor.
Step 6: Verify
Check that the FIPS daemon log shows the onion endpoint at startup:
sudo journalctl -u fips -e | grep -i 'onion\|directory'
You should see a line indicating the onion address FIPS will accept
inbound connections on, and that the local bind on 127.0.0.1:8444
succeeded.
From another node configured with the Tor transport in socks5 or
directory mode, attempt to dial:
fipsctl connect <peer-npub-or-hostname> <your-onion>.onion:8443 tor
A successful fipsctl show peers afterwards on the inbound side
shows the new peer with transport=tor.
Optional: advertise the onion endpoint via Nostr discovery
If node.discovery.nostr.enabled: true, set
transports.tor.advertise_on_nostr: true so the onion endpoint
appears in this node's published advert. See
enable-nostr-discovery.md Scenario 2.
Troubleshooting
- Tor refuses to start with
Sandbox 1and onion-service errors.Sandbox 1requiresdirectorymode and forbids creating onion services through the control port. Verify yourtorrcusesHiddenServiceDir(this guide), notADD_ONIONvia control port. - FIPS daemon fails to bind
127.0.0.1:8444. Another process is already bound to that port. Either stop the conflicting process or pick a different port and update bothtorrc'sHiddenServicePorttarget andfips.yaml'sbind_addrto match. - Onion hostname is empty or missing. Check
journalctl -u torfor permission errors onHiddenServiceDir. The directory must be owned by the Tor user with mode0700. - FIPS daemon cannot read
hostname_file. File is owned by the Tor user and not readable by the FIPS daemon user. Adjust permissions, or copy the hostname into a path the FIPS user can read.
See also
- ../design/fips-transport-layer.md
— Tor transport design, three modes (
socks5,control_port,directory), bridge-node pattern - ../reference/configuration.md —
full
transports.tor.*configuration knob table - enable-nostr-discovery.md — Scenario 2 for advertising the onion endpoint to peers via Nostr