| name | ssh-config |
| description | SSH key management, config file setup, tunnels, port forwarding, and jump hosts. Use when user asks to "setup SSH keys", "configure SSH", "create SSH tunnel", "add SSH host", "jump host", "port forwarding", "bastion host", "SSH agent", "ssh-copy-id", "SSH proxy", "SSH hardening", "SSH multiplexing", "SSH certificates", "multiple GitHub keys", "ProxyJump", "SSH debug", "SSH escape", "SSH SOCKS proxy", "rsync over SSH", or manage SSH connections. |
SSH Config
SSH key management, configuration, tunneling, and security hardening.
Key Generation
ssh-keygen -t ed25519 -C "your@email.com"
ssh-keygen -t ed25519 -f ~/.ssh/github_key -C "github"
ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -C "deploy" -N ""
ssh-keygen -t rsa -b 4096 -C "your@email.com"
ssh-keygen -p -f ~/.ssh/id_ed25519
ssh-keygen -lf ~/.ssh/id_ed25519.pub
ssh-keygen -c -f ~/.ssh/id_ed25519 -C "alice@work-laptop-2024"
Copying Public Keys
ssh-copy-id user@host
ssh-copy-id -i ~/.ssh/mykey.pub user@host
ssh-copy-id -p 2222 user@host
cat ~/.ssh/id_ed25519.pub | ssh user@host 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
pbcopy < ~/.ssh/id_ed25519.pub
SSH Agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -t 43200 ~/.ssh/id_ed25519
ssh-add -l
ssh-add -d ~/.ssh/id_ed25519
ssh-add -D
macOS Keychain Integration
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Agent Forwarding
ssh -A user@server
Host myserver
ForwardAgent yes
Only forward agent to trusted hosts. A compromised host can use your agent to authenticate as you.
SSH Config File (~/.ssh/config)
Basic Host Entries
Host myserver
HostName 192.168.1.100
User admin
Port 22
IdentityFile ~/.ssh/id_ed25519
Host prod
HostName prod.example.com
User deploy
IdentityFile ~/.ssh/deploy_key
IdentitiesOnly yes
IdentitiesOnly yes prevents SSH from trying every key in the agent.
Wildcards and Defaults
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
Host *.example.com
User deploy
IdentityFile ~/.ssh/deploy_key
Host 192.168.1.*
User admin
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Multiple GitHub/GitLab Accounts
Host github.com-personal
HostName github.com
User git
IdentityFile ~/.ssh/github_personal
IdentitiesOnly yes
Host github.com-work
HostName github.com
User git
IdentityFile ~/.ssh/github_work
IdentitiesOnly yes
git clone git@github.com-personal:myuser/repo.git
git clone git@github.com-work:company/repo.git
git remote set-url origin git@github.com-work:company/repo.git
Jump Hosts / Bastion Hosts
ProxyJump (OpenSSH 7.3+)
Host bastion
HostName bastion.example.com
User jump
Host internal
HostName 10.0.0.5
User admin
ProxyJump bastion
# Chain: bastion -> middleware -> deep-internal
Host middleware
HostName 10.0.0.10
User app
ProxyJump bastion
Host deep-internal
HostName 172.16.0.5
User admin
ProxyJump middleware
ssh -J jump@bastion.example.com admin@10.0.0.5
ssh -J jump@bastion1,jump@bastion2 admin@10.0.0.5
ProxyCommand (Legacy)
Host internal-legacy
HostName 10.0.0.5
User admin
ProxyCommand ssh -W %h:%p bastion
Port Forwarding
Local Forward (-L)
ssh -L 8080:localhost:80 user@server
ssh -L 5432:localhost:5432 user@server
ssh -L 8080:internal-db.example.com:5432 user@bastion
ssh -L 0.0.0.0:8080:localhost:80 user@server
Remote Forward (-R)
ssh -R 8080:localhost:3000 user@server
Dynamic Forward / SOCKS Proxy (-D)
ssh -D 1080 user@server
ssh -D 1080 -f -N user@server
Port Forwarding in Config
Host tunnel-db
HostName server.example.com
User admin
LocalForward 5432 localhost:5432
LocalForward 6379 localhost:6379
Host tunnel-web
HostName server.example.com
User admin
LocalForward 8080 localhost:80
DynamicForward 1080
SSH Tunnels
ssh -f -N -L 8080:localhost:80 user@server
pkill -f "ssh -f -N -L 8080"
autossh -M 0 -f -N -L 8080:localhost:80 user@server
ssh -f -N -L 5432:db.internal:5432 user@bastion && psql -h localhost -p 5432 -U dbuser mydb
ssh -f -N -L 6379:redis.internal:6379 user@bastion && redis-cli -h localhost
SCP and rsync Over SSH
scp file.txt user@host:/path/
scp user@host:/path/file.txt ./
scp -r folder/ user@host:/path/
rsync -avz folder/ user@host:/path/
rsync -avz --progress folder/ user@host:/path/
rsync -avz --delete folder/ user@host:/path/
rsync -avzn folder/ user@host:/path/
rsync -avz -e "ssh -J jump@bastion" folder/ admin@internal:/path/
Multiplexing (Connection Reuse)
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
mkdir -p ~/.ssh/sockets
ssh -O check myserver
ssh -O exit myserver
ControlPersist 600 keeps the socket alive 600s after the last session closes.
SSH Escape Sequences
Press Enter then ~ during an SSH session:
~. Disconnect (kill hung session) ~? List all escapes
~C Open command line (add -L/-R/-D mid-session)
~# List forwarded connections ~~ Send literal ~
Debugging Connection Issues
ssh -v user@host
ssh -vvv user@host
ssh -T git@github.com
ssh -G myserver | grep -i hostname
ssh-keygen -R hostname
ssh-keygen -R "[hostname]:port"
Common errors:
- "Permission denied (publickey)" -- wrong key, key not in agent, or not in authorized_keys
- "Host key verification failed" -- host key changed (server reinstall or MITM)
- "Connection refused" -- sshd not running or wrong port
- "Connection timed out" -- firewall, wrong IP, or host down
SSH Security Hardening
File Permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/config ~/.ssh/authorized_keys
chmod 644 ~/.ssh/id_ed25519.pub
Server Configuration (/etc/ssh/sshd_config)
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
Port 2222
AllowUsers deploy admin
PermitEmptyPasswords no
MaxAuthTries 3
X11Forwarding no
AllowAgentForwarding no
sudo sshd -t
sudo systemctl restart sshd
fail2ban (Brute-Force Protection)
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
SSH Certificates vs Keys
ssh-keygen -t ed25519 -f ca_key -C "SSH CA"
ssh-keygen -s ca_key -I "alice-cert" -n alice -V +52w id_ed25519.pub
ssh-keygen -s ca_key -I "web-server" -h -n web.example.com host_key.pub
ssh-keygen -Lf id_ed25519-cert.pub
Server trusts CA: add TrustedUserCAKeys /etc/ssh/ca_key.pub to sshd_config.
Client trusts host CA: add @cert-authority *.example.com <ca_key.pub contents> to known_hosts.
Certificates eliminate distributing authorized_keys to every server -- sign once, access everywhere the CA is trusted.