Show HN: Ts-SSH – SSH over Tailscale without running the daemon
ts-ssh: Powerful Tailscale SSH/SCP CLI Tool
A streamlined command-line SSH client and SCP utility that connects to your Tailscale network using tsnet
. Features powerful multi-host operations, batch command execution, and real tmux integration - all without requiring the full Tailscale daemon.
Perfect for DevOps teams who need fast, reliable SSH access across their Tailscale infrastructure.
Features
🚀 Core SSH/SCP Functionality
- Userspace Tailscale connection using
tsnet
- no daemon required - Multiple authentication methods: SSH keys, password prompts, or both
- Interactive SSH sessions with full PTY support and terminal resizing
- Secure host key verification using
~/.ssh/known_hosts
- Direct SCP transfers with automatic upload/download detection
💪 Multi-Host Power Operations
--list
: Fast host discovery with online/offline status--multi host1,host2,host3
: Real tmux sessions with multiple SSH connections--exec "command" host1,host2
: Batch command execution across hosts--parallel
: Concurrent command execution for faster operations--copy file host1,host2:/path/
: Multi-host file distribution--pick
: Simple interactive host selection
🛠️ Professional DevOps Features
- ProxyCommand support (
-W
) for integration with standard tools - Cross-platform: Linux, macOS (Intel/ARM), Windows
- Multi-language support: English and Spanish localization
- Fast startup - no UI frameworks or complex initialization
- Composable commands - works perfectly in scripts and automation
- Clear error handling and helpful feedback
Prerequisites
- Go: Version 1.18 or later installed (
go version
). - Tailscale Account: An active Tailscale account.
- Target Node: A machine within your Tailscale network running an SSH server that allows connections from your user/key/password.
Installation
You can install ts-ssh
using go install
(recommended) or build it manually from the source.
Using go install
:
go install github.com/derekg/ts-ssh@latest
(Make sure your $GOPATH/bin
or $HOME/go/bin
is in your system's PATH
)
Manual Build:
- Clone the repository:
git clone https://github.com/derekg/ts-ssh.git cd ts-ssh
- Build the executable:
go build -o ts-ssh .
You can now run./ts-ssh
.
Cross-Compilation:
You can easily cross-compile for other platforms. Set the GOOS
and GOARCH
environment variables. Use CGO_ENABLED=0
for easier cross-compilation.
- For macOS (Apple Silicon):
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o ts-ssh-darwin-arm64 .
- For macOS (Intel):
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o ts-ssh-darwin-amd64 .
- For Linux (amd64):
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ts-ssh-linux-amd64 .
- For Windows (amd64):
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ts-ssh-windows-amd64.exe .
Usage
Usage: ts-ssh [options] [user@]hostname[:port] [command...]
ts-ssh --list # List available hosts
ts-ssh --multi host1,host2,host3 # Multi-host tmux session
ts-ssh --exec "command" host1,host2 # Run command on multiple hosts
ts-ssh --copy file.txt host1,host2:/tmp/ # Copy file to multiple hosts
ts-ssh --pick # Interactive host picker
Powerful SSH/SCP tool for Tailscale networks.
Options:
-W string
forward stdio to destination host:port (for use as ProxyCommand)
-control-url string
Tailscale control plane URL (optional)
-copy string
Copy files to multiple hosts (format: localfile host1,host2:/path/)
-exec string
Execute command on specified hosts
-i string
Path to SSH private key (default "/home/user/.ssh/id_rsa")
-insecure
Disable host key checking (INSECURE!)
-l string
SSH Username (default "user")
-lang string
Language for CLI output (en, es)
-list
List available Tailscale hosts
-multi string
Start tmux session with multiple hosts (comma-separated)
-parallel
Execute commands in parallel (use with --exec)
-pick
Interactive host picker (simple selection)
-tsnet-dir string
Directory to store tsnet state (default "/home/user/.config/ts-ssh-client")
-v Verbose logging
-version
Print version and exit
Arguments:
- For SSH:
[user@]hostname[:port] [command...]
hostname
must be the Tailscale MagicDNS name or Tailscale IP address of the target machine.user
defaults to your current OS username if not provided or specified with-l
.port
defaults to22
if not provided.command...
(optional): If provided, executes the command on the remote host instead of starting an interactive shell.
- For SCP (direct CLI):
- Upload:
local_path [user@]hostname:remote_path
- Download:
[user@]hostname:remote_path local_path
- The
user@
in the remote argument is optional; if not provided, the user from-l
or the default OS user will be used.
- Upload:
Examples
🔍 Host Discovery
# List all Tailscale hosts with status ts-ssh --list # Detailed host information ts-ssh --list -v # Interactive host picker ts-ssh --pick
🖥️ Basic SSH Operations
# Connect to a single host ts-ssh your-server # Connect as specific user ts-ssh admin@your-server ts-ssh -l admin your-server # Run a remote command ts-ssh your-server uname -a # Use specific SSH key ts-ssh -i ~/.ssh/my_key user@your-server
🚀 Multi-Host Power Operations
# Create tmux session with multiple hosts ts-ssh --multi web1,web2,db1 # Run command on multiple hosts (sequential) ts-ssh --exec "uptime" web1,web2,web3 # Run command on multiple hosts (parallel) ts-ssh --parallel --exec "systemctl status nginx" web1,web2 # Check disk space across all web servers ts-ssh --exec "df -h" web1.domain,web2.domain,web3.domain
📁 File Transfer Operations
# Single host SCP ts-ssh local.txt your-server:/remote/path/ ts-ssh your-server:/remote/file.txt ./ # Multi-host file distribution ts-ssh --copy deploy.sh web1,web2,web3:/tmp/ ts-ssh --copy config.json db1,db2:/etc/myapp/ # Copy with specific user ts-ssh --copy -l admin backup.tar.gz server1,server2:/backups/
🔧 Advanced Usage
# ProxyCommand integration scp -o ProxyCommand="ts-ssh -W %h:%p" file.txt server:/path/ # Version information ts-ssh -version # Verbose logging for debugging ts-ssh --list -v
🌍 Language Support
# Use Spanish interface ts-ssh --lang es --list LANG=es ts-ssh --help # Use English (default) ts-ssh --lang en --help LC_ALL=en ts-ssh --help # Set permanent language preference export TS_SSH_LANG=es ts-ssh --help # Now shows Spanish
Language Detection Priority:
- CLI flag (
--lang
) TS_SSH_LANG
environment variableLC_ALL
environment variableLANG
environment variable- Default (English)
Supported Languages:
- 🇺🇸 English (
en
) - Default - 🇪🇸 Spanish (
es
) - Complete translation
💡 Real-World DevOps Scenarios
# Deploy configuration to all web servers ts-ssh --copy nginx.conf web1,web2,web3:/etc/nginx/ ts-ssh --parallel --exec "sudo nginx -t && sudo systemctl reload nginx" web1,web2,web3 # Check service status across infrastructure ts-ssh --parallel --exec "systemctl is-active docker" node1,node2,node3 # Collect logs from multiple servers ts-ssh --exec "tail -100 /var/log/app.log" app1,app2,app3 # Emergency system info gathering ts-ssh --parallel --exec "uptime && free -h && df -h" web1,web2,db1,db2
Multi-Host tmux Sessions
The --multi
flag creates real tmux sessions with SSH connections to multiple hosts. This provides a professional terminal multiplexing experience:
# Create tmux session with 3 hosts
ts-ssh --multi web1,web2,db1
tmux Controls
Once connected, use standard tmux key bindings:
Ctrl+B n
- Next window (next host)Ctrl+B p
- Previous window (previous host)Ctrl+B 1-9
- Switch to window numberCtrl+B c
- Create new windowCtrl+B d
- Detach from sessionCtrl+B ?
- Show all key bindings
Session Management
# List active tmux sessions tmux list-sessions # Reconnect to a detached session tmux attach-session -t ts-ssh-1234567890 # Kill a specific session tmux kill-session -t ts-ssh-1234567890
Note:
The Tailscale authentication flow may show verbose logs during startup. Use -v
for clearer diagnostic output if needed.
Tailscale Authentication
The first time you run ts-ssh
on a machine, or if its Tailscale authentication expires, it will need to authenticate to your Tailscale network.
The program will print a URL to the console. Copy this URL and open it in a web browser. Log in to your Tailscale account to authorize this client ("ts-ssh-client" or the hostname set in code).
Once authorized, ts-ssh
stores authentication keys in the state directory (~/.config/ts-ssh-client
by default, configurable with -tsnet-dir
) so you don't need to re-authenticate every time.
Security Notes
- Host Key Verification: This tool performs host key verification against
~/.ssh/known_hosts
by default. This is a crucial security feature to prevent Man-in-the-Middle (MITM) attacks. -insecure
Flag: The-insecure
flag disables host key checking entirely. This is dangerous and should only be used in trusted environments or for specific testing purposes where you fully understand the security implications. You are vulnerable to MITM attacks if you use this flag carelessly.
License
This project is licensed under the MIT License - see the LICENSE file for details.
What's Your Reaction?






