purple. Your ssh config, synced with your cloud.

Spin up a VM and it's in your host list before the console catches up. Kill one and purple marks it stale, so your list never lies. Everything else you do over SSH lives in the same terminal.

purplehoststunnelscontainerssnippetskeys322731bastion-amsNAMETAGSLAST▾ops@140.82.121.3:22online(7ms)checkedjustnowbastion-amsproduction<1mdb-primaryproduction1hCONNECTIONmonitoringproduction2hHost140.82.121.3gateway-vpninfra3hUseropspodman-edgeedge4hKeyid_ed25519prod-eu1production5hPasswordkeychainprod-eu2production6hPing7mscustomer-jumpcustomer7hcustomer-db-1customer8hACTIVITYlegacy-prodproduction9hLastSSH<1magoaws-api-prodproduction10hConnections247aws-api-stagingstaging11haws-worker-euproduction12haws-batch-usproduction13h······aws-ml-euml14h1y~6monowdo-work-web-amsproduction16hdo-work-staging-amsstaging17hTAGSdo-work-worker-amsworker18hproduction,vpndo-work-ci-runnerci19hdo-personal-blogpersonal20hTUNNELSdo-personal-mailpersonal21hD1080pve-web-01web22hL8443internal.corp:443pve-web-02web23hpve-db-01database1dSNIPPETSpve-db-02database1d10available(rtorun)pve-rediscache1dgetpurple.shCONTAINERSEnterconnect/search#tagvcompact:jump?morepurplehoststunnelscontainerssnippetskeyssearch:28/32bastion-amsNAMEADDRESSops@140.82.121.3:22online(7ms)checkedjustnowbastion-ams140.82.121.3db-primary10.30.1.5:5433CONNECTIONdb-protondb1.example.comHost140.82.121.3monitoring10.30.2.10Useropsgateway-vpn185.199.108.5Keyid_ed25519podman-edge10.20.30.40Passwordkeychainprod-eu1195.144.107.61Ping7msprod-eu2195.144.107.62customer-jump198.51.100.10ACTIVITYlegacy-prod203.0.113.45LastSSH<1magoaws-api-prod52.47.100.23Connections247aws-api-staging52.47.100.24aws-worker-eu3.120.55.17aws-batch-us52.47.100.25······do-work-web-ams104.248.38.911y~6monowdo-work-staging-ams104.248.38.92do-work-worker-ams104.248.38.93TAGSdo-personal-blog167.99.42.10production,vpndo-personal-mail167.99.42.11pve-web-01192.168.1.20TUNNELSpve-web-02192.168.1.21D1080pve-db-01192.168.1.30L8443internal.corp:443pve-db-02192.168.1.31pve-redis192.168.1.40SNIPPETSpve-mail192.168.1.5010available(rtorun)getpurple.sh/p_(28of32)EnterconnectCtrl+EeditEsccanceltag:fuzzytag=exactpurplehoststunnelscontainerssnippetskeyssearch:19/32bastion-amsNAMEADDRESSTAGSops@140.82.121.3:22online(7ms)checkedjustnowbastion-ams140.82.121.3productionvpndb-primary10.30.1.5:5433productiondatabaseCONNECTIONdb-protondb1.example.comproductiondatabaseHost140.82.121.3monitoring10.30.2.10productionmonitoringUseropsprod-eu1195.144.107.61productionapieuKeyid_ed25519prod-eu2195.144.107.62productionapieuPasswordkeychainlegacy-prod203.0.113.45productionlegacyPing7msaws-api-prod52.47.100.23productionapiawsaws-worker-eu3.120.55.17productionworkerawsACTIVITYaws-batch-us52.47.100.25productionbatchawsLastSSH<1magodo-work-web-ams104.248.38.91productionwebdigitaloceanConnections247pve-web-01192.168.1.20webinternalproxmoxpve-web-02192.168.1.21webinternalproxmoxpve-db-01192.168.1.30databaseinternalproxmox······pve-db-02192.168.1.31databaseinternalproxmox1y~6monowpve-redis192.168.1.40cacheinternalproxmoxpve-mail192.168.1.50mailinternalproxmoxTAGSpve-monitor192.168.1.60monitoringinternalproxmoxproduction,vpnpve-backup192.168.1.70backupinternalproxmoxTUNNELSD1080L8443internal.corp:443SNIPPETS10available(rtorun)getpurple.sh/pr_(19of32)EnterconnectCtrl+EeditEsccanceltag:fuzzytag=exactpurplehoststunnelscontainerssnippetskeyssearch:19/32bastion-amsNAMEADDRESSTAGSops@140.82.121.3:22online(7ms)checkedjustnowbastion-ams140.82.121.3productionvpndb-primary10.30.1.5:5433productiondatabaseCONNECTIONdb-protondb1.example.comproductiondatabaseHost140.82.121.3monitoring10.30.2.10productionmonitoringUseropsprod-eu1195.144.107.61productionapieuKeyid_ed25519prod-eu2195.144.107.62productionapieuPasswordkeychainlegacy-prod203.0.113.45productionlegacyPing7msaws-api-prod52.47.100.23productionapiawsaws-worker-eu3.120.55.17productionworkerawsACTIVITYaws-batch-us52.47.100.25productionbatchawsLastSSH<1magodo-work-web-ams104.248.38.91productionwebdigitaloceanConnections247pve-web-01192.168.1.20webinternalproxmoxpve-web-02192.168.1.21webinternalproxmoxpve-db-01192.168.1.30databaseinternalproxmox······pve-db-02192.168.1.31databaseinternalproxmox1y~6monowpve-redis192.168.1.40cacheinternalproxmoxpve-mail192.168.1.50mailinternalproxmoxTAGSpve-monitor192.168.1.60monitoringinternalproxmoxproduction,vpnpve-backup192.168.1.70backupinternalproxmoxTUNNELSD1080L8443internal.corp:443SNIPPETS10available(rtorun)getpurple.sh/pro_(19of32)EnterconnectCtrl+EeditEsccanceltag:fuzzytag=exactpurplehoststunnelscontainerssnippetskeyssearch:11/32bastion-amsNAMEADDRESSTAGSops@140.82.121.3:22online(7ms)checkedjustnowbastion-ams140.82.121.3productionvpndb-primary10.30.1.5:5433productiondatabaseCONNECTIONdb-protondb1.example.comproductiondatabaseHost140.82.121.3monitoring10.30.2.10productionmonitoringUseropsprod-eu1195.144.107.61productionapieuKeyid_ed25519prod-eu2195.144.107.62productionapieuPasswordkeychainlegacy-prod203.0.113.45productionlegacyPing7msaws-api-prod52.47.100.23productionapiawsaws-worker-eu3.120.55.17productionworkerawsACTIVITYaws-batch-us52.47.100.25productionbatchawsLastSSH<1magodo-work-web-ams104.248.38.91productionwebdigitaloceanConnections247······1y~6monowTAGSproduction,vpnTUNNELSD1080L8443internal.corp:443SNIPPETS10available(rtorun)getpurple.sh/prod_(11of32)EnterconnectCtrl+EeditEsccanceltag:fuzzytag=exactpurplehoststunnelscontainerssnippetskeysNAMEFORWARDSPEEDUPTIMELAST▾bastion-ams1080any796.9KB/s12m47snowbastion-ams8443internal.corp:443796.9KB/s12m47snowdb-primary5432localhost:5432335.9KB/s47m12snowdb-primary9090localhost:9090335.9KB/s47m12snowmonitoring3000localhost:30005.9KB/s2h14mnowdo-work-staging-ams5432localhost:5432105.5KB/s5m22snowpve-db-015432localhost:5432259.8KB/s22m4snowpve-redis6379localhost:6379140.6KB/s8m33snowpve-monitor3000localhost:300062.5KB/s18m41snowpve-monitor9090localhost:909062.5KB/s18m41snowgetpurple.shactive·up12m47scurl:51209·3s[pid9412]214.8KB/sGhosttypsql:54321·4s[pid8123]500.0KB/sGhosttyssh:54398·12s[pid8200]23.4KB/sSafari2conn1m02s31.2KB/sch#25socks4sch#23socks38sch#20direct1m35sch#24socks8sEnterstop/searchssort:jump?morepurplehoststunnelscontainerssnippetskeys29NAMEIMAGEUPTIMEaws-api-stagingapimyteam/api:v4.1.0-rc22ddatadog-agentdatadog/agent:72dnginxnginx:1.25-alpine2dredisredis:7-alpine2daws-batch-usbastion-amsapp-backendmyapp:v2.14.112dcertbotcertbot/certbot:v2.7-grafanagrafana/grafana:10.25dnginx-proxynginx:1.25-alpine12dpostgrespostgres:16-alpine12dprometheusprom/prometheus:v2.485dredisredis:7-alpine12ddb-primarypg-exporterprometheuscommunity/postgres-exporter:0.1530dpgbouncerpgbouncer:1.2130dpostgres-primarypostgres:16-alpine30ddo-work-web-amsappmyapp:3.2.18dnginxnginx:1.258dredisredis:7-alpine8dsidekiqmyapp:3.2.1-workermyapp:3.2.18dgateway-vpnpiholepihole/pihole:2024.0745dgetpurple.shEntershell/searchllogsvcompact:jump?morepurplehoststunnelscontainerssnippetskeysSnippets(10)OVERVIEWNAMEPARAMSDESCRIPTIONPullandrollaserviceuptime·ServeruptiParameters2disk-usage·RootdiskuDefaulthostsprod-eu1,prod-eu2,aws-api-proddocker-ps·Runningcontail-logs·Last50sysTRACKRECORD97%reliablerestart-nginx·Restartngideploy2Pullandro100backup-db1Snapshotalog-rotate·Forcealog0container-prune·Showdiskulast2hago·28of29hostrunsok·1partialcertbot-renew·RenewLet'sCOMMANDcd/opt/{{app}}&&gitpull&&dockercomposepull&&dockercomposeup-d--no-deps{{service:web}}PARAMETERSapprequiredservice=webIMPACT·writesstateoneachhost·dockercomposeup:changesrunningstate·runsoneveryhostyouselectEnterrun/searchaaddeeditddelvcompact:jump?morepurplehoststunnelscontainerssnippetskeysVAULTSSH4activegateway-vpnssh-client-signer/sign/infra7h0maws-api-prodssh-client-signer/sign/admin6h0mprod-eu1ssh-client-signer/sign/admin5h0mprod-eu2ssh-client-signer/sign/admin1:30KEYS1/5id_ed25519yubikey_workStrength95/100customer-xPassphraseencryptedid_rsa_legacy=*@@/Agentloadedid_rsa.bakoE=+B#Modified2024-03-27(2yago)...==TypeED25519256....XFingerprintSHA256:dGVzdGRlbW9rZXlmb3JwdXJwbGVzc2gNcAdGhISB=Path~/.ssh/id_ed25519.o+Commenteric@MacBook.+Linked3Usedjustnow··························30d~2wnowLINKEDHOSTS3bastion-ams140.82.121.3<1magoaws-api-prod52.47.100.2310hagoaws-api-staging52.47.100.2411hagoEntercopyppushVsigncert:jump?more
$ curl -fsSL getpurple.sh | sh
or brew install erickochen/purple/purple cargo install purple-ssh nix profile install github:erickochen/purple paru -S purple-bin

purple is a free, open-source terminal SSH manager and SSH config editor in Rust for macOS and Linux that keeps ~/.ssh/config in sync with 16 cloud providers, monitors live SSH tunnels and manages Docker and Podman containers fleet-wide.

16 cloud providers 7,300+ tests Single Rust binary MIT licensed No account, no telemetry

I had a perfectly good SSH config. Clean, well-organized, no complaints. That part worked.

What didn't work was the six other things I needed to do every day. Every container check was ssh, docker ps, scroll, repeat. Every file transfer was remembering scp flags. Every new cloud VM meant opening a console, copying an IP, editing my config by hand. And running the same command across a dozen hosts? That was either a bash loop or a whole Ansible setup for a one-liner.

So I put all of it in one terminal.

One terminal. Five hundred servers. Zero tabs.

purple cloud provider list close-up: per-provider sync status with host counts and stale markers

Your ssh config tracks your infra

Drop in one API token per provider. New machines land in ~/.ssh/config the moment they boot, IPs follow instances as they move and decommissioned hosts grey out instead of lingering. 16 providers, multiple accounts each, side by side.

purple host detail close-up: connection info, ping, password source and a one-year activity sparkline

Everything at a glance, no editor required

One panel answers the questions you actually have. Is it up. How do I reach it. When was I last on it. What runs there. Connection info, jump route, a year of SSH activity, tags, tunnels and containers per host. Underneath sits a real ~/.ssh/config editor with round-trip fidelity: your hand-written config stays yours.

purple Jump bar close-up: universal fuzzy search across hosts, tunnels, containers, snippets and actions

Jump to anything with one keystroke

Press : and type four letters. Any host, tunnel, container, snippet or action, ranked by how often you use it. It searches the SSH User, ProxyJump and Vault SSH role too, and field prefixes (user:, proxy:, vault:, tag:) cut straight to one directive. Like Linear's Cmd+K, but in your terminal.

purple Containers tab close-up: containers across multiple hosts grouped per host with state and uptime

Manage Docker and Podman on every server, over SSH

Your whole fleet's containers in one list, grouped per host. Shell in, stream logs, restart, stop, exec or cycle a compose stack member by member. No agent on the remote, no web UI, no extra ports. Just SSH.

purple tunnel detail close-up: per-client process roster with live throughput sparklines and a channel swimlane

Monitor SSH tunnels in real time

Forwards run blind. purple doesn't: every Local, Remote and Dynamic SOCKS forward with live throughput, channel activity and uptime, down to the exact app behind each connection. curl, psql, Safari: caught in the act.

purple snippet detail close-up: command with parameters, a blast-radius impact card and a host-run track record

Run one command across your fleet

Save a command once, run it on any set of hosts. purple shows the blast radius before you fan out and keeps the track record per snippet. "28 of 29 host runs ok" is a number you want to see before production.

purple key detail close-up: randomart fingerprint, strength score, agent status and per-key activity

Push any SSH key to your fleet, no ssh-copy-id loop

Every key in ~/.ssh, scored and fingerprinted, with the hosts it unlocks and the last time it was used. Push one to your whole fleet with p. Vault-managed hosts skip automatically, so cert-managed stays cert-managed.

purple Vault SSH close-up: signed certificates with remaining TTL bars per host

Short-lived SSH certificates, signed by Vault

Permanent keys on production are a standing liability. purple signs short-lived certificates via the HashiCorp Vault SSH secrets engine, bulk-signs the fleet with V and shows every certificate's remaining TTL. Renewal is automatic.

See it in motion

And more

📂 Browse and copy files between machines. Dual-pane file explorer. Local filesystem on one side, remote on the other. Handles ProxyJump chains and tunnels.
🔑 Passwords handled for you. Auto-filled at connect time from OS Keychain, 1Password, Bitwarden, pass, the HashiCorp Vault KV secrets engine, Proton Pass or a custom script.
🤖 Let AI agents manage your servers. Built-in MCP server with one-click .mcpb install for Claude Desktop. Works with Claude Code, Cursor, Windsurf and any MCP-compatible agent. Read-only mode keeps agents on a leash and every call lands in the audit log.
📬 Release notes in the TUI. A summary of everything that changed since you last opened purple, right on startup. Press n to reopen.
Syncs with 16 cloud providers
AWS EC2AzureDigitalOceanGCPHetzneri3D.netLeasewebLinodeOracle CloudOVHcloudProxmox VEScalewayTailscaleTransIPUpCloudVultr

How purple compares

purpleTermiussshsLazydocker
Open sourceYes (MIT)NoYesYes
LanguageRustElectronRustGo
Multi-cloud SSH sync16 providersLimitedNoNo
Containers over SSHDocker and Podman, fleet-wideNoNoLocal host only
Live tunnel monitoringYesNoNoNo
MCP server for AI agentsYesNoNoNo
Account requiredNoYesNoNo
PriceFreeFreemiumFreeFree

Your ~/.ssh/config, true to production. Always.

FAQ
PURPLE(1)General Commands ManualPURPLE(1)
What is purple SSH?
purple is a free, open-source terminal SSH manager and SSH config editor in Rust for macOS and Linux that keeps ~/.ssh/config in sync with 16 cloud providers, monitors live SSH tunnels and manages Docker and Podman containers fleet-wide. New VMs appear in your host list automatically and decommissioned hosts dim. Plus instant fuzzy search, visual file transfer, command snippets, multi-host SSH key push, short-lived HashiCorp Vault SSH certificates and automatic password management. Single binary, no account, no telemetry.
Is purple a free, open source Termius alternative?
Yes. purple is free, MIT licensed, needs no account and runs natively in your terminal. It edits your real ~/.ssh/config with round-trip fidelity instead of locking hosts in a proprietary database, and it syncs with 16 cloud providers. You also get live SSH tunnel monitoring, fleet-wide Docker and Podman management and an MCP server for AI agents, which Termius does not offer. Termius remains the better fit if you want mobile apps or a desktop GUI; for terminal workflows purple covers everything.
Is purple an SSH bookmark manager?
Yes. purple stores every SSH host in ~/.ssh/config as a named bookmark, fuzzy-searches them by alias, hostname or tag and connects on Enter. Frecency sorting keeps your most-used bookmarks on top. purple also keeps your bookmarks in sync with 16 cloud providers and signs short-lived Vault SSH certificates.
What cloud providers does purple support?
purple keeps ~/.ssh/config in sync with 16 cloud providers: AWS EC2, Azure, DigitalOcean, GCP (Compute Engine), Hetzner, i3D.net, Leaseweb, Linode (Akamai), Oracle Cloud Infrastructure (OCI), OVHcloud, Proxmox VE, Scaleway, Tailscale, TransIP, UpCloud and Vultr. Drop in one API token per provider. New VMs appear in your host list automatically. Decommissioned hosts dim. No manual ssh config edits.
How do I sync AWS EC2 instances with purple?
In the TUI, press S to open the provider list, then add AWS. Select your regions from the region picker and fill in your credentials profile or access key. The CLI alternative is purple provider add aws --profile default --regions us-east-1,eu-west-1. EC2 tags are synced (excluding internal aws:* tags). AMI names are resolved for OS metadata.
How do I sync Google Cloud (GCP) instances with purple?
In the TUI, press S to open the provider list, then add GCP. Fill in your service account JSON key file path, project ID and optionally specific zones. Purple reads the key, creates a JWT and exchanges it for an access token automatically. The CLI alternative is purple provider add gcp --token /path/to/sa-key.json --project my-project.
How do I sync Azure VMs with purple?
In the TUI, press S to open the provider list, then add Azure. Fill in your service principal JSON file path and subscription IDs. Supports both az CLI and portal credential formats. The CLI alternative is purple provider add azure --token /path/to/sp.json --regions SUBSCRIPTION_ID.
How do I sync Oracle Cloud Infrastructure (OCI) instances with purple?
In the TUI, press S to open the provider list, then add Oracle. Fill in your OCI config file path, compartment OCID and regions. The CLI alternative is purple provider add oracle --token ~/.oci/config --compartment OCID --regions eu-amsterdam-1. Requires IAM policies: read instance-family and read virtual-network-family.
How do I monitor SSH tunnels in the terminal?
Press Tab from the host list to switch to the dedicated Tunnels page. Every SSH forward across all your hosts shows up in one sortable, searchable list with current throughput, uptime and a green dot when active. The detail panel on the right opens automatically for active tunnels and shows: a per-client process roster (PID, source port, age, current bytes per second, sparkline of recent throughput, responsible app reported by the OS), a 60-second swimlane of channel opens and closes (Direct channels for LocalForward and RemoteForward, Dynamic channels for SOCKS), and uptime, peak concurrent and total opens counters. Sort with s, search with /, add a tunnel with a or use T from the host list for the per-host tunnel overlay.
How do I manage Docker containers across multiple servers from one terminal?
Press Tab from the Hosts page until you reach purple's dedicated Containers page. Every Docker and Podman container across your fleet appears in one list, grouped per host. The detail panel summarises engine version, runtime, sync age and running counts when the cursor sits on a divider. Enter shells in. l tails the last 200 log lines. K restarts. S stops. e runs a one-off command. Ctrl-K cycles a compose stack member by member. R refreshes every host in parallel (max four at a time). Auto-detects Docker or Podman. No agent. No web UI. No extra ports.
Can I manage Docker or Podman containers with purple?
Yes. The Containers page lists every container across every cached host in one view, grouped per host. Enter shells in. l tails logs. K restarts. S stops. e runs a one-off command. Ctrl-K cycles a whole compose stack member by member. K or S on a host divider sweeps every running container on that host at once. The detail panel reads docker inspect once and remembers, so image digest, restart policy, mounts, network and healthcheck render instantly. Per-host C overlay still works on the Hosts page. Auto-detects Docker or Podman. No agent, no web UI, no extra ports.
How does purple compare to Lazydocker?
Lazydocker is built for one local host. purple's Containers page lists every container across every cached SSH host in one view: shell in, stream logs, restart, stop, exec or cycle a whole compose stack. R refreshes the whole fleet in parallel. K or S on a host divider sweeps every running container on that host at once. The detail panel reads docker inspect once and remembers, so image digest, restart policy, mounts, network and healthcheck render instantly. Use Lazydocker for single-host local management. Use purple for fleet-wide remote management.
Is purple a Portainer alternative?
For container visibility and lifecycle control (shell, logs, restart, stop, exec, stack restart) over SSH, yes. The Containers tab lists every container across every host, grouped per host. No agent to install, no web UI to host, no ports to open. Works with Docker and Podman. Purple does not provide container creation, registry management or role-based access control.
Can AI assistants use purple?
Yes. Run curl -fsSL getpurple.sh | sh, then purple mcp to start the MCP server. Claude Code, Cursor, Windsurf and other agents get five tools: list_hosts, get_host, run_command, list_containers and container_action. Pass --read-only to restrict it to list_hosts, get_host and list_containers. Every call is logged to ~/.purple/mcp-audit.log by default (JSON Lines, mode 0o600, run_command body redacted). Claude Desktop users can install the .mcpb bundle from GitHub releases for a one-click setup. Full setup guide on the wiki.
Can I transfer files between local and remote servers with purple?
Yes. Press F on any host to open the remote file explorer. It shows local files on the left and the remote server on the right. Navigate directories, select files and copy them between machines via scp. Works through ProxyJump chains, password sources and active tunnels.
How do command snippets work in purple?
Save commands and run them on remote hosts via SSH. In the TUI, press r to run on the selected host, Space to multi-select hosts then r, or R to run on all visible hosts. purple shows a command's blast radius before you fan it out and tracks every run per snippet. The CLI alternative supports tag-based targeting (--tag prod) and parallel execution (--parallel). Snippets are stored locally in ~/.purple/snippets.
How does SSH password management work in purple?
Set a password source per host via the TUI or a global default. When you connect, purple acts as SSH_ASKPASS and retrieves the password automatically. Supported sources: OS Keychain, 1Password, Bitwarden, pass, HashiCorp Vault KV secrets engine, Proton Pass and custom commands. For short-lived SSH certificates purple also integrates with the HashiCorp Vault SSH secrets engine (a separate engine).
Does purple modify my existing SSH config?
Only when you add, edit, delete or sync. All writes are atomic with automatic backups. Auto-sync runs on startup for providers that have it enabled (configurable per provider).
Will purple break my SSH config comments or formatting?
No. purple preserves comments, indentation and unknown directives through every read-write cycle. Consecutive blank lines are collapsed to one.
Does purple need a daemon or background process?
No. purple is a single Rust binary. Run it, use it, close it. No runtime, no daemon, no async framework.
Does purple send my SSH config anywhere?
No. Your config never leaves your machine. Provider sync calls cloud APIs to fetch server lists. The TUI checks GitHub for new releases on startup (cached for 24 hours). No config data is transmitted.
Can I use purple with SSH Include files?
Yes. Hosts from Include files are displayed in the TUI but never modified. purple resolves Include directives recursively (up to depth 16) with tilde and glob expansion.
How do I troubleshoot connection problems?
Run with --verbose to enable debug logging, then purple logs --tail in another terminal. Logs are written to ~/.purple/purple.log with fault domain prefixes: [external] for remote/tool errors, [config] for local config issues. Set PURPLE_LOG=trace for maximum detail.
purple v3.22.12026-07-07PURPLE(1)

One command to install. One search to any server after that.

$ curl -fsSL getpurple.sh | sh