SSH Cheat Sheet
ssh user@host # connect
ssh -p 2222 user@host # non-standard port
ssh-keygen -t ed25519 -C "you@laptop" # create a key pair
ssh-copy-id user@host # install your public key on the server
scp file.txt user@host:/tmp/ # copy a file to the server
ssh -L 8080:localhost:80 user@host # local port forward (tunnel)
This page covers the OpenSSH client and server shipped by every major distro. For a step-by-step setup of key login and disabling passwords, read how to set up SSH keys. If a connection fails, jump to troubleshooting.
Connecting
| Command | What it does |
|---|---|
ssh host | Connect as your local user name |
ssh user@host | Connect as user |
ssh -p 2222 user@host | Custom port |
ssh -i ~/.ssh/work_ed25519 user@host | Use a specific private key |
ssh user@host 'df -h' | Run one command remotely and exit |
ssh -t user@host 'sudo systemctl restart nginx' | Force a terminal (needed for sudo prompts, top, vim) |
ssh -J bastion user@internal | Connect through a jump host |
ssh -X user@host | X11 forwarding (-Y for trusted; only for X11 apps) |
ssh -C user@host | Compress traffic (helps on slow links) |
ssh -4 user@host / -6 | Force IPv4 or IPv6 |
ssh -v user@host | Verbose debug output (-vvv for more) |
ssh -o ConnectTimeout=5 user@host | Set any config option on the command line |
Keys and the agent
| Command | What it does |
|---|---|
ssh-keygen -t ed25519 -C "comment" | New Ed25519 key pair (recommended) |
ssh-keygen -t rsa -b 4096 | RSA key for old systems without Ed25519 |
ssh-keygen -t ed25519-sk | Key bound to a FIDO2 hardware token |
ssh-keygen -p -f ~/.ssh/id_ed25519 | Change or add a passphrase |
ssh-keygen -y -f ~/.ssh/id_ed25519 | Print the public key from a private key |
ssh-keygen -lf ~/.ssh/id_ed25519.pub | Show a key's fingerprint |
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host | Append a public key to the server's authorized_keys |
eval "$(ssh-agent -s)" | Start an agent in the current shell |
ssh-add | Add default keys to the agent |
ssh-add -t 1h ~/.ssh/id_ed25519 | Add a key that expires after an hour |
ssh-add -l / ssh-add -D | List loaded keys / remove all |
ssh -A user@host | Forward your agent (only to hosts you trust) |
Copying files
| Command | What it does |
|---|---|
scp file user@host:/path/ | Copy a local file to the server |
scp user@host:/path/file . | Copy from the server to the current directory |
scp -r dir/ user@host:/path/ | Copy a directory recursively |
scp -P 2222 file user@host: | Custom port (capital P), into the home directory |
scp -3 host1:/f host2:/f | Copy between two remote hosts through your machine |
sftp user@host | Interactive file transfer (put, get, ls, cd) |
rsync -avz dir/ user@host:/path/dir/ | Sync a directory (only changed files are sent) |
rsync -avz -e 'ssh -p 2222' dir/ user@host:/path/ | rsync over a custom SSH port |
rsync -avP big.iso user@host: | Show progress and resume partial transfers |
sshfs user@host:/srv ~/mnt | Mount a remote directory (package sshfs; unmount with fusermount3 -u ~/mnt) |
Port forwarding and tunnels
| Command | What it does |
|---|---|
ssh -L 8080:localhost:80 user@host | Local forward: localhost:8080 on your machine reaches port 80 on the server |
ssh -L 5433:db.internal:5432 user@bastion | Reach a database the server can see but you can't |
ssh -R 9000:localhost:3000 user@host | Remote forward: port 9000 on the server reaches port 3000 on your machine |
ssh -D 1080 user@host | Dynamic SOCKS5 proxy on localhost:1080 |
ssh -N -L 8080:localhost:80 user@host | Tunnel only, no remote shell |
ssh -fN -L 8080:localhost:80 user@host | Same, in the background |
ssh -L 0.0.0.0:8080:localhost:80 user@host | Let other machines on your LAN use the tunnel |
Client config: ~/.ssh/config
Settings here apply automatically, so ssh web1 replaces a long command line. The first value found for each option wins, so put specific Host blocks before Host *.
Host web1
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/work_ed25519
IdentitiesOnly yes
Host internal-*
ProxyJump bastion
Host *
AddKeysToAgent yes
ServerAliveInterval 60
ServerAliveCountMax 3
| Command | What it does |
|---|---|
ssh -G web1 | Print the final config that would be used for a host |
ControlMaster auto + ControlPath ~/.ssh/cm-%r@%h:%p + ControlPersist 10m | Reuse one connection for later sessions (much faster repeat logins) |
ssh -O exit web1 | Close a shared master connection |
LocalForward 8080 localhost:80 | Config-file version of -L |
Include ~/.ssh/config.d/* | Split config into several files (put it at the top) |
Server side (sshd)
Put changes in a drop-in such as /etc/ssh/sshd_config.d/50-local.conf instead of editing the main file. Always keep a working session open while you test.
| Command | What it does |
|---|---|
sudo sshd -t | Check the configuration for errors before restarting |
sudo sshd -T | grep -i passwordauth | Show the effective value of a setting |
sudo systemctl restart ssh | Restart on Debian/Ubuntu (unit name ssh) |
sudo systemctl restart sshd | Restart on Fedora, Arch, openSUSE (unit name sshd) |
PasswordAuthentication no | Keys only (set up keys first) |
PermitRootLogin no | Block direct root login (prohibit-password allows keys only) |
AllowUsers alice bob | Only these users may log in |
sudo ss -tlnp | grep ssh | Confirm sshd is listening and on which port |
journalctl -u ssh -f | Follow sshd logs (-u sshd on Fedora/Arch) |
On Ubuntu 22.10 and later, sshd is started by ssh.socket. If you change Port, run sudo systemctl daemon-reload and sudo systemctl restart ssh.socket so the socket listens on the new port. On Fedora with SELinux, a new port also needs sudo semanage port -a -t ssh_port_t -p tcp 2222. More on unit names in the systemctl cheat sheet.
Troubleshooting connections
| Command | What it does |
|---|---|
ssh -vvv user@host | See exactly where authentication fails |
ssh-keygen -R host | Remove an old host key after a legitimate reinstall (see REMOTE HOST IDENTIFICATION HAS CHANGED) |
chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys | Fix permissions that make sshd ignore your key (Permission denied (publickey)) |
nc -zv host 22 | Check whether the port is reachable (Connection refused) |
ssh -o PubkeyAuthentication=no user@host | Test password login on its own |
Enter, then ~. | Kill a hung session; ~? lists all escape sequences |
Common recipes
Run a long job that survives disconnects (see the tmux cheat sheet):
ssh -t user@host 'tmux new -A -s main'
Open a remote web admin panel that only listens on the server's localhost:
ssh -N -L 9090:localhost:9090 admin@server
# then browse to http://localhost:9090
Run the same command on several servers:
for h in web1 web2 db1; do
echo "== $h"; ssh "$h" 'uptime'
done
Copy your public key manually when ssh-copy-id is not available:
cat ~/.ssh/id_ed25519.pub | ssh user@host 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
Back up a remote database straight to your machine:
ssh db1 'sudo -u postgres pg_dump mydb | gzip' > mydb-$(date +%F).sql.gz
Compare a remote file with a local one:
diff <(ssh web1 cat /etc/nginx/nginx.conf) /etc/nginx/nginx.conf
Gotchas
-pvs-P. ssh uses lowercase-pfor the port; scp and sftp use uppercase-P(lowercase-pmeans "preserve times").- Service name differs. The unit is
sshon Debian/Ubuntu/Mint andsshdon Fedora/Arch/openSUSE. The package to install isopenssh-server(apt, dnf, zypper) oropenssh(pacman). - Permissions are strict. sshd ignores authorized_keys if your home, ~/.ssh or the file is writable by others. Private keys must be 600 or the client refuses them.
- Too many keys. With many keys in the agent, the server may disconnect with "Too many authentication failures" before the right key is tried. Use
IdentitiesOnly yeswithIdentityFile. - scp uses SFTP now. Current OpenSSH scp transfers over the SFTP protocol. Remote paths with spaces need only normal quoting;
scp -Oforces the legacy protocol for very old servers. - Agent forwarding is a risk. Anyone with root on the remote host can use your forwarded agent. Prefer
ProxyJump(-J) for hopping through bastions. - Lockout risk. Test with
sshd -tand a second session before closing the first one after any change to sshd or the firewall.
Reference: ssh(1) and ssh_config(5) in the OpenBSD manual pages (OpenSSH upstream).
Frequently asked questions
How do I SSH on a different port?
Use ssh -p 2222 user@host. For scp the flag is a capital -P: scp -P 2222 file user@host:.
How do I copy files over SSH?
scp file user@host:/path/ for quick copies, or rsync -avz dir/ user@host:/path/ for directories and resumable transfers.
What is the difference between -L and -R port forwarding?
-L opens a port on your machine that forwards to something reachable from the server. -R opens a port on the server that forwards back to something reachable from your machine.
How do I stop SSH asking for my key passphrase every time?
Load the key into an agent with ssh-add, or set AddKeysToAgent yes in ~/.ssh/config. GNOME and KDE start an agent automatically.
How do I get out of a frozen SSH session?
Press Enter, then type ~. (tilde, period). This escape sequence closes the connection from the client side.
Spotted a mistake or a command that no longer works? Send a correction — pages are re-checked when reports come in.