Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The mesh-hub daemon

Reference · generated · every flag of the daemon with its default, printed by the binary itself

mesh-hub

Pulse Mesh local daemon — Universal Port Protocol terminator over UDS + WebSocket

ArgumentDefaultMeaning
--hub-name <HUB_NAME>default_hubThe hub name, which names its shared memory (/pms-<name> and /pms-<name>-envelopes): 1 to 15 characters from letters, digits, _, . and -
--store-slots <STORE_SLOTS>256Slots in the envelope store that keeps each envelope for the processes attached to the hub by name, 65,600 bytes of shared memory each: 0 (no store) to 4,294,967,295
--uds-path <UDS_PATH>/tmp/pms.sockUnix-domain socket path, at most as long as a socket address holds (103 bytes on macOS, 107 on Linux)
--ws-bind <WS_BIND>127.0.0.1:9876WebSocket bind address (host:port): a loopback address, unless --ws-tls-cert and --attach-keys are both given, so that the WebSocket is encrypted and its clients prove their keys, or --ws-allow-remote is
--ws-allow-remoteLet --ws-bind take an address other than loopback without TLS and attach keys both. Without --attach-keys the WebSocket authenticates no client, so anything that can reach the address can attach, send and subscribe; without --ws-tls-cert nothing encrypts it, and a proof made at attach can be relayed as it is made. The daemon logs a warning when it binds such an address, naming what is missing
--ws-tls-cert <PEM>A PEM file of the certificate chain the WebSocket presents, its own certificate first. With --ws-tls-key (both or neither), the WebSocket is wss://: each connection completes a TLS 1.3 handshake before its upgrade, the two within --handshake-timeout-secs. TLS encrypts the WebSocket and authenticates the daemon to clients that trust the certificate; --attach-keys authenticates the clients, each proof bound to its TLS connection
--ws-tls-key <PEM>A PEM file of the private key of --ws-tls-cert’s certificate (PKCS #8, PKCS #1 or SEC1); both or neither
--attach-keys <FILE>A file of the Ed25519 public keys a client may prove at attach: one key’s standard base64 per line, as pms keys public prints it, with # comments and blank lines. With it, an attach on the WebSocket must carry a listed key and answer the daemon’s challenge with a proof of it within --handshake-timeout-secs, and is named by the key; one without a key, a proof that fails, or a key not listed is refused with auth_failed, and the connection closed. The Unix socket, which only the daemon’s user can open, still admits an attach without a key unless --attach-keys-uds is given. A file that cannot be read, or holds a line that is not a key, stops the start (exit status 1)
--attach-keys-udsRequire a listed key, proved at attach, on the Unix socket too; needs --attach-keys
--metrics-bind <ADDR>Serve the daemon’s counts at GET /metrics on this address (host:port), in the Prometheus text format; off unless given. A loopback address unless --metrics-allow-remote is given
--metrics-allow-remoteLet --metrics-bind take an address other than loopback. The endpoint has no authentication, so anything that can reach the address can read the daemon’s counts; the daemon logs a warning when it binds one
--allow-origin <ORIGIN>A web origin, scheme://host[:port], whose pages may open the WebSocket besides pages served from localhost, 127.0.0.1 or [::1] (repeatable); other pages’ upgrades get HTTP 403, and clients that send no Origin are admitted
--node-key <FILE>The file of this daemon’s node key, the X25519 key its links to other daemons authenticate with: loaded, or, when there is no file, generated and saved with mode 0600. A file its group or others can read or write is refused. Links need it, --link-bind and at least one peer (--link-peer or --link-peer-key), all three or none. The daemon logs at startup its daemon id (the fingerprint of the key’s public half, which names it across links), the public half, which its peers configure, its link address and its peers
--link-bind <ADDR>The UDP address (an IP address and port) every link to another daemon is sent from and received on: one sealed endpoint (Noise IK sessions, ChaCha20-Poly1305), whatever the number of peers. Links are off unless it is given, with --node-key and a peer
--link-peer <ADDR=PUBKEY>A daemon to link to, as ADDR=PUBKEY: the IP address and port of its --link-bind, and the public half of its node key as 64 hex digits (repeatable). Only the peers’ keys are admitted, each of these from its address’s IP. A client’s send is forwarded, once, to each linked peer whose subscribers may want it, and what a peer forwards reaches the subscribers here, its origin name@ and the sending daemon’s id
--link-peer-key <PUBKEY>A daemon to link to named by the public half of its node key alone, as 64 hex digits (repeatable). Its address is learned from its announcements on the --link-announce group, which this needs. Such a peer is admitted from any address its handshake comes from, its key authenticated as any peer’s is, where a --link-peer is admitted only from its address’s IP
--link-announce <GROUP:PORT>An IPv4 multicast group and port, GROUP:PORT (the group’s first byte 224 to 239, and 239 the range a site uses for its own), on which the daemon announces its link endpoint (its node key’s public half and its link port) at startup and every 5 seconds, and hears the other daemons’ announcements; off unless given. An announcement is a plaintext hint, not signed. One from a key that is not a configured peer’s is ignored; one from a configured peer’s key, while no sealed session to it exists, asks for a handshake, which then authenticates the key: at the announced address for a --link-peer-key, and at its own address for a --link-peer, which no announcement changes; at most one such handshake per peer every 5 seconds. Needs --link-bind to be an IPv4 address; the announcements leave by its interface when it is not 0.0.0.0
--link-announce-ttl <TTL>1How many hops the --link-announce announcements may cross, their IPv4 TTL, 1 to 255. The default, 1, keeps them on the local network
--link-relayRelay for the linked daemons (ADR-0021, item 9): forward once more what one peer sent, to the other peers whose subscribers may want it (never back to the peer it came from, nor to its origin’s daemon), and tell each peer what the other peers that are not relays want and which clients they have, so that sends and to sends reach them through this daemon. A send crosses one relay at most: it leaves its origin with a hop limit of two, and a relay spends one. The peers see in its Hello that it relays; whether they accept what it relays is their own --link-trust-relay. Needs links
--link-trust-relay <PUBKEY>A configured peer, named by the public half of its node key as 64 hex digits, whose relayed traffic this daemon accepts (repeatable): sends of other daemons’ clients that it forwards, the clients it announces as reached through it, and their health. From any other peer such traffic is refused and counted. The peer’s link authenticates the peer itself, but the origins it reports for what it relays are only as trustworthy as it is: nothing signs an envelope end to end. The key must be a --link-peer’s or a --link-peer-key. Needs links
--no-udsDisable the UDS transport
--no-wsDisable the WebSocket transport
--foregroundtrueRun in the foreground, the only mode; use a supervisor (launchd, systemd, nohup) to run it in the background
--ping-interval-secs <PING_INTERVAL_SECS>30Seconds between WebSocket pings, at most 31,536,000 (a year); 0 disables them
--idle-timeout-secs <IDLE_TIMEOUT_SECS>90Seconds of silence (no frame, no pong) before a connection is closed, at most 31,536,000 (a year); 0 disables the check
--write-timeout-secs <WRITE_TIMEOUT_SECS>10Seconds one outbound write may take before the connection is closed as unreadable, at most 31,536,000 (a year); 0 waits forever
--handshake-timeout-secs <HANDSHAKE_TIMEOUT_SECS>5Seconds a WebSocket upgrade may take before the connection is dropped, the TLS handshake before it included on wss://, 1 to 31,536,000 (a year)
--max-message-bytes <MAX_MESSAGE_BYTES>1048576Largest message accepted on either transport, a WebSocket message counting whole however many frames it comes in: 1,024 to 4,294,967,295 bytes
--subscriber-queue <SUBSCRIBER_QUEUE>1024Events queued per connection before newer ones are dropped and counted in the unsubscribe ack, 1 to 1,048,576
--subscriber-queue-bytes <SUBSCRIBER_QUEUE_BYTES>16777216Bytes of event JSON queued per connection, the event being written included, before newer events are dropped and counted; 0 drops every event
--total-queue-bytes <TOTAL_QUEUE_BYTES>268435456Bytes of event JSON queued across all connections, shared so that one within its equal share takes room from the one holding the most. A subscriber that keeps up holds at most two events, so it loses no event to this budget while fewer connections hold events than this over twice --max-message-bytes (about 128 at the defaults); past that it can lose events too. 0 drops every event
--max-subscriptions <MAX_SUBSCRIPTIONS>64Subscriptions one connection may hold at once, a subscribe beyond it refused with limit_exceeded; 0 refuses every subscribe
--max-connections <MAX_CONNECTIONS>256Connections the daemon holds at once across both transports, one beyond it refused (a limit_exceeded frame on the Unix socket, HTTP 503 on the WebSocket); 0 refuses every connection
--basket-path <BASKET_PATH>A basket SQLite file to capture every published envelope into, for pms-query and the mesh_query MCP tool
--basket-retention-secs <BASKET_RETENTION_SECS>60Seconds between the basket’s retention sweeps, 1 to 31,536,000 (a year); no effect without --basket-path

Exit status:

  • 0: stopped by SIGINT or SIGTERM.
  • 1: could not start, or could not install its signal handlers; the log says why (another daemon holds the socket, the port or the hub name, a store or a basket could not be made or opened, the WebSocket’s TLS certificate or key could not be read or was refused, the –attach-keys file could not be read or holds a line that is not a key, the –node-key file could not be read or made, the –link-bind address could not be bound, or the –link-announce group could not be joined).
  • 2: the command line was refused.
  • 3: displaced. The hub name’s lock file was removed while the daemon ran and another owner took the name, so the processes attached to the hub by name follow that owner and nothing sent to this daemon reaches them. The daemon notices within 1s, logs at error level what happened and who holds the name now, closes its connections, removes its socket if the path still names it, and exits. A restart under the same --hub-name is refused while that owner lives, so a supervisor should not restart the daemon on this status (systemd: RestartPreventExitStatus=3).