.\" 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 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. The directory becomes the group's first root, and is .B read\-write so that a new group can receive an upload without further configuration; pass .B \-\-no\-writable for a group that only publishes. 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 Root management A group has one or more named roots: directories on this machine that its members see. Each is read\-only or read\-write, independently; a group whose roots are all read\-only is valid and accepts no uploads at all. . .TP .B root list List this group's roots with their flags and current availability. . .TP \fBroot add\fR \fIpath\fR [\fB\-\-name\fR \fIname\fR] [\fB\-\-writable\fR] [\fB\-\-removable\fR] Add a directory to the group. The name defaults to the directory's basename; two roots in a group cannot share a name, compared without regard to case, and no root may sit inside another. Run .B meshbay\-node reload afterwards to start indexing it. . .TP \fBroot remove\fR \fIname\fR Remove a root from the group. Files on disk are untouched; only .I node.toml changes. The last remaining root cannot be removed. Asks for confirmation unless .B \-\-yes is given. . .TP \fBroot set\fR \fIname\fR [\fB\-\-writable\fR|\fB\-\-no\-writable\fR] [\fB\-\-removable\fR|\fB\-\-no\-removable\fR] Change a root's flags without removing it. Takes effect immediately; no reload is needed. . .TP \fBroot eject\fR \fIname\fR Mark a removable root as ejected before physically disconnecting the device. Its files are hidden from members and its index entries are frozen \(em nothing is deleted \(em and the directory watcher stops, so the unplug produces no deletions to propagate. The device can then be removed safely. Refused on a root that is not marked .BR removable . . .TP \fBroot plug\fR \fIname\fR Re\-enable an ejected root once the device is back. Refused if the directory is not readable, since clearing the flag while the device is still absent would hand the next scan an empty directory. The root is rescanned, so anything that changed while it was away is picked up. . .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. . .TP .B member upload Removed. Whether uploads are accepted is a property of each directory now, not a per\-group switch \(em see .BR "root set" . A group whose directories are all read\-only accepts no uploads at all, which is what turning the old switch off meant. . .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 .BR \-\-writable ", " \-\-no\-writable Whether a root accepts uploads from group members, used with .BR "root add" ", " "root set" " and " "group add" . Uploads land in an .I uploads subdirectory of the root; existing files are never replaced. A new root is read\-only unless .B \-\-writable is given; the directory passed to .B "group add" is the exception and is writable by default. . .TP .BR \-\-removable ", " \-\-no\-removable Whether a root lives on a device that gets disconnected, used with .BR "root add" " and " "root set" . Enables .BR "root eject" " and " "root plug" , and makes the node treat the directory suddenly disappearing as an unannounced eject rather than as a deletion. . .TP \fB\-\-upload\-dir\fR \fIpath\fR Deprecated. A second, read\-write root, used with .BR "group add" , from before roots carried their own read\-write flag. Setting it makes every other root of that group read\-only. Use .B "meshbay\-node root add" \fIpath\fR \fB\-\-writable\fR instead. . .TP \fB\-\-name\fR \fIname\fR Explicit name for a root, used with .BR "root add" . Default: the directory's basename. Required for a drive or filesystem root, which has no basename to derive one from. . .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 read\-write root named after the directory's basename. Cannot be combined with .BR [[groups.roots]] . . .TP .B upload_dir Deprecated. A separate filesystem path for uploads, from before roots carried their own read\-write flag. A configuration still using it is read as a second, writable root and every other root is forced read\-only. Use .B writable on the intended root instead. . .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 writable Boolean. Whether members may upload into this root. Uploads land in an .I uploads subdirectory; an existing file is never replaced. Any number of roots in a group may be writable, including none. Default: .BR false . . .TP .B removable Boolean. Whether this root lives on a device that gets disconnected. Enables .BR "meshbay\-node root eject" , and makes the directory suddenly disappearing freeze the root rather than look like a deletion of everything in it. Default: .BR false . . .TP .B upload Deprecated spelling of .BR writable , read for configurations written before the two were separated. .B writable wins where both appear. . .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