| name | ssh-remote |
| category | system |
| description | Manage SSH connections, key management, remote command execution, tunneling, and file transfer with scp and rsync. Use when the user asks to connect to a remote server, generate SSH keys, set up port forwarding or tunnels, transfer files remotely, configure jump hosts, manage known_hosts, or set up SSH config for multiple hosts.
|
| license | MIT |
| compatibility | Requires openssh-client (pre-installed on macOS and most Linux distributions) |
| metadata | {"author":"zeph","version":"1.0"} |
SSH, SCP, and Rsync
Quick Reference
| Task | Command |
|---|
| Connect | ssh user@host |
| Connect on port | ssh -p 2222 user@host |
| Run remote command | ssh user@host 'command' |
| Generate key | ssh-keygen -t ed25519 |
| Copy key to server | ssh-copy-id user@host |
| Copy file to remote | scp file.txt user@host:/path/ |
| Copy file from remote | scp user@host:/path/file.txt . |
| Sync directory | rsync -avz dir/ user@host:/path/ |
| Local tunnel | ssh -L 8080:localhost:80 user@host |
SSH Key Management
Generate Keys
ssh-keygen -t ed25519 -C "user@hostname"
ssh-keygen -t ed25519 -f ~/.ssh/id_project -C "user@hostname"
ssh-keygen -t rsa -b 4096 -C "user@hostname"
ssh-keygen -t ed25519 -f ~/.ssh/id_automation -N ""
ssh-keygen -p -f ~/.ssh/id_ed25519
ssh-keygen -lf ~/.ssh/id_ed25519.pub
ssh-keygen -lf ~/.ssh/id_ed25519.pub -E md5
Deploy Public Key
ssh-copy-id user@host
ssh-copy-id -i ~/.ssh/id_project.pub user@host
ssh-copy-id -p 2222 user@host
cat ~/.ssh/id_ed25519.pub | ssh user@host 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
SSH Agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -t 3600 ~/.ssh/id_ed25519
ssh-add -l
ssh-add -d ~/.ssh/id_ed25519
ssh-add -D
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
SSH Connection
Basic Connection
ssh user@host
ssh -p 2222 user@host
ssh -i ~/.ssh/id_project user@host
ssh -v user@host
ssh -vv user@host
ssh -vvv user@host
ssh -o PreferredAuthentications=password user@host
ssh -o PreferredAuthentications=publickey user@host
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@host
ssh -X user@host
ssh -t user@host 'sudo systemctl restart nginx'
Remote Command Execution
ssh user@host 'uptime'
ssh user@host 'df -h /home'
ssh user@host 'cd /app && git pull && systemctl restart app'
ssh -t user@host 'sudo systemctl status nginx'
ssh user@host 'LANG=C df -h'
cat data.csv | ssh user@host 'cat > /tmp/data.csv'
ssh user@host 'bash -s' < local_script.sh
ssh user@host 'bash -s' < local_script.sh -- arg1 arg2
result=$(ssh user@host 'cat /etc/hostname')
SSH Config (~/.ssh/config)
# Default settings for all hosts
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
IdentitiesOnly yes
# Named host with short alias
Host myserver
HostName 192.168.1.100
User admin
Port 2222
IdentityFile ~/.ssh/id_project
# Jump host (bastion) setup
Host bastion
HostName bastion.example.com
User jumpuser
IdentityFile ~/.ssh/id_bastion
Host internal-*
ProxyJump bastion
User admin
IdentityFile ~/.ssh/id_internal
Host internal-web
HostName 10.0.1.10
Host internal-db
HostName 10.0.1.20
# Wildcard host pattern
Host *.staging.example.com
User deploy
IdentityFile ~/.ssh/id_staging
# Tunnel configuration (persistent)
Host tunnel-db
HostName db-server.example.com
User admin
LocalForward 5432 localhost:5432
IdentityFile ~/.ssh/id_db
# Multiple jump hosts
Host deep-internal
HostName 10.0.2.50
ProxyJump bastion1,bastion2
User admin
Usage after config:
ssh myserver
ssh internal-web
ssh -N tunnel-db
SSH Tunneling (Port Forwarding)
Local Port Forwarding (-L)
Access a remote service through a local port.
ssh -L 8080:localhost:80 user@host
ssh -L 5432:localhost:5432 user@db-server
ssh -L 3306:db-host:3306 user@bastion
ssh -fNL 8080:localhost:80 user@host
ssh -L 0.0.0.0:8080:localhost:80 user@host
ssh -L 8080:localhost:80 -L 8443:localhost:443 user@host
Remote Port Forwarding (-R)
Make a local service accessible from the remote side.
ssh -R 9000:localhost:3000 user@host
ssh -fNR 9000:localhost:3000 user@host
ssh -R 0.0.0.0:9000:localhost:3000 user@host
Dynamic Port Forwarding (-D) — SOCKS Proxy
ssh -D 1080 user@host
ssh -fND 1080 user@host
curl --socks5 localhost:1080 https://example.com
export ALL_PROXY=socks5://localhost:1080
Jump Hosts (ProxyJump)
ssh -J bastion user@internal-server
ssh -J bastion1,bastion2 user@internal-server
ssh -J jumpuser@bastion:2222 admin@internal
scp -J bastion file.txt user@internal:/path/
rsync -avz -e "ssh -J bastion" dir/ user@internal:/path/
File Transfer — SCP
scp file.txt user@host:/remote/path/
scp user@host:/remote/file.txt /local/path/
scp -r dir/ user@host:/remote/path/
scp -P 2222 file.txt user@host:/path/
scp -i ~/.ssh/id_project file.txt user@host:/path/
scp -p file.txt user@host:/path/
scp -l 1000 large-file.tar.gz user@host:/path/
scp user1@host1:/path/file.txt user2@host2:/path/
scp file1.txt file2.txt user@host:/path/
scp -J bastion file.txt user@internal:/path/
File Transfer — Rsync
Rsync transfers only changed parts of files, making subsequent syncs much faster.
rsync -avz dir/ user@host:/remote/dir/
rsync -avz user@host:/remote/dir/ local-dir/
rsync -avzn dir/ user@host:/remote/dir/
rsync -avz --delete dir/ user@host:/remote/dir/
rsync -avz --exclude='*.log' --exclude='node_modules' dir/ user@host:/path/
rsync -avz --exclude-from='rsync-exclude.txt' dir/ user@host:/path/
rsync -avz -e "ssh -p 2222" dir/ user@host:/path/
rsync -avz -e "ssh -i ~/.ssh/id_project" dir/ user@host:/path/
rsync -avz --bwlimit=1000 dir/ user@host:/path/
rsync -avz --progress dir/ user@host:/path/
rsync -avz --info=progress2 dir/ user@host:/path/
rsync -avz dir/ user@host:/path/
rsync -avzH dir/ user@host:/path/
rsync -avz --partial --append dir/ user@host:/path/
rsync -avzc dir/ user@host:/path/
Rsync Flags
| Flag | Meaning |
|---|
-a | Archive mode (recursive, preserves permissions, symlinks, timestamps, group, owner) |
-v | Verbose |
-z | Compress during transfer |
-n | Dry run |
-P | Show progress + keep partial files |
-H | Preserve hard links |
-e | Specify remote shell |
--delete | Delete extraneous files on receiver |
--exclude | Exclude pattern |
--bwlimit | Bandwidth limit in KB/s |
Known Hosts Management
cat ~/.ssh/known_hosts
ssh-keygen -R hostname
ssh-keygen -R "[hostname]:port"
ssh-keygen -R 192.168.1.100
ssh-keygen -H -f ~/.ssh/known_hosts
ssh-keyscan -t ed25519 hostname >> ~/.ssh/known_hosts
ssh-keyscan -p 2222 hostname >> ~/.ssh/known_hosts
Permissions Reference
SSH is strict about file permissions. Incorrect permissions cause silent authentication failures.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/config
chmod 644 ~/.ssh/known_hosts
Important Notes
- Always prefer Ed25519 keys over RSA for new setups (shorter, faster, more secure)
- Use
ssh-copy-id instead of manually editing authorized_keys
- Set
IdentitiesOnly yes in SSH config to avoid sending all keys to every server
- Use
ServerAliveInterval to prevent idle connections from being dropped by firewalls
- For tunnels, use
-fN flags to run in background without a shell
- The trailing
/ in rsync source path matters: dir/ syncs contents, dir syncs the directory itself
- Use
rsync --dry-run before --delete to verify what will be removed
- Never disable
StrictHostKeyChecking on production or public networks
- Use
ProxyJump (SSH 7.3+) instead of the older ProxyCommand for jump hosts
- SSH agent forwarding (
-A) is convenient but carries security risks; prefer ProxyJump
- Keep
~/.ssh/config permissions at 600; SSH may silently ignore it otherwise