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

Usage Scenarios

This page is intentionally example-heavy. Treat the host names as placeholders and adapt the commands to your own runbooks.

Scenario 1: First Health Check

You just received access to a server and want a low-risk check.

ssh-keyscan -H prod-web >> ~/.ssh/known_hosts
sshx -h=prod-web -u=deploy "hostname && uptime && whoami"

Why this is useful: it verifies host trust, authentication, the remote user, and basic reachability without changing the server.

Scenario 2: Add A Production Host Once

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

sshx --host-test=prod-web
sshx -h=prod-web "hostname"

Why this is useful: future commands no longer repeat IP, user, key path, and sudo key.

Scenario 3: Check A Service Without Changing It

sshx -h=prod-web "systemctl is-active nginx"
sshx -h=prod-web "systemctl status nginx --no-pager"

For automation:

sshx -h=prod-web --json "systemctl is-active nginx"

Scenario 4: Restart A Service With Review

sshx -h=prod-web --dry-run --json "sudo systemctl restart nginx"
sshx -h=prod-web -pk=prod-web-sudo "sudo systemctl restart nginx"
sshx -h=prod-web "systemctl is-active nginx"

Why this is useful: the dry-run confirms local interpretation before a privileged change.

Scenario 5: Check Disk Pressure On Several Servers

for host in prod-web prod-api prod-db; do
  echo "== $host =="
  sshx -h="$host" --timeout=15s "df -h / /var /data"
done

Agent-friendly version:

for host in prod-web prod-api prod-db; do
  sshx -h="$host" --timeout=15s --json "df -h / /var /data"
done

Scenario 6: Collect Logs For An Incident

mkdir -p incident-2026-07-01/prod-web
sshx -h=prod-web --download=/var/log/nginx/error.log --to=incident-2026-07-01/prod-web/error.log
sshx -h=prod-web --download=/var/log/nginx/access.log --to=incident-2026-07-01/prod-web/access.log
sshx -h=prod-web --audit-output=incident-2026-07-01/audit "journalctl -u nginx --since '30 min ago' --no-pager"

Why this is useful: downloaded evidence and local audit metadata stay next to the incident folder.

Scenario 7: Upload A Config Safely

sshx -h=prod-web --upload=./nginx.conf --to=/tmp/nginx.conf
sshx -h=prod-web "sudo nginx -t -c /tmp/nginx.conf"
sshx -h=prod-web "sudo install -m 0644 /tmp/nginx.conf /etc/nginx/nginx.conf"
sshx -h=prod-web "sudo nginx -t"
sshx -h=prod-web "sudo systemctl reload nginx"

Why this is useful: the file is staged and validated before replacing the production config.

Scenario 8: Use Different Sudo Keys Per Host

sshx --password-set=prod-web-sudo
sshx --password-set=prod-db-sudo

sshx -h=prod-web -pk=prod-web-sudo "sudo systemctl reload nginx"
sshx -h=prod-db -pk=prod-db-sudo "sudo systemctl status postgresql"

Why this is useful: one operator can manage several servers without reusing one global sudo key.

Scenario 9: Validate Every Configured Host

sshx --host-test-all

Run this after rotating keys, changing VPN access, or importing a new settings.json.

Scenario 10: Script A Safe Status Report

for host in prod-web prod-api prod-db; do
  sshx -h="$host" --timeout=20s --json "hostname && uptime" \
    | jq --arg host "$host" '{alias: $host, success, exit_code, error_kind, stdout}'
done

Why this is useful: scripts read JSON fields instead of scraping terminal prose.

Scenario 11: Bound A Risky Long-Running Command

sshx -h=prod-web --timeout=2m "sudo apt-get update"

Why this is useful: unattended commands should not hang forever.

Scenario 12: Diagnose A Host-Key Failure

If a host key changed, do not bypass it first. Check why it changed.

ssh-keygen -F prod-web
ssh-keyscan -H prod-web

Only update known_hosts after confirming the machine was rebuilt, reinstalled, or intentionally rotated.

Scenario 13: Avoid Shell-Pipe Installers

This command pattern is intentionally high risk:

sshx -h=prod-web "curl -fsSL https://example.invalid/install.sh | sh"

Safer pattern:

sshx -h=prod-web "curl -fsSL https://example.invalid/install.sh -o /tmp/install.sh"
sshx -h=prod-web "less /tmp/install.sh"
sshx -h=prod-web "sha256sum /tmp/install.sh"
sshx -h=prod-web "sh /tmp/install.sh"

Scenario 14: Use PTY Only When Needed

sshx -h=prod-web --pty "sudo visudo -c"

Prefer non-PTY for scripts because it preserves stdout and stderr separation.

Scenario 15: Disable Audit For A Single Sensitive Run

If command text itself would reveal sensitive context, disable audit for that invocation and record the reason in your own runbook.

SSHX_NO_AUDIT=true sshx -h=prod-web "echo redacted"

Do not use this as a default. Audit events are useful for explaining what happened.

Scenario 16: Check Docker Without Opening A Shell

sshx -h=prod-web --json "docker ps --format '{{json .}}' | head -20"
sshx -h=prod-web "docker inspect nginx --format '{{.State.Status}} {{.RestartCount}}'"

Why this is useful: operators can collect container state without starting an interactive SSH session or copying broad logs.

Scenario 17: Verify A Deployment Artifact Before Releasing

sshx -h=prod-web --upload=./dist/app.tar.gz --to=/tmp/app.tar.gz
sshx -h=prod-web "sha256sum /tmp/app.tar.gz"
sshx -h=prod-web "tar -tzf /tmp/app.tar.gz | head"

Only install the artifact after the checksum and archive contents match the release note.

Scenario 18: Rotate A Service Config With Rollback

sshx -h=prod-web --upload=./service.env --to=/tmp/service.env.new
sshx -h=prod-web "sudo cp /etc/myapp/service.env /etc/myapp/service.env.bak.\$(date +%Y%m%d%H%M%S)"
sshx -h=prod-web "sudo install -m 0600 /tmp/service.env.new /etc/myapp/service.env"
sshx -h=prod-web "sudo systemctl restart myapp"
sshx -h=prod-web --json "systemctl is-active myapp"

Why this is useful: the backup, install mode, restart, and health check are separate visible steps.

Scenario 19: Collect A Minimal Support Bundle

mkdir -p support/prod-web
sshx -h=prod-web --download=/etc/os-release --to=support/prod-web/os-release
sshx -h=prod-web --audit-output=support/audit "uname -a"
sshx -h=prod-web --audit-output=support/audit "df -h"
sshx -h=prod-web --audit-output=support/audit "free -m"

Do not download private application data unless the support case explicitly needs it.

Scenario 20: Use -- When Remote Flags Look Like Local Flags

sshx -h=prod-web -- docker run --rm alpine:3.20 sh -c 'echo hello'
sshx -h=prod-web -- echo --force belongs-to-the-remote-command

Why this is useful: -- makes the boundary between local sshx flags and remote command arguments obvious.

Scenario 21: Test A New Host Entry Before Sharing It

sshx --host-add --host-name=staging-api -h=10.0.8.21 -u=deploy -i=~/.ssh/staging.pem -pk=staging-api-sudo
sshx --host-test=staging-api
sshx -h=staging-api --dry-run --json "sudo systemctl reload api"

Only commit or share a runbook after the named host resolves, authenticates, and selects the expected sudo key.

Scenario 22: Keep A Migration Run Bounded

sshx -h=prod-db --timeout=10s --json "pg_isready"
sshx -h=prod-db --timeout=5m --dry-run --json "sudo systemctl restart postgresql"
sshx -h=prod-db --timeout=5m -pk=prod-db-sudo "sudo systemctl restart postgresql"
sshx -h=prod-db --timeout=30s --json "pg_isready"

Why this is useful: every step has a time budget and a machine-readable result.

Scenario 23: Remove A Temporary File With Evidence

sshx -h=prod-web --list=/tmp
sshx -h=prod-web --rm=/tmp/app.tar.gz
sshx -h=prod-web --list=/tmp

Deletion should be visible before and after. For high-risk paths, prefer a remote mv into a dated quarantine directory before permanent removal.

Scenario 24: Fail Closed In CI

result="$(sshx -h=prod-web --timeout=20s --json "systemctl is-active nginx")"
printf '%s\n' "$result" | jq .
printf '%s\n' "$result" | jq -e '.success == true and .stdout == "active\n"'

Why this is useful: CI fails when the structured result is missing, the command fails, or the service state is not exactly what the runbook expects.