.\" meshbay-node(1) man page .TH MESHBAY\-NODE 1 "August 2026" "meshbay-node 0.6.0" "MeshBay Manual" . .SH NAME meshbay\-node \- MeshBay Node daemon, local file host, streaming server, and group manager . .SH SYNOPSIS .B meshbay\-node .RI [ command ] .RI [ subcommand ] .RI [ target ] .RI [ options ] . .SH DESCRIPTION .B meshbay\-node is the local daemon of the MeshBay decentralized platform. It hosts shared directories, indexes files, serves video streams to peers, manages group membership, and provides a local control API. .PP When invoked without a command, the daemon starts in the foreground. It loads its configuration from .IR ~/.config/meshbay/node.toml , unlocks (or creates) its Ed25519 keystore, connects to the hub, starts the directory indexer, the QUIC chunk server, the WebRTC transport, and the local control API. .PP The daemon runs until interrupted by .B SIGINT or .BR SIGTERM . . .SH COMMANDS If no command is given, the daemon starts normally. . .TP .B init Write an example configuration file and create the keystore if they do not already exist. . .TP .B status Print node state: hub connection, node key, running daemon information, configured groups and their roots, operator pairing status, and pending invitations. Works whether the daemon is running or stopped. . .TP .B calibrate\-argon2 Benchmark Argon2id with several memory cost values and suggest the one closest to a 500\ ms target on the current hardware. . .TP .B reload Ask systemd to send SIGHUP to the running daemon, causing it to re\-read .I node.toml and pick up new or changed groups without dropping live connections. Equivalent to .BR "systemctl \-\-user reload meshbay\-node" . . .TP .B restart\-daemon Restart the daemon via systemd. Equivalent to .BR "systemctl \-\-user restart meshbay\-node" . . .SS Group management .TP .B group list List all hosted groups with their roots, key status, file count, and connected peers. . .TP \fBgroup add\fR \fIname\fR \fB\-\-dir\fR \fIpath\fR [\fB\-\-upload\-dir\fR \fIpath\fR] Attach a hub\-side group to this node by writing a .B [[groups]] entry to .IR node.toml . The group must already exist on the hub. Run .B meshbay\-node reload afterwards, then .BR "meshbay\-node gek init" . . .TP \fBgroup remove\fR \fIname\fR Remove a group from .I node.toml and stop hosting it after the next restart. Asks for confirmation unless .B \-\-yes is given. . .SS Member management .TP .B member list List all admitted members and pending invitation codes, showing role, status, group scope, and when each identity was pinned. . .TP \fBmember invite\fR \fIusername\fR Generate a one\-time invitation code for the named user. The code is printed to the terminal and written to a file under the data directory. It is valid for the period set by .B invite_ttl_hours (default: 168 hours / 7\ days). . .TP \fBmember revoke\fR \fIusername\fR Revoke a member's access to the group. They stop receiving the group encryption key on their next connection. Rotate the GEK afterwards with .BR "meshbay\-node gek rotate" . . .TP \fBmember unpin\fR \fIusername\fR Forget a member's pinned key, allowing them to pair again with a new one. . .SS Group encryption key (GEK) .TP .B gek init Initialize the group encryption key. Alias: .BR gek\-init . . .TP .B gek rotate Replace the current GEK. Every active member re\-receives the new key automatically. Revoked members keep only the old key. Asks for confirmation unless .B \-\-yes is given. . .SS Operator .TP .B operator pair Generate a one\-time pairing code that authorizes a browser as this node's operator. The operator can invite members and delete files. Pairing is node\-wide (not per\-group). The code is valid for .B pair_ttl_hours (default: 24 hours). . .SS File management .TP \fBfile list\fR [\fB\-\-group\fR \fIid\fR] List all indexed files with their id, size, and path. . .TP \fBfile rm\fR \fIfile\-id\fR [\fB\-\-yes\fR] Delete a file from disk (not just from the index). The file id can be a prefix as long as it matches exactly one file. Asks for confirmation unless .B \-\-yes is given. . .SS Denylist .TP .B denylist show Display all denied users, groups, and JTIs. Entries survive daemon restarts. . .TP \fBdenylist clear\fR [\fIidentifier\fR] [\fB\-\-yes\fR] Remove entries from the denylist. If an identifier is given, only that entry is removed; otherwise the entire list is cleared. . .SS STUN servers .TP .B stun list Display the STUN servers currently used for ICE candidate gathering. . .TP \fBstun add\fR \fIurl\fR Add a STUN server. The URL must start with .BR stun: , e.g.\& .BR stun:stun.example.com:3478 . . .TP \fBstun remove\fR \fIurl\fR Remove a STUN server from the list. . .TP .B stun reset Reset the STUN server list to the built\-in defaults (four public servers). . .SH OPTIONS .TP \fB\-\-config\fR \fIpath\fR Path to the configuration file. Defaults to .IR ~/.config/meshbay/node.toml . . .TP \fB\-\-group\fR \fIid\fR Select a group by id or name when the node hosts multiple groups. Optional when only one group is configured. . .TP \fB\-\-dir\fR \fIpath\fR Shared directory, used with .BR "group add" . . .TP \fB\-\-upload\-dir\fR \fIpath\fR Separate upload directory, used with .BR "group add" . Files land directly in this directory (not in a subdirectory) and it appears as its own root in the index. . .TP .B \-\-yes Skip confirmation prompts for destructive commands .RB ( "gek rotate" , .BR "group remove" , .BR "file rm" , .BR "denylist clear" ). . .TP \fB\-\-log\-level\fR \fIlevel\fR Logging level for daemon mode. One of .BR DEBUG , .BR INFO " (default)," .BR WARNING , .BR ERROR . Ignored for query commands, which always suppress library logging. . .SH CONFIGURATION The daemon reads its configuration from .I ~/.config/meshbay/node.toml (overridable with .BR \-\-config ). Run .B meshbay\-node init to generate an example file. .PP Certain settings can be overridden by environment variables prefixed with .BR MESHBAY_ . . .SS [hub] .TP .B url Hub server URL. Default: .BR https://meshbay.org . Override: .BR MESHBAY_HUB_URL . . .TP .B username Hub account username. Override: .BR MESHBAY_USERNAME . . .SS [node] .TP .B quic_port QUIC (MNP) port for LAN, port\-forwarded, or hub\-less direct access. Default: .BR 19010 . Override: .BR MESHBAY_QUIC_PORT . . .TP .B ui_port Local control API port (loopback only, token\-gated). Default: .BR 18000 . . .TP .B invite_ttl_hours How long a member invitation code remains valid. Default: .BR 168 (7\ days). . .TP .B pair_ttl_hours How long an operator pairing code remains valid. Default: .BR 24 . . .TP .B device_request_ttl_minutes How long a device\-add request may wait for approval from an existing device. Default: .BR 60 . . .TP .B max_concurrent_streams Maximum number of simultaneous video streams. One ffmpeg process runs per viewer; it remuxes rather than re\-encodes so CPU cost is low, but each uses about 50\ MB of memory. When reached, new viewers are told the server is busy. Default: .BR 8 . Override: .BR MESHBAY_MAX_CONCURRENT_STREAMS . Must be a positive integer; zero or negative values are ignored with a warning. . .TP .B transcode_incompatible_video When .BR true " (default)," HEVC and other browser\-incompatible video codecs are transcoded to H.264 during streaming so browsers can play them. Unlike remuxing, this costs real CPU per concurrent viewer. Set to .B false only when all viewers are known to decode the source codec natively. . .TP .B ice_interfaces Whitelist of network interface names for WebRTC ICE candidate gathering. When empty (default), virtual and VPN adapters are auto\-excluded: Tailscale (tailscale*, wt*), libvirt (virbr*), Docker (docker*, veth*, br\-*), Podman (podman*), and CNI (cni*). CGNAT\-range addresses (100.64.0.0/10) are also excluded in auto mode. Set to an explicit list to override auto\-detection: .RS .nf ice_interfaces = ["wlp0s20f3", "eth0"] .fi .RE . .TP .B stun_servers List of STUN server URLs for WebRTC ICE candidate gathering (NAT traversal). Each entry must start with .BR stun: . When empty (default), four public servers are used: .IR stun.l.google.com:19302 , .IR stun1.l.google.com:19302 , .IR stun.cloudflare.com:3478 , and .IR stun.services.mozilla.com:3478 . Set to an explicit list to override: .RS .nf stun_servers = ["stun:stun.l.google.com:19302", "stun:stun.cloudflare.com:3478"] .fi .RE . .SS [[groups]] One or more group sections, each hosting a set of named directories .RI ( roots ). . .TP .B id Group identifier, obtained from the hub after creating the group there. . .TP .B name Human\-readable group name. . .TP .B shared_dir Single\-directory shorthand: equivalent to declaring one root named after the directory's basename, which receives uploads. Cannot be combined with .BR [[groups.roots]] . . .TP .B upload_dir A separate filesystem path for uploads. Files land directly in it (not in a subdirectory) and it appears as its own root in the index. When set, no other root receives uploads. . .TP .B visibility .BR private " (default) or " public . A public group is discoverable on the hub; visibility does not control admission. . .TP .B join_policy .BR invite " (default) or " open . With .BR invite , newcomers need a one\-time code from .BR "meshbay\-node member invite" . With .BR open , anyone the hub presents is served without a code. Read from the local configuration only, never from the hub. . .TP .B quic_port Per\-group QUIC port override. Default: inherits from .BR [node].quic_port . . .SS [[groups.roots]] Each root is a named directory inside a group. . .TP .B path Filesystem path to the directory. . .TP .B name Display name for this root. Default: the directory's basename. Two roots in the same group cannot share a name (case\-insensitive), and no root may sit inside another. . .TP .B kind A view hint: one of .BR generic " (default)," .BR video , .BR audio , .BR photo . Currently unused. . .TP .B upload Boolean. Exactly one root per group must receive uploads. Default: .BR false . . .SS [keystore] .TP .B path Path to the encrypted keystore file. Default: .IR ~/.config/meshbay/keystore.enc . . .TP .B unlock_file Path to a file containing the keystore passphrase, for unattended startup. Alternatively, set the .B MESHBAY_UNLOCK_KEY environment variable. . .SH ENVIRONMENT .TP .B MESHBAY_HUB_URL Override the hub URL from the configuration file. . .TP .B MESHBAY_USERNAME Override the hub username. . .TP .B MESHBAY_QUIC_PORT Override the QUIC port. . .TP .B MESHBAY_MAX_CONCURRENT_STREAMS Override the maximum number of concurrent video streams. . .TP .B MESHBAY_UNLOCK_KEY Keystore passphrase for unattended startup (alternative to .BR unlock_file ). . .TP .B MESHBAY_TMDB_DEFAULT_TOKEN TMDB API token for the Videos app metadata enrichment (optional). . .TP .B MESHBAY_MUSICBRAINZ_CONTACT_DEFAULT Contact address (email or URL) sent in the User-Agent for the Music app's MusicBrainz lookups (optional). Not a credential — MusicBrainz needs none — but still never a literal value in source: it is a personal contact string, same handling as an API token. Absent means MusicBrainz lookups are inert. . .SH FILES .TP .I ~/.config/meshbay/node.toml Default configuration file. . .TP .I ~/.config/meshbay/node.env Environment file read by the systemd service. Contains secrets such as .BR MESHBAY_UNLOCK_KEY , and, optionally, .BR MESHBAY_TMDB_DEFAULT_TOKEN and .BR MESHBAY_MUSICBRAINZ_CONTACT_DEFAULT . The node authenticates to the hub with its own Ed25519 identity key, not a password, so no hub credential lives here. . .TP .I ~/.config/meshbay/keystore.enc Encrypted Ed25519 + X25519 keystore, protected by Argon2id. . .TP .I ~/.local/share/meshbay/ Data directory: chat databases, index caches, bundle store, roster, denylist, and the control API session token. . .TP .I ~/.local/share/meshbay/ui\-token Per\-run token for the local control API. Written by the daemon at startup and read by the .B meshbay\-node CLI and the desktop client's Node page. . .SH SYSTEMD INTEGRATION A user service unit is provided at .IR packaging/systemd/meshbay\-node.service . Install and enable with: .PP .RS .nf sudo cp meshbay\-node.service /etc/systemd/system/meshbay\-node@.service sudo systemctl enable \-\-now meshbay\-node@$USER .fi .RE .PP Or as a per\-user unit: .PP .RS .nf cp meshbay\-node\-user.service ~/.config/systemd/user/meshbay\-node.service systemctl \-\-user enable \-\-now meshbay\-node .fi .RE .PP The unit reads secrets from .I ~/.config/meshbay/node.env and supports .B reload (SIGHUP, re\-reads configuration) and .BR restart . . .SH SECURITY .IP \(bu 2 The control API binds to .B 127.0.0.1 only and is protected by a per\-run token. .IP \(bu 2 Operator authority is established locally via .BR "meshbay\-node operator pair" , never learned from the hub. .IP \(bu 2 Group join policy .RB ( invite / open ) is read from the local configuration only, never from the hub. A hub cannot declare a group open. .IP \(bu 2 The keystore is encrypted with Argon2id. Run .B meshbay\-node calibrate\-argon2 to tune parameters for your hardware. .IP \(bu 2 The denylist is persisted to disk and survives daemon restarts. . .SH EXAMPLES Initialize a new node: .PP .RS .nf meshbay\-node init meshbay\-node .fi .RE .PP Check node status: .PP .RS .nf meshbay\-node status .fi .RE .PP Host a group: .PP .RS .nf meshbay\-node group add "My Media" \-\-dir /home/user/Media meshbay\-node reload meshbay\-node gek init \-\-group "My Media" .fi .RE .PP Invite a member: .PP .RS .nf meshbay\-node member invite alice .fi .RE .PP Pair an operator browser: .PP .RS .nf meshbay\-node operator pair .fi .RE .PP Stream up to 4 concurrent videos (in node.toml): .PP .RS .nf [node] max_concurrent_streams = 4 transcode_incompatible_video = false .fi .RE .PP Override STUN servers (in node.toml): .PP .RS .nf [node] stun_servers = ["stun:stun.l.google.com:19302", "stun:stun.cloudflare.com:3478"] .fi .RE . .SH SEE ALSO .BR meshbay\-hub (1), .BR systemctl (1), .BR ffmpeg (1) . .SH AUTHORS MeshBay contributors. .br .UR https://meshbay.org .UE