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

Host Management

Named hosts turn repetitive SSH details into a short, readable alias. They are useful when you manage several servers, when each server uses a different SSH key, or when an agent needs a stable host inventory.

Add Hosts

Interactive setup:

sshx --host-add

Command-line setup. Omit -pk unless you want a stored sudo key; the inventory must not record the runtime fallback master.

sshx --host-add \
  --host-name=prod-web \
  -h=192.168.1.100 \
  -p=22 \
  -u=deploy \
  -i=~/.ssh/prod-web.pem \
  -pk=prod-web-sudo \
  --host-desc="Production web node" \
  --host-type=linux \
  --bind=en0

Then run commands by alias:

sshx -h=prod-web "hostname && uptime"

Import from ~/.ssh/config

If you already maintain hosts in the OpenSSH client config, import them selectively instead of retyping them. Import is never all-or-nothing by default — you choose what enters ~/.sshx/settings.json.

Interactive selection:

sshx --host-import

sshx lists importable entries (with the resolved user@host:port and key) plus everything it skipped and why, then asks which entries to import (numbers, names, or all).

Non-interactive, by name (script/agent friendly, all-or-nothing). --json requires the name list and emits sshx.hosts.v1:

sshx --host-import=web1,db1
sshx --host-import=web1,db1 --json

--host-add / --host-update / --host-remove / --host-test / --host-test-all also honor --json with the same schema (success, host identity, and error_kind on failed tests).

Import from a different config file:

sshx --host-import --ssh-config=~/work/ssh_config

Preview without writing anything:

sshx --host-import=web1 --dry-run --json

What is imported per entry: HostName (or the alias itself when absent), Port, User, IdentityFile (as the per-host key), BindAddress / BindInterface (as bind; first value wins), and a single-token ProxyJump when that alias is already a named sshx host (as via).

Pollution guards — the importer always skips:

  • wildcard or negated patterns (Host *, web-?, !pattern) — they are rules, not hosts;
  • aliases that already exist in settings;
  • entries whose host:port already exists in settings (or duplicates an earlier entry in the same file);
  • options sshx does not support (ForwardAgent, unmapped ProxyJump, …) — shown as ignored: so nothing disappears silently;
  • options from other blocks: Host * defaults are never merged into imported entries;
  • IdentityFile values containing % tokens (reported in a note).

Match blocks are ignored and Include directives are not followed; import from included files directly via --ssh-config=<path>.

Settings File

Host definitions live in ~/.sshx/settings.json.

{
  "key": "/Users/alice/.ssh/id_rsa",
  "hosts": [
    {
      "name": "prod-web",
      "description": "Production web node",
      "host": "192.168.1.100",
      "port": "22",
      "user": "deploy",
      "key": "/Users/alice/.ssh/prod-web.pem",
      "password_key": "prod-web-sudo",
      "type": "linux",
      "bind": "en0",
      "via": "edge"
    }
  ]
}

The top-level key is the default SSH private key. A per-host key overrides it for that host only.

Jump hosts

When the local machine cannot reach app but named host edge can, persist via on the target. sshx opens one SSH session to edge, then a direct-tcpip channel to app, for this invocation only. There is no local listen port and nothing to tear down after the process exits.

sshx --host-add --host-name=edge -h=100.64.0.10 -u=jump
sshx --host-add --host-name=app -h=10.0.0.5 -u=app --via=edge
sshx -h=app --json "uptime"
sshx -h=app --via=          # force a direct connection for one run

Each hop verifies its own host key and uses its own key or ssh_password_key. Secrets stay local. --via=name on a command overrides inventory for that invocation. Removing a host that other hosts still use as via is rejected.

Daily Host Commands

# List configured hosts
sshx --host-list

# Test one host
sshx --host-test=prod-web

# Test every host with a per-host dial timeout
sshx --host-test-all

# Update a host
sshx --host-update --host-name=prod-web -u=deploy -i=~/.ssh/prod-web-2026.pem

# Change or clear the persisted source bind
sshx --host-update --host-name=prod-web --bind=192.0.2.10
sshx --host-update --host-name=prod-web --bind=

# Remove a host
sshx --host-remove=old-lab

Practical Naming Patterns

Use names that explain both role and environment:

prod-web-1
prod-db-primary
staging-api
lab-router
customer-a-jump

Use password keys that do not expose sensitive topology in public logs. For shared runbooks, prefer placeholders:

sshx -h=prod-web -pk=<sudo-key> "sudo systemctl reload nginx"

Team And Agent Use

For human operators, named hosts reduce typing errors. For automation agents, they create a stable boundary:

  • The agent receives prod-web, not a raw IP and key path.
  • The operator can review ~/.sshx/settings.json.
  • --dry-run --json can confirm which address, port, user, key, and sudo key would be used.
  • Audit events can record the resolved host without storing secrets.