Multi-node Deployment Guide
From bare VMs to an encrypted, self-aware fleet: how nodes get their mesh IP, bootstrap WireGuard, elect an edge leader, and route cross-fleet traffic.
How nodes get their mesh IP
BRIDGE creates a decentralized Layer 3 overlay network directly inside the Linux kernel. Unlike legacy VPNs or centralized SD-WANs, there is no central controller or hub-and-spoke bottleneck:
1. Overlay subnet
The cluster operates on a private subnet (conventionally 10.8.0.0/24). Each node is assigned a unique IP within this range via mesh_ip.
2. WireGuard interface (wg0)
On startup, BRIDGE creates and provisions the wg0 interface using CAP_NET_ADMIN, binding mesh_ip/24 on port 51820.
3. Curve25519 keypairs
Each node generates an RFC 7748 Curve25519 keypair automatically if not explicitly configured in bridge.toml.
4. Point-to-point routes
When SWIM gossip discovers a peer, BRIDGE programs a kernel peer route with AllowedIPs = [<peer_mesh_ip>/32] pointing to that peer's public UDP endpoint.
Traffic routed across nodes flows directly point-to-point over WireGuard at kernel speed. If node-01 needs to send a request to a container running on node-02, it sends packets to 10.8.0.2, which tunnel securely over UDP without transit through an intermediary.
Prerequisites & Firewall
Before installing, ensure each VM can reach peers on the required ports:
| Port / Protocol | Direction | Purpose |
|---|---|---|
80 / TCP, 443 / TCP | Inbound (Public) | Ingress HTTP/HTTPS traffic from clients. |
51820 / UDP | Inbound / Outbound (Inter-node) | Encrypted WireGuard mesh tunnels and SWIM gossip heartbeats. |
9090 / TCP | Localhost / Private | Embedded operations console, JSON API, and WebSocket event stream. |
Step 1: Install BRIDGE on each VM
Run the installation script on all nodes you want in the cluster (e.g. node-01, node-02, node-03):
Direct GitHub raw fallback: curl -fsSL https://raw.githubusercontent.com/Penivera/Bridge/main/scripts/install.sh | sh
The installer configures /usr/local/bin/bridge, sets up the dedicated
bridge system user with CAP_NET_BIND_SERVICE and
CAP_NET_ADMIN, and provisions a systemd unit.
Step 2: Configure the bootstrap node (node-01)
Designate your first node (e.g. node-01 on public IP 203.0.113.10)
as the bootstrap seed and edge leader. Edit /etc/bridge/bridge.toml:
enable_telemetry = false
[proxy]
mode = "Direct"
listeners = ["http"]
http_addr = "0.0.0.0:80"
[dashboard]
enabled = true
listen_addr = "127.0.0.1:9090"
[ipc]
enabled = true
socket_path = "/tmp/bridge.sock"
# This node's cluster identity and mesh address
[node]
id = "node-01"
mesh_ip = "10.8.0.1"
endpoint = "203.0.113.10:51820"
listen_port = 51820
priority = 100 # Highest priority: elected leader for public ingress
[[nodes]]
node_id = "node-01"
endpoint = "203.0.113.10:51820"
Validate the syntax and start the daemon:
bridge config validate --config /etc/bridge/bridge.toml
systemctl restart bridge
Step 3: Join worker nodes to the mesh
On your other VMs (node-02 at 203.0.113.11 and node-03 at 203.0.113.12),
assign unique mesh IPs (10.8.0.2 and 10.8.0.3) and point them at node-01 in [[seeds]]:
# /etc/bridge/bridge.toml on node-02
enable_telemetry = false
[proxy]
mode = "Direct"
listeners = ["http"]
http_addr = "0.0.0.0:80"
[node]
id = "node-02"
mesh_ip = "10.8.0.2"
endpoint = "203.0.113.11:51820"
listen_port = 51820
priority = 80
[[seeds]]
endpoint = "203.0.113.10:51820"
[[nodes]]
node_id = "node-02"
endpoint = "203.0.113.11:51820"
On node-03, apply the same structure with mesh_ip = "10.8.0.3",
its public endpoint, and priority = 60. Restart the service on each host:
systemctl restart bridge
Step 4: Verify the fleet using the CLI
Inspect cluster health, mesh interfaces, and leader election using BRIDGE CLI commands:
# 1. Check overall system health
bridge health
# 2. List nodes, mesh IPs, and elected roles
bridge nodes
# 3. Inspect WireGuard mesh interface and active tunnels
bridge mesh status
# 4. Check leader election consensus
bridge election status
You should see all 3 nodes marked ALIVE, connected over wg0, with node-01 elected as the active leader holding the public ingress boundary.
Step 5: Add routes & test cross-fleet traffic
Define a service running on node-02 (e.g. a web application listening on local port 3000):
bridge add-route app.example.com --upstream 127.0.0.1:3000 --node-id node-02
Now test traffic from your laptop or public client by sending a request to the leader's public IP:
curl -H "Host: app.example.com" http://203.0.113.10/
The request reaches node-01, matches the routing table for app.example.com,
and tunnels instantaneously across the WireGuard mesh to node-02 (10.8.0.2:3000).
Step 6: Test autonomous failover
Simulate an edge failure by stopping node-01 (or triggering a step-down):
bridge election trigger
SWIM gossip detects the change, Bully consensus executes in milliseconds, and
node-02 (the highest-priority alive peer) assumes leadership and takes
over the ingress entrypoint automatically. No human intervention, no stale DNS.