go-web-frame — Effortless auth: declare required permissions on routes, verify once in a Filter, keep handlers clean. Generic Model for full-stack CRUD: define a struct, and create/read/update/delete just works. Lightweight, install only the components you need. No code generation, no CI tooling required — the most elegant Go web full-stack framework.
A cross-platform implementation of sshpass (Windows, Linux & macOS), providing similar functionality to the Linux sshpass tool.
💡 Like this project? Give it a ⭐ Star — it helps others discover the tool!
- SSH login with password, private key, or ssh-agent authentication
- Execute remote commands or open interactive shell
- File upload/download via SFTP (with progress bar)
- SCP-style and Rsync-style file transfer
- Config file support for managing multiple servers
- Interactive shell with raw terminal mode (proper echo, Ctrl+C, and full-screen app support)
- Dynamic terminal resizing in interactive shell mode
- Git Bash path conversion detection and auto-fix
- IPv6 address support
- Support for Windows (x64, ARM64), Linux (amd64, arm64), and macOS (amd64, arm64)
- Reusable Go SDK — import as a library (
package sshpass) to embed SSH/SFTP/shell in your own app, with injectable I/O streams and progress callbacks - Port forwarding — local (
-L) and remote (-R) TCP port forwarding through SSH tunnels - SSH agent forwarding (
-A) — forward local ssh-agent to remote server, auto-detect agent when no credentials specified - JSON output mode (
-json) — structured JSON results for AI agents and automation - Proxy support — tunnel SSH connections through SOCKS5/SOCKS4/HTTP/HTTPS proxies
- Breakpoint resume — resume interrupted SFTP file transfers from where they left off
- File hash & verify — compute and verify local file hashes (MD5, SHA-1, SHA-256, SHA-512)
- Key generation — built-in SSH key pair generation (Ed25519 and RSA)
- Detached commands (
--bg) — start a service over SSH and return immediately, without the session hanging on it
Download the latest release from GitHub Releases:
| Architecture | Zip | MSI Installer |
|---|---|---|
| x64 (amd64) | win-sshpass-*-amd64.zip |
win-sshpass-*-amd64.msi |
| ARM64 | win-sshpass-*-arm64.zip |
win-sshpass-*-arm64.msi |
| Architecture | Tarball |
|---|---|
| amd64 | win-sshpass-*-linux-amd64.tar.gz |
| arm64 | win-sshpass-*-linux-arm64.tar.gz |
| Architecture | PKG Installer | Tarball |
|---|---|---|
| amd64 (Intel) | win-sshpass-*-darwin-amd64.pkg |
win-sshpass-*-darwin-amd64.tar.gz |
| arm64 (Apple Silicon) | win-sshpass-*-darwin-arm64.pkg |
win-sshpass-*-darwin-arm64.tar.gz |
The
.pkginstaller places the binary at/usr/local/bin/win-sshpassautomatically.
- Go to Releases page
- Download the package for your platform and architecture
- Windows MSI / macOS PKG: run the installer — it will add the binary to your system PATH automatically
- Windows Zip / Linux tar.gz / macOS tar.gz: extract and place the binary in your PATH
Zero dependencies:
win-sshpass.exeis a standalone binary. No need to install OpenSSH or any other software. Download it, put it in your PATH, and you're ready to go.
scoop bucket add chuccp https://github.com/chuccp/scoop-bucket
scoop install win-sshpasswinget install chuccp.win-sshpass# Password login and execute command
win-sshpass -p 'password' ssh user@example.com 'whoami'
# Private key login and execute command
win-sshpass -i ~/.ssh/id_ed25519 ssh user@example.com 'hostname'
# SSH agent authentication (auto-detect, no -p/-i needed)
win-sshpass ssh user@example.com 'whoami'
# JSON output for AI agents and automation
win-sshpass -json -p 'password' ssh user@example.com 'uptime'
# Upload file
win-sshpass -h example.com -p 'password' -local file.txt -remote /tmp/file.txt
# Download file
win-sshpass -h example.com -p 'password' -d -remote /tmp/file.txt -local ./file.txtWhen no command is specified, win-sshpass opens an interactive shell with raw terminal mode:
win-sshpass -p 'password' ssh user@hostRaw terminal mode features:
- Proper echo — typed characters are displayed correctly (no double echo)
- Ctrl+C / Ctrl+Z — signals are forwarded to the remote process
- Full-screen apps — vim, top, htop, nano, etc. work correctly
- Dynamic terminal resizing — the remote terminal automatically matches your local window size
- Tab completion — remote shell tab completion works as expected
While connected, use rz / sz commands to transfer files (no need to install anything on the remote server):
# Upload file to remote current directory (opens file picker)
rz
# Upload specific local file
rz /local/path/to/file
# Download remote file (opens save dialog)
sz /remote/path/to/file
# Download remote file to specific local path
sz /remote/path/to/file /local/save/pathHow it works: When the remote shell reports
rz/sz: command not found, the tool intercepts it and performs the transfer over SFTP instead. Files and directories are both supported, with progress bars.
# Password authentication
win-sshpass -p <password> ssh [user@host] [command]
win-sshpass -p <password> ssh -p <port> user@host 'command'
win-sshpass -p <password> ssh -o StrictHostKeyChecking=no user@host
# Host without user@ — user defaults to root, the name is resolved by the OS
win-sshpass -p <password> ssh example.com 'uptime'
# Empty password — for servers that have no password set (use -p '', don't omit it)
win-sshpass -p '' ssh root@192.168.1.100 'hostname'
# Interactive shell (raw terminal mode: proper echo, Ctrl+C, vim/top support)
win-sshpass -p <password> ssh user@host
# Private key authentication
win-sshpass -i <private_key_path> ssh [user@host] [command]
# SSH agent authentication (auto-detect, no -p/-i needed)
win-sshpass ssh user@host 'whoami'
# SSH agent with forwarding (-A flag)
win-sshpass -A -i ~/.ssh/id_ed25519 ssh user@jumphost
# Password from environment variable
SSHPASS=<password> win-sshpass -e ssh user@host
# Password from file
echo 'password' > pass.txt
win-sshpass -f pass.txt ssh user@host
# Configuration file (multi-line format)
win-sshpass -f server.configStart a long-running process (a service, a daemon) and return immediately instead of waiting for it to exit.
# Start a service after deploying a new binary
win-sshpass -p 'pass' ssh --bg root@host 'cd /app && ./myapp > /tmp/myapp.log 2>&1'
# Replace the binary and start it in the same command
win-sshpass -p 'pass' ssh --bg root@host 'cd /app && cp /tmp/myapp-new ./myapp && chmod +x ./myapp && ./myapp > /tmp/myapp.log 2>&1'
# Restart a service, then verify it in a separate connection
win-sshpass -p 'pass' ssh --bg root@host 'pkill -x myapp; sleep 1; cd /app && ./myapp > /tmp/myapp.log 2>&1'
win-sshpass -p 'pass' ssh root@host 'ps -ef | grep [m]yapp; curl -s localhost:8080/api/status/ping'Why it is needed: ssh host 'nohup ./myapp &' hangs. The background
process inherits the session's stdout/stderr, so the SSH channel never reaches
EOF and the client keeps waiting until the service exits (or -t fires).
--bg starts the command through setsid (falling back to nohup on systems
without it) with all three streams redirected, so the channel closes as soon as
the shell returns while the service keeps running.
Notes:
- Redirect the command's output inside the command (
> /tmp/xxx.log 2>&1);--bgdiscards anything left on the streams. - The exit code only reports that the command was launched, not that the service came up — verify with a second connection as shown above.
- Can also be set per host in a config file with
background: true.
Git Bash users: Use
//prefix for remote paths, e.g.-remote //tmp/file.txt. See Git Bash Notes below.
# Upload file
win-sshpass -h <host> -p <password> -local <local_path> -remote <remote_path>
# Upload multiple files (comma-separated)
win-sshpass -h <host> -p <password> -local "a.txt,b.txt,c.txt" -remote //tmp/
# Upload multiple files (space-separated, only for simple paths without / or \)
win-sshpass -h <host> -p <password> -local "a.txt b.txt c.txt" -remote //tmp/
# Upload directory (auto-recursive)
win-sshpass -h <host> -p <password> -local <local_dir> -remote <remote_dir>
# Download file/directory
win-sshpass -h <host> -p <password> -d -remote <remote_path> -local <local_path># Upload file
win-sshpass -p <password> scp <local_file> user@host:<remote_path>
win-sshpass -p <password> scp -P <port> <local_file> user@host:<remote_path>
# Upload directory
win-sshpass -p <password> scp -r <local_dir> user@host:<remote_path>
# Download file/directory
win-sshpass -p <password> scp user@host:<remote_file> <local_path># Upload
win-sshpass -p <password> rsync -avz <local_path> user@host:<remote_path>
# Download
win-sshpass -p <password> rsync -avz user@host:<remote_path> <local_path>| Parameter | Description | Example |
|---|---|---|
-p |
Password. An explicitly empty value (-p '') is a valid password, for servers with no password set |
-p 'secret123' |
-i |
Private key path | -i ~/.ssh/id_ed25519 |
-f |
Password file / config file | -f pass.txt |
-e |
Read password from SSHPASS env var | SSHPASS='pass' win-sshpass -e ssh ... |
-h |
Host address | -h example.com |
-u |
Username, default: root | -u ubuntu |
-P |
Port, default: 22 | -P 2222 |
-c |
Command to execute | -c 'ls -la' |
-local |
Local path(s) (comma or space separated) | -local "a.txt,b.txt" |
-remote |
Remote path (upload/download) | -remote /tmp/file.txt |
-d |
Download mode | -d |
-k |
Enable strict host key verification | -k |
-t |
Total operation timeout in seconds (0 = no limit) | -t 30 |
-ct |
TCP connection timeout in seconds (default: 10) | -ct 5 |
-retry |
Total connection attempts (default: 3) | -retry 5 |
-resume |
Resume interrupted file transfer from breakpoint | -resume |
-proxy |
Proxy URL (socks5/socks4/http/https) | -proxy socks5://127.0.0.1:1080 |
-L |
Local port forward (repeatable) | -L 8080:db.internal:3306 |
-R |
Remote port forward (repeatable) | -R 9090:localhost:8080 |
-A |
Enable ssh-agent forwarding | -A |
--bg |
Start the command detached from the session and return immediately (for services, e.g. after deploying a binary). Redirect the command's output inside the command itself | --bg './server > /tmp/server.log 2>&1' |
-json |
Output results as JSON (for AI/automation) | -json |
-v |
Show version | -v |
-help |
Show help message | -help |
| Parameter | Description | Default |
|---|---|---|
-algo |
Key algorithm (ed25519 or rsa) |
ed25519 |
-comment |
Comment for generated public key | user@host |
-out |
Output path for private key | ~/.ssh/id_ed25519 or ~/.ssh/id_rsa |
Compute and verify local file hashes without needing an SSH connection:
# Compute hash
win-sshpass hash md5 ./file.iso
win-sshpass hash sha256 ./file.iso
# Verify file against expected hash
win-sshpass verify sha256 d1dc38f6df... ./file.iso
# Output: OK (or: FAILED)Supported algorithms: md5, sha1, sha256, sha512.
Generate SSH key pairs locally without needing ssh-keygen:
# Generate Ed25519 key (recommended — faster and more secure)
win-sshpass keygen
# Generate RSA 4096-bit key
win-sshpass keygen -algo rsa
# Specify output path
win-sshpass keygen -out ~/.ssh/mykey
# Add a comment
win-sshpass keygen -comment "my-laptop"
# Show generated key info
# Private key: ~/.ssh/id_ed25519 (or specified -out path)
# Public key: ~/.ssh/id_ed25519.pubKeys are saved to ~/.ssh/id_ed25519 (Ed25519) or ~/.ssh/id_rsa (RSA) by default. The public key file is automatically given a .pub suffix.
Deploy the public key to enable password-less login:
# Read the public key content into a variable, then deploy via SSH
PUBKEY=$(cat ~/.ssh/id_ed25519.pub)
win-sshpass -p 'password' ssh user@host "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '$PUBKEY' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# Then log in with the private key
win-sshpass -i ~/.ssh/id_ed25519 ssh user@hosthost: example.com
username: root
password: your_password
port: 22
# key: ~/.ssh/id_ed25519 # optional, use private key instead of password
# timeout: 0 # optional, total operation timeout in seconds (0 = no limit)
# connect_timeout: 10 # optional, TCP connection timeout in seconds
# strict_host_key: false # optional, enable strict host key verification
# proxy: socks5://user:pass@127.0.0.1:1080 # optional, proxy URL (socks5/socks4/http/https)Usage:
win-sshpass -f server.config -c 'ls -la'
win-sshpass -f server.config 'ls -la'# 1. Password login and execute command
win-sshpass -p 'mypass' ssh root@192.168.1.100 'docker ps'
# 2. Private key login and execute sudo command
win-sshpass -i ~/.ssh/id_ed25519 ssh ubuntu@server.com 'sudo systemctl restart nginx'
# 3. Upload entire directory to server
win-sshpass -h server.com -p 'mypass' -local ./dist -remote //var/www/html
# 4. Download server log directory
win-sshpass -h server.com -p 'mypass' -d -remote //var/log/nginx -local ./logs
# 5. SCP upload file
win-sshpass -p 'mypass' scp ./app.jar user@server.com:/opt/app/
# 6. Password via environment variable (more secure)
export SSHPASS='mypass'
win-sshpass -e ssh user@server.com 'whoami'
# 7. Operation timeout (abort after 30 seconds)
win-sshpass -p 'mypass' -t 30 ssh user@server.com 'long-running-command'
# 8. Config file with positional command
win-sshpass -f server.config 'docker ps'
# 9. Resume interrupted upload
win-sshpass -p 'mypass' -h server.com -local ./bigfile.iso -remote //data/bigfile.iso -resume
# 10. Compute file hash
win-sshpass hash sha256 ./download.iso
# 11. Verify file integrity
win-sshpass verify sha256 d1dc38f6dfb1e4c8... ./download.iso
# 12. Generate SSH key pair
win-sshpass keygen
# 13. Generate RSA key with custom path and comment
win-sshpass keygen -algo rsa -out ~/.ssh/mykey -comment "my-server"
# 14. Login with generated private key (after deploying public key to server)
win-sshpass -i ~/.ssh/id_ed25519 ssh user@host
# 15. SSH agent authentication (no password/key needed)
win-sshpass ssh user@host 'whoami'
# 16. SSH agent forwarding to jumphost
win-sshpass -A ssh user@jumphost
# 17. JSON output for automation
win-sshpass -json -p 'pass' ssh user@host 'uptime'
# 18. Local port forwarding (access internal DB via jumphost)
win-sshpass -p 'pass' -L 3306:db.internal:3306 ssh user@jumphost
# 19. Remote port forwarding (expose local dev server)
win-sshpass -p 'pass' -R 9090:localhost:8080 ssh user@serverTunnel SSH connections through a proxy server. Supported protocols: SOCKS5, SOCKS4, SOCKS4A, HTTP CONNECT, and HTTPS CONNECT.
# SOCKS5 proxy
win-sshpass -p 'pass' -proxy socks5://127.0.0.1:1080 ssh user@host
# SOCKS5 with authentication
win-sshpass -p 'pass' -proxy socks5://proxyuser:proxypass@127.0.0.1:1080 ssh user@host
# SOCKS4 proxy
win-sshpass -p 'pass' -proxy socks4://192.168.1.1:1080 ssh user@host
# HTTP CONNECT proxy
win-sshpass -p 'pass' -proxy http://proxy.local:8080 ssh user@host
# HTTPS CONNECT proxy with authentication
win-sshpass -p 'pass' -proxy https://user:pass@proxy.local:8443 ssh user@host
# Proxy with file transfer
win-sshpass -p 'pass' -proxy socks5://127.0.0.1:1080 -h host -local ./file.txt -remote /tmp/file.txt
# Proxy with SCP
win-sshpass -p 'pass' -proxy socks5://127.0.0.1:1080 scp ./app.jar user@host:/opt/app/
# Proxy via config file
# proxy: socks5://user:pass@127.0.0.1:1080Tunnel TCP connections through an SSH server using local (-L) or remote (-R) forwarding:
# Local forward: access db.internal:3306 via jumphost at localhost:8080
win-sshpass -p 'pass' -L 8080:db.internal:3306 ssh user@jumphost
# Multiple local forwards
win-sshpass -p 'pass' -L 8080:db1.internal:3306 -L 8081:db2.internal:3306 ssh user@jumphost
# Remote forward: expose localhost:8080 at remote server's port 9090
win-sshpass -p 'pass' -R 9090:localhost:8080 ssh user@server
# Forward-only mode (block until Ctrl+C, no command)
win-sshpass -p 'pass' -L 8080:db.internal:3306 -L 6379:redis.internal:6379 ssh user@jumphostPort forwarding uses the standard OpenSSH format:
[bind_address:]port:host:hostport. Not supported with SCP, Rsync, or file transfer modes.
Use // prefix for remote paths to avoid path conversion:
# Wrong: /tmp will be converted to Windows path
win-sshpass ... -remote /tmp/file.txt
# Correct: use double slashes
win-sshpass ... -remote //tmp/file.txtwin-sshpass is also a reusable Go library (package sshpass). Import it to
embed SSH/SFTP/shell capabilities in your own application:
go get github.com/chuccp/win-sshpasspackage main
import (
"log"
sshpass "github.com/chuccp/win-sshpass"
)
func main() {
cfg := sshpass.NewConfig()
cfg.Host = "example.com"
cfg.User = "root"
cfg.Password = "secret"
// NewClient dials and returns a ready-to-use client.
client, err := sshpass.NewClient(cfg, sshpass.WithSignalHandler())
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Execute a command (output streams to os.Stdout/os.Stderr by default).
if err := client.Exec("uname -a"); err != nil {
log.Fatal(err)
}
// Upload a file over SFTP.
sftp, err := client.SFTP()
if err != nil {
log.Fatal(err)
}
defer sftp.Close()
if err := sftp.Upload("./local.txt", "/tmp/remote.txt"); err != nil {
log.Fatal(err)
}
}Behavior is configured through functional options passed to NewClient:
| Option | Purpose |
|---|---|
WithStdin(r) / WithStdout(w) / WithStderr(w) |
Redirect I/O streams (default os.Stdin/os.Stdout/os.Stderr). |
WithProgress(fn) |
Set a ProgressFunc callback that receives (description string, sent, total int64) during SFTP transfers. The SDK performs no rendering — callers display progress however they like. Defaults to none (headless-friendly). |
WithFileSelector(s) |
Set the FileSelector used by the rz/sz shell-transfer fallback. The SDK ships no default implementation; without one, rz/sz prompts for a path on stdin. |
WithResume() |
Enable breakpoint-resume for SFTP transfers — interrupted uploads/downloads continue from where they left off. |
WithSignalHandler() |
Register a Ctrl+C handler that closes the connection. Off by default so the library never interferes with host signal handling. |
The SDK intentionally bundles no UI code (no progress bar, no file dialog).
Those concerns live in the CLI package (cmd/sshpass/ui.go), which wires a
progressbar-based ProgressFunc and a zenity-based FileSelector into the
client. Library users provide their own.
To tunnel the SSH connection through a proxy, set Config.ProxyURL before
calling NewClient:
cfg := sshpass.NewConfig()
cfg.Host = "example.com"
cfg.User = "root"
cfg.Password = "secret"
cfg.ProxyURL = "socks5://user:pass@127.0.0.1:1080" // or http://, https://, socks4://
client, err := sshpass.NewClient(cfg)Lower-level helpers are also exported for advanced use: Dial, NewConfig,
LoadConfig, LoadConfigOrPasswordFile, ParseSSHArgs, ParseSCPArgs,
ParseRsyncArgs, DetectCommandType, RunSCP, RunRsync, CleanRemotePath,
SplitPaths, ParseUserHostPath, ExitCodeFromError.
# Windows
go build -o win-sshpass.exe ./cmd/sshpass
# Linux / macOS
go build -o win-sshpass ./cmd/sshpass
# Cross-compile
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o win-sshpass ./cmd/sshpass
GOOS=windows GOARCH=amd64 go build -o win-sshpass.exe ./cmd/sshpass
GOOS=darwin GOARCH=arm64 go build -o win-sshpass ./cmd/sshpass- Go 1.23+
- golang.org/x/crypto/ssh
- github.com/pkg/sftp
- github.com/schollz/progressbar/v3 (CLI progress bar only)
- github.com/ncruces/zenity (CLI file dialogs only)