Geodineum

Multi-Node Deployment Guide

Deploy additional nodes that join an existing Geodineum constellation.

Deployment Tiers

                          ┌──────────────────────────────────┐
                          │         MASTER SERVER             │
                          │                                    │
                          │   ValKey :47445 (VPN only)         │
                          │   gNode daemon (--node-id master)  │
                          │   All sites, all streams           │
                          │                                    │
                          └──────────┬───────────────────────┘
                                     │ WireGuard VPN
                                     │ (10.66.0.0/24)
                    ┌────────────────┼────────────────┐
                    │                │                 │
           ┌────────┴──────┐  ┌──────┴───────┐  ┌─────┴────────┐
           │   HEADLESS    │  │   REPLICA    │  │  FULL NODE   │
           │               │  │              │  │              │
           │  gCore + PHP  │  │  ValKey      │  │  gNode       │
           │  No daemon    │  │  (replica)   │  │  daemon      │
           │  No ValKey    │  │  + gNode     │  │  No local    │
           │               │  │  daemon      │  │  ValKey      │
           │  Streams via  │  │              │  │              │
           │  VPN directly │  │  Local reads │  │  Can take    │
           │               │  │  VPN writes  │  │  over on     │
           │  SMTP server, │  │              │  │  master fail │
           │  satellite    │  │  Content,    │  │              │
           │  sites, COMMS │  │  caching,    │  │  HA, infra,  │
           │               │  │  rendering   │  │  inference   │
           └───────────────┘  └──────────────┘  └──────────────┘
Tier Components ValKey gNode Use Case
Headless gCore + services or standalone (COMMS, BAK) None None Lightest. SMTP servers, satellite PHP sites, standalone components that just need stream access
Replica Full stack + local ValKey replica Local (read) + VPN (write) Yes Content-heavy. Caching, template rendering, topology queries at local speed. Ideal for serving sites with heavy read patterns
Full node Full stack, no local ValKey Remote via VPN Yes High availability. Full command processing, service discovery, can take over failing master's streams. For inference workers, distributed topologies

ValKey is never exposed to the internet. All inter-node communication flows through a WireGuard VPN (10.66.0.0/24). The only internet-facing port is WireGuard's UDP port (51820), which is cryptographically silent - drops all packets not signed by a known peer.

Prerequisites

Master server: Working Geodineum installation.

Worker server:

Step 1: Initialize the Master

# On the MASTER server
sudo geodineum constellation init

This:

Note the public key shown in the output - the worker needs it.

Step 2: Set Up the Worker

# On the WORKER server

# 1. Install WireGuard
sudo apt install wireguard-tools    # Linux
# Or: brew install wireguard-tools  (macOS)
# Or: download from wireguard.com   (Windows)

# 2. Generate a keypair
wg genkey | sudo tee /etc/wireguard/wg-geodineum.key | wg pubkey
# Save the public key output - the master needs it

Step 3: Add the Worker to the Constellation

# On the MASTER server
sudo geodineum constellation add-peer worker1 "<worker_public_key>" "<worker_public_ip>:51820"

Then get the config the worker needs:

geodineum constellation show-config

This prints a complete WireGuard config file. Copy it to the worker.

Step 4: Connect the Worker

# On the WORKER server

# 1. Save the config (replace WORKER_PRIVATE_KEY with your generated key)
sudo nano /etc/wireguard/wg-geodineum.conf

# 2. Start WireGuard
sudo systemctl enable --now wg-quick@wg-geodineum

# 3. Verify VPN connectivity
ping 10.66.0.1    # Should reach the master

Step 5: Stage the Shared Daemon Credential

Every daemon in the constellation authenticates to the master's ValKey as gnode_daemon. Copy the credential before installing so the installer can pick it up:

# On the MASTER
sudo cat /etc/geodineum/credentials/valkey_daemon.password

# On the WORKER
sudo install -d -m 750 /etc/geodineum/credentials
echo -n "<paste_password>" | sudo tee /etc/geodineum/credentials/valkey_daemon.password >/dev/null
sudo chmod 640 /etc/geodineum/credentials/valkey_daemon.password

(The interactive wizard prompts for this instead; pre-staging is what makes the fully flag-driven install below possible.)

Step 6: Install Geodineum on the Worker

# On the WORKER server
git clone https://github.com/geodineum/Geodineum.git
cd Geodineum
sudo ./install.sh --constellation private --deploy-tier full \
    --master-ip 10.66.0.1 --yes --no-comms

That single command is the whole node setup. Component code is fetched from the public GitHub repositories (the master ships credentials, never code) and the installer converges everything a worker needs:

Re-running the installer is idempotent: it re-pulls, re-asserts permissions, and converges services rather than duplicating anything.

Expected (and correct) worker-tier output: Lua function libraries are managed on the master, and the ValKey admin credential stays on the master by design; the installer states both instead of failing.

Step 7: Verify

# On the WORKER - daemon up, unique node id on the command line
systemctl status gnode-daemon
journalctl -u gnode-daemon -n 20   # expect "Stream discovery status: N sites"

# On the MASTER - the worker appears in the live topology
sudo bash -c 'REDISCLI_AUTH=$(cat /etc/geodineum/credentials/valkey.password) \
  valkey-cli -p 47445 --no-auth-warning HGETALL "{geodineum}:gnode:topology:services"' \
  | grep -i "<worker-hostname>"

Check from either server:

geodineum constellation status

Managing the Constellation

# Add another worker
sudo geodineum constellation add-peer worker2 "<pubkey>" "<ip>:51820"

# Remove a worker
sudo geodineum constellation remove-peer worker1

# Show current state
geodineum constellation status

# Tear down entirely (revert to single-node)
sudo geodineum constellation close

Node Types

Route commands to specialized nodes using the _gh field:

Type Routing Use Case
general Excludes inference/gpu hints Default worker
inference Only inference/ML commands Dedicated ML server
gpu_compute Only GPU tensor commands GPU node
all Processes everything Dev/single-node
# Route a command to an inference node
XADD {site}:gnode:unified:production * cmd predict params '{}' _gh inference

A node processes an entry only if its type covers the entry's _gh hint. This is exposure: what a node is willing to do, independent of what it is capable of. It is why an intermittent or partially-trusted node — a developer laptop, a borrowed GPU box — can join without being handed load-bearing work. Give it inference and it serves inference and nothing else, no matter how busy the rest of the constellation is.

Intermittent Nodes and Orphan Recovery

Nodes may leave without notice — a laptop sleeps, a network drops, a process is killed. Ownership of an in-flight stream entry lives in the consumer group until the entry is acknowledged, so an entry held by a node that vanished would, on its own, never be redelivered.

Every node therefore periodically reclaims entries whose owner has gone idle past a threshold, restricted to entries its own exposure covers — a node never takes work it would not otherwise process. An entry orphaned by one node is picked up by another that is exposed to it; node loss costs throughput, never correctness.

Consumers are cleaned up in step: a node removes itself from its groups on graceful shutdown, and a periodic sweep removes consumers that are idle with no pending entries. A consumer still holding entries is never removed — that would discard the entries — so a crashed node's work is reclaimed first and its consumer entry disappears only once it is empty. The practical effect: you can connect and disconnect a laptop all day and the group tracks live participants, not the history of connections.

Security Model

Layer Protection
Network WireGuard VPN - ValKey only on private 10.66.0.x interface
Port 47445 Not bound to public IP - unreachable from internet
Port 51820 (UDP) WireGuard - cryptographically silent, drops unknown packets
Authentication ValKey ACL - per-user permissions, 64-char hex passwords
Brute-force fail2ban - 3 failed auth attempts → permanent ban
Encryption WireGuard ChaCha20-Poly1305 - all traffic between nodes encrypted

Cross-Platform Workers

WireGuard runs on Linux, macOS, Windows, FreeBSD, iOS, and Android. The config file format is identical. A developer can run a gNode worker on macOS connecting to the Linux master over the VPN.