README
ยถ
$$$$$$\ $$$$$$\ $$\ $$\ $$\ $$\
$$ __$$\ $$ __$$\ $$ | $$ |$$ | $$ |
$$ / \__|$$ / \__|$$ | $$ |\$$\ $$ |
\$$$$$$\ \$$$$$$\ $$$$$$$$ | \$$$$ /
\____$$\ \____$$\ $$ __$$ | $$ $$<
$$\ $$ |$$\ $$ |$$ | $$ |$$ /\$$\
\$$$$$$ |\$$$$$$ |$$ | $$ |$$ / $$ |
\______/ \______/ \__| \__|\__| \__|
Secure SSH & SFTP Client with Built-in Password Manager
SSHX
sshx is a barrier-free, cross-platform SSH/SFTP command-line client with a built-in system keyring password manager, making it easy to manage and operate multiple remote servers.
Why You Need It?
Managing multiple servers means juggling different passwords and repeatedly entering sudo passwords. sshx securely stores passwords in your system keyring and auto-fills sudo passwords, so you can run commands across many servers without the password hassle. One command, multiple servers, zero password hassle.
New! Host Configuration Management - Store your frequently used host configurations in ~/.sshx/settings.json and connect with just a name instead of typing full connection details every time. Each host can have its own SSH private key. Add hosts interactively!
Project Structure
cmd/sshx: Main binary entry point, responsible for command-line argument parsing and password management features.internal/sshclient: Core SSH/SFTP/script execution logic and command security validation.internal/app: CLI command routing, host configuration management, and password management.
Key Features
- Cross-platform SSH/SFTP operations (supports sudo auto-fill).
- Password management (Keychain / Secret Service / Credential Manager).
- Host configuration management with per-host SSH keys.
- Script execution and command security validation.
Installation
Quick Install with Go (Recommended for Go Users)
If you have Go 1.21+ installed, you can use Go's built-in tools:
Run directly without installation (like npx)
# Run the latest version
go run github.com/talkincode/sshx/cmd/sshx@latest --help
# Run specific version
go run github.com/talkincode/sshx/cmd/sshx@v0.0.6 -h=192.168.1.100 "uptime"
Install globally
# Install latest version to $GOPATH/bin
go install github.com/talkincode/sshx/cmd/sshx@latest
# Then use it anywhere
sshx --help
sshx -h=192.168.1.100 "uptime"
Note: Make sure $GOPATH/bin (typically ~/go/bin) is in your PATH.
One-Line Installation Script
Linux / macOS
curl -fsSL https://raw.githubusercontent.com/talkincode/sshx/main/install.sh | bash
Or download and run:
wget https://raw.githubusercontent.com/talkincode/sshx/main/install.sh
chmod +x install.sh
./install.sh
Install specific version:
./install.sh v0.0.2
Windows
Open PowerShell as Administrator and run:
irm https://raw.githubusercontent.com/talkincode/sshx/main/install.ps1 | iex
Or download and run:
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/talkincode/sshx/main/install.ps1" -OutFile "install.ps1"
.\install.ps1
Install specific version:
.\install.ps1 -Version v0.0.2
Manual Installation
Download pre-built binaries from Releases:
Linux / macOS:
# Download and extract (replace <platform>-<arch> with your system)
tar -xzf sshx-<platform>-<arch>.tar.gz
# Move to system path
sudo mv sshx /usr/local/bin/
# Make executable
sudo chmod +x /usr/local/bin/sshx
# Verify installation
sshx --help
Windows:
- Download
sshx-windows-amd64.zip - Extract the archive
- Move
sshx.exeto a directory in your PATH (e.g.,C:\Program Files\sshx) - Or add the extracted directory to your system PATH
Build from Source
# Clone repository
git clone https://github.com/talkincode/sshx.git
cd sshx
# Build command-line tool
go build -o bin/sshx ./cmd/sshx
# Print the version (also exposed via the binary's --version flag)
make version
# Install to system (optional)
# Installs the binary to ~/.local/bin and the agent skill to ~/.agents/skills/sshx
make install
# Check the installed version
sshx --version
Quick Start
# Execute remote command
sshx -h=192.168.1.100 -u=root "uptime"
# Save password for easier access (interactive input)
sshx --password-set=root
# Or set password for specific host
sshx --password-set=192.168.1.100-root
# Execute command without password flag (uses saved password)
sshx -h=192.168.1.100 -u=root "df -h"
Agent / Scripting Mode
sshx is designed to be driven by scripts and AI agents, not just humans. The
command-execution path gives you a stable, machine-readable contract.
By default:
- stdout and stderr stay separate and stream live (no PTY, no terminal control characters mixed in).
- The remote command's exit status is propagated as
sshx's own exit code.
Exit codes
| Code | Meaning |
|---|---|
0 |
Command succeeded |
1..254 |
Remote command's exit status, propagated verbatim |
255 |
sshx-level failure (connect / auth / host-key / timeout / blocked) |
--json structured output
Add --json to get a single JSON object on stdout (diagnostics still go to
stderr, so stdout stays pure):
sshx -h=prod-web --json "systemctl is-active nginx"
{
"host": "192.168.1.100",
"port": "22",
"user": "root",
"command": "systemctl is-active nginx",
"exit_code": 0,
"success": true,
"stdout": "active\n",
"stderr": "",
"duration_ms": 142,
"auth_method": "key"
}
On an sshx-level failure the object has exit_code: -1 and a non-empty
error_kind (one of timeout, auth, host_key, connect, blocked,
exit_missing, config, error), so it is always distinguishable from a
remote command that happens to exit 255.
--timeout and --pty
# Kill the command if it runs longer than 30 seconds (also accepts 2m, etc.)
sshx -h=prod-web --timeout=30s "apt-get update"
# Opt back into a PTY for commands that insist on a terminal
# (note: a PTY merges stderr into stdout; it cannot be combined with --json)
sshx -h=prod-web --pty "top -b -n1"
The timeout can also be set via the SSH_TIMEOUT environment variable.
Host Configuration Management
NEW! Manage your frequently used hosts in ~/.sshx/settings.json for quick access.
Quick Setup
# Add hosts interactively
sshx --host-add
# Add host with command line options
sshx --host-add --host-name=prod-web -h=192.168.1.100 -u=root --host-desc="Production Web Server"
# Add a host that uses its own SSH private key
sshx --host-add --host-name=prod-db -h=192.168.1.200 -u=admin -i=~/.ssh/prod-db.pem
# List all configured hosts
sshx --host-list
# Test connection to a configured host
sshx --host-test=prod-web
# Use configured host (auto-resolves from settings)
sshx -h=prod-web "systemctl status nginx"
# Test every configured host and show auth methods
sshx --host-test-all
Configuration File Format
Location: ~/.sshx/settings.json
{
"key": "/Users/username/.ssh/id_rsa",
"hosts": [
{
"name": "prod-web",
"description": "Production Web Server",
"host": "192.168.1.100",
"port": "22",
"user": "root",
"password_key": "prod-web-password",
"type": "linux"
},
{
"name": "prod-db",
"description": "Production Database",
"host": "192.168.1.200",
"port": "22",
"user": "admin",
"key": "/Users/username/.ssh/prod-db.pem",
"type": "linux"
}
]
}
The top-level
keyis the default SSH private key for all hosts. A per-hostkeyoverrides the default for that host only.
Host Management Commands
--host-add- Add new host (interactive or with options)--host-list- List all configured hosts--host-test=<name>- Test connection to a host--host-test-all- Test connections to all hosts (per-host 10s dial timeout) and show auth method used--host-remove=<name>- Remove a host from configuration
Benefits:
- ๐ Store connection details once, use everywhere
- ๐ Connect with just a name:
sshx -h=prod-web "command" - ๐ Integrate with password manager for each host
- โ Test connections before use
Password Management
sshx provides secure password storage using the operating system's native credential manager, eliminating the need to enter passwords repeatedly or store them in plaintext.
Supported Platforms
- macOS: Uses Keychain Access
- Linux: Uses Secret Service (GNOME Keyring / KDE Wallet)
- Windows: Uses Credential Manager
Password Commands
Save Password
# Save default sudo password (interactive input, recommended)
sshx --password-set=master
# Save password for specific user
sshx --password-set=root
# Save password for specific host+user combination
sshx --password-set=192.168.1.100-root
# Set password inline (not recommended, insecure)
sshx --password-set=master:yourpassword
You will be prompted to enter the password securely (input is hidden).
Check Saved Password
# Check if password exists
sshx --password-check=master
sshx --password-check=root
# Output example:
# โ Password exists for key: master
List Saved Passwords
# List common password keys
sshx --password-list
# Output example:
# Checking password keys in system keyring...
# Service: sshx
#
# Common keys:
# โ master (exists)
# โ root (exists)
# sudo (not set)
Get Password
# Get stored password (for debugging)
sshx --password-get=master
# Output example:
# โ Password retrieved from system keyring
# Service: sshx
# Key: master
#
# Password: yourpassword
Delete Password
# Delete password
sshx --password-delete=master
sshx --password-delete=root
# Confirmation message:
# โ Password deleted from system keyring
# Service: sshx
# Key: master
Using Stored Passwords
Once a password is saved, sudo commands will automatically retrieve the password from system keyring:
# 1. First save sudo password
sshx --password-set=master
# 2. Execute sudo commands (automatically uses stored password)
sshx -h=192.168.1.100 -u=root "sudo systemctl status nginx"
sshx -h=192.168.1.100 -u=root "sudo reboot"
# 3. Multi-server scenario: save different passwords for different servers
sshx --password-set=server-A
sshx --password-set=server-B
sshx --password-set=server-C
# 4. Use -pk parameter to specify sudo password key temporarily
sshx -h=192.168.1.100 -pk=server-A "sudo systemctl restart nginx"
sshx -h=192.168.1.101 -pk=server-B "sudo systemctl restart nginx"
sshx -h=192.168.1.102 -pk=server-C "sudo systemctl restart nginx"
Host Key Verification ๐
sshx now enforces strict host key verification just like the OpenSSH client. Instead of silently trusting unknown hosts, the tool reads the trust store from ~/.ssh/known_hosts (or the path you provide) and aborts the connection if the host is missing or the key changes.
Ways to manage host keys:
- Add hosts manually (recommended):
ssh-keyscan -H <host> >> ~/.ssh/known_hosts - One-time automatic trust:
sshx --accept-unknown-host -h=<host> ...(or setSSH_ACCEPT_UNKNOWN_HOST=1). The first connection records the key; subsequent runs stay strict. - Custom trust store:
sshx --known-hosts=/path/to/known_hostsorSSH_KNOWN_HOSTS=/path/to/known_hosts. - Legacy insecure mode (last resort):
sshx --insecure-hostkey ...orSSH_INSECURE_HOST_KEY=1. This re-enables the previousInsecureIgnoreHostKeybehavior and should only be used in controlled environments.
If the host key ever changes, sshx clearly explains how to remove the old entry before re-connecting, protecting you from potential man-in-the-middle attacks.
Password Key Names
- master: Default sudo password key name, used for sudo commands
- root: Password for root user
- Custom keys: You can use any key name, e.g.,
server-A,server-B,prod-db, etc.
Best Practices for Multi-Server Password Management
If you manage multiple servers with the same username but different passwords, use this strategy:
# Scenario: Manage 3 servers, all with root user but different passwords
# 1. Save password for each server (use meaningful key names)
sshx --password-set=prod-web # Production web server
sshx --password-set=prod-db # Production database server
sshx --password-set=dev-server # Development server
# 2. Execute commands using -pk parameter to specify password key
sshx -h=192.168.1.10 -u=root -pk=prod-web "sudo systemctl status nginx"
sshx -h=192.168.1.20 -u=root -pk=prod-db "sudo systemctl status mysql"
sshx -h=192.168.1.30 -u=root -pk=dev-server "sudo docker ps"
# 3. You can also use aliases to simplify commands (add to ~/.zshrc or ~/.bashrc)
alias ssh-prod-web='sshx -h=192.168.1.10 -u=root -pk=prod-web'
alias ssh-prod-db='sshx -h=192.168.1.20 -u=root -pk=prod-db'
alias ssh-dev='sshx -h=192.168.1.30 -u=root -pk=dev-server'
# Then use simply:
ssh-prod-web "sudo systemctl restart nginx"
ssh-prod-db "sudo systemctl restart mysql"
ssh-dev "sudo docker-compose up -d"
Sudo Key Environment Variables
You can customize the sudo password key name via environment variable (but using -pk parameter is more flexible):
# Use environment variable (can only specify one at a time, needs constant modification)
export SSH_SUDO_KEY=my-sudo-password
sshx --password-set=my-sudo-password
sshx -h=192.168.1.100 "sudo ls -la /root"
# Recommended: Use -pk parameter, more flexible, no need to modify environment variables
sshx -h=192.168.1.100 -pk=server-A "sudo ls -la /root"
sshx -h=192.168.1.101 -pk=server-B "sudo ls -la /root"
Security Notes
- โ Passwords are stored using OS-native encryption
- โ Passwords are never stored in plaintext
- โ Each host+user combination has a separate password entry
- โ Password input is hidden during entry
- โ ๏ธ Requires OS credential manager to be available
- โ ๏ธ On Linux, requires Secret Service daemon running (usually automatic with desktop environments)
Connection Environment Variables
You can use environment variables to avoid typing credentials repeatedly:
# Set in .env file or export in shell
export SSH_HOST=192.168.1.100
export SSH_USER=root
export SSH_PORT=22
export SUDO_PASSWORD=your_sudo_password
# Then run commands without flags
./bin/sshx "uptime"
SSH Authentication Preferences
sshxnow prioritizes SSH keys and automatically falls back to password authentication when the server rejects your key (for example when a host only allows passwords). As long as a password is available, the client will transparently retry with a password-only session.- Use
--no-key(alias--password-only) to disable key authentication for a single command. You can re-enable it by supplying--key=<path>again. - Set
SSH_DISABLE_KEY=truein your environment to permanently disable key authentication (useful on hosts that never accept keys). This override is respected even if a default key path exists in~/.sshx/settings.json. - When key auth is enabled and no explicit path is provided,
sshxstill auto-loads~/.ssh/id_rsa(or the path specified in settings) before falling back to passwords.
Log Level Configuration
You can control the logging verbosity using the SSHX_LOG_LEVEL environment variable:
# Set log level to DEBUG (shows detailed debugging information)
export SSHX_LOG_LEVEL=debug
# Set log level to INFO (default)
export SSHX_LOG_LEVEL=info
# Set log level to WARNING
export SSHX_LOG_LEVEL=warning
# Set log level to ERROR
export SSHX_LOG_LEVEL=error
Debug level logs include:
- Detailed SSH/SFTP operation processes
- Authentication method selection and fallback details
Example Workflow
# 1. Save sudo password (interactive input)
sshx --password-set=master
# Enter password for key 'master': ******
# 2. Verify it's saved
sshx --password-check=master
# โ Password exists for key: master
# 3. Use for SSH commands (sudo automatically uses stored password)
sshx -h=192.168.1.100 -u=root "sudo systemctl status docker"
sshx -h=192.168.1.100 -u=root "sudo df -h"
# 4. Use for SFTP operations
sshx -h=192.168.1.100 -u=root --upload=local.txt --to=/tmp/remote.txt
sshx -h=192.168.1.100 -u=root --download=/etc/hosts --to=./hosts.txt
# 5. List all saved password keys
sshx --password-list
# Common keys:
# โ master (exists)
# root (not set)
# 6. When done, optionally delete the password
sshx --password-delete=master
# โ Password deleted from system keyring
Troubleshooting
"sshx: command not found"
Solution:
- Ensure
/usr/local/bin(or your installation directory) is in your PATH - Restart your terminal after installation
- Or run with full path:
/usr/local/bin/sshx
macOS Security Warning
macOS may block the binary on first run:
sudo xattr -rd com.apple.quarantine /usr/local/bin/sshx
Or go to System Preferences โ Security & Privacy โ Click "Allow Anyway"
Windows SmartScreen Warning
Click "More info" and then "Run anyway" if Windows Defender SmartScreen shows a warning.
Permission Denied
# Make sure the binary has execute permissions
sudo chmod +x /usr/local/bin/sshx
Development
# Run tests
go test ./...
# Format code
gofmt -w .
# Build for all platforms
make build-all
# Run linter
make lint
The lint target requires
golangci-lintv2.6.1 or newer. Install it withgo install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.6.1.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Documentation โข Issues โข Discussions โข Releases
Made with โค๏ธ by talkincode