Skip to content

Multi Host Topology

Griffen Fargo edited this page Aug 1, 2026 · 3 revisions

Multi-Host Topology

Define which stacks deploy to which hosts in a single place. Added in v0.22.0.

Overview

For projects spanning multiple hosts, strut.conf supports [hosts] and [stacks] sections that map your infrastructure topology:

# strut.conf
REGISTRY_TYPE=none
DEFAULT_BRANCH=main

[hosts]
compass = gfargo@compass.local:22 ~/.ssh/id_rsa
mac = griffen@mac.local:22 ~/.ssh/id_rsa
pi-ops = pi@pi-ops.local:2222 ~/.ssh/pi_key

[stacks]
plane = compass
hub = compass
agent-platform = mac
immich = mac
observability = pi-ops
monitoring = pi-ops

How it works

When you run strut plane deploy --env prod:

  1. strut looks up plane in the [stacks] section → finds compass
  2. Looks up compass in the [hosts] section → gets gfargo@compass.local:22 ~/.ssh/id_rsa
  3. Exports VPS_HOST=compass.local, VPS_USER=gfargo, VPS_PORT=22, VPS_SSH_KEY=~/.ssh/id_rsa
  4. The deploy proceeds targeting that host

Env file values always take precedence. If your .prod.env sets VPS_HOST, that overrides the topology. This means topology provides defaults, and env files can override per-environment.

Host format

<alias> = <user>@<host>:<port> <ssh_key_path>
Part Required Default Example
user Yes gfargo
host Yes compass.local
port No 22 2222
ssh_key No ~/.ssh/id_rsa

Minimal form (defaults to port 22, no explicit key):

myhost = ubuntu@10.0.0.5

Benefits

  • Single source of truth — topology visible at a glance in strut.conf
  • Cleaner env files — only secrets, no host config duplication
  • Multi-host operationsstrut status-all knows which host to check for each stack
  • No per-stack SSH config — connection info defined once per host, shared across stacks

Introspection

The topology module provides functions for scripting and debugging:

# In a strut context (after sourcing lib/topology.sh):
topology_list_hosts          # List all host aliases
topology_list_stacks         # List all mapped stacks
topology_list_stacks compass # List stacks on a specific host
topology_resolve_host plane  # Output: gfargo compass.local 22 ~/.ssh/id_rsa

Fleet Status (since v0.31.0)

strut fleet status reads every host in [hosts], connects over SSH, and reports each one's git sync state in a single table — the fastest way to answer "is anything behind?" across a whole fleet without deploying to find out.

strut fleet status
  HOST      BRANCH   BEHIND AHEAD DIRTY HEAD
  ────      ──────   ────── ───── ───── ────
  prod      main          0     0     0 abc1234
  staging   main          5     0     3 def5678
  • BEHIND/AHEAD — commits the host's checkout is behind/ahead of origin
  • DIRTY — count of modified/untracked files (0 = clean checkout)
  • HEAD — current commit, short SHA
strut fleet status --json
{
  "hosts": [
    { "host": "prod", "status": "ok", "branch": "main", "behind": 0, "ahead": 0, "dirty": 0, "head_sha": "abc1234567..." },
    { "host": "staging", "status": "unreachable" }
  ]
}

An unreachable host reports "status": "unreachable" rather than failing the whole command — useful for a scheduled check where one flaky host shouldn't hide drift on the others. Pair with strut sync <host> (or --all) to bring a behind/dirty host back in line.

Backward compatibility

The [hosts] and [stacks] sections are entirely optional. Projects without them work exactly as before — VPS_HOST and friends come from the env file or services.conf.

If a stack has no entry in [stacks], topology is a no-op for that stack.

Clone this wiki locally