ssh

OpenSSH 9.0+

Quick reference for OpenSSH: connections, key management, the user config file, file transfer (scp/rsync/sshfs), port forwarding and jump hosts — with common options and practical examples.

26 commands

Connection

ssh <user>@<host>

Open an interactive SSH session on a remote host.

-p PORT; -i identity_file; -l user (overrides user@); -E logfile debug; -v / -vv / -vvv verbose levels

ssh -p 2222 [email protected]
ssh <user>@<host> '<cmd>'

Run a single non-interactive command on the remote host.

ssh ops@db1 'sudo systemctl status postgresql'
ssh -J <jumphost>

Route the SSH connection through a jump host (ProxyJump).

-J user1@jump1:2222,user2@jump2; -o ProxyCommand=ssh -W ...

ssh -J [email protected] db1.private -i ~/.ssh/db1_key
ssh -N -L <l:r> -f <host>

Background local port forwarding without opening a shell; -L local:rremote.

-N no remote cmd; -f background; -L 8080:localhost:80; -g allow remote to connect to local side

ssh -N -L 5432:localhost:5432 -f db1 && psql -h localhost
ssh -N -R <r:localhost:l>

Reverse tunnel — open a port on the remote side that forwards back to a local port.

-N; -f; -R 8080:localhost:3000; GatewayPorts yes (server config)

ssh -N -R 8080:localhost:3000 [email protected]
ssh -D <lport>

Set up a SOCKS proxy on the local side via the SSH server.

-C compress; -q quiet; -D 1080

ssh -D 1080 -q -N tunnel.example.com && curl --proxy socks5h://localhost:1080 https://ifconfig.me
ssh -A <user>@<host>

Forward your local ssh-agent to the remote host (chain SSH through it).

-A agent forward; -a disable

ssh -A ops@bastion && ssh internal-db # uses your local keys
ssh -o <key>=<value>

Pass per-invocation SSH options (useful for one-off changes that don't deserve a config entry).

StrictHostKeyChecking=no; UserKnownHostsFile=/dev/null (insecure, demo only); RequestTTY=force

ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null [email protected]
ssh -F <configfile>

Use an alternative ssh_config file (handy for per-project / per-customer settings).

-F path; -G parse and print config without connecting

ssh -F ~/.ssh/config.work -G devbox | grep -E 'hostname|user'

Keys

ssh-keygen -t ed25519 -C '<email>'

Generate a modern, compact ED25519 key pair (preferred over RSA).

-t ed25519|rsa|ecdsa; -b bits; -C comment; -f output_path; -N 'passphrase'; -q quiet

ssh-keygen -t ed25519 -C 'you@work' -f ~/.ssh/work_ed25519 -N ''
ssh-keygen -lf <pubkey>

Show the fingerprint and length of a public key (auditing SSH banners).

-E md5|sha256|shake256; -l list; -i read from stdin

ssh-keygen -lf ~/.ssh/id_ed25519.pub -E sha256
ssh-keygen -R <host>

Remove a host key from known_hosts (after the server is rebuilt / re-keyed).

-R '[host]:port' support non-default port

ssh-keygen -R '[bastion.example.com]:2222'
ssh-copy-id <user>@<host>

Install your public key into a remote authorized_keys (password auth required).

-i identity.pub; -p PORT; -o options

ssh-copy-id -i ~/.ssh/work_ed25519.pub -p 2222 deploy@bastion
ssh-add [path]

Add a private key to the running ssh-agent (so you don't re-type the passphrase).

-l list fingerprints; -D delete all; -d path remove; -t N lifetime

eval $(ssh-agent) && ssh-add ~/.ssh/work_ed25519 && ssh-add -l
ssh-keyscan <host>

Print remote host keys (for prebaking into known_hosts / bootstrap).

-t rsa|ed25519|ecdsa; -p PORT

ssh-keyscan -t ed25519 -p 2222 bastion.example.com >> ~/.ssh/known_hosts

Config File

~/.ssh/config

Per-user SSH config — declare hosts, aliases, identities, jump hosts, keepalives.

Host alias; HostName real; User; Port; IdentityFile; PreferredAuthentications; AddKeysToAgent yes; ServerAliveInterval 30; IdentitiesOnly yes; ProxyJump / ProxyCommand; LocalForward / RemoteForward; ControlMaster auto / ControlPath / ControlPersist

Host bastion HostName bastion.example.com Port 2222 User ops IdentityFile ~/.ssh/work_ed25519 Host db* ProxyJump bastion User ubuntu

File Transfer

scp <src> <dest>

Copy files between hosts over SSH (legacy but ubiquitous).

-r recursive; -P PORT; -i identity; -C compress; -p preserve mode/time; -l limit bandwidth (Kbit/s)

scp -P 2222 -r dist/ [email protected]:/srv/app/releases/1.4.2/
rsync -avz -e ssh <src> <dest>

Mirror / copy with delta sync — must faster for repeating transfers of large trees.

-a archive; -v verbose; -z compress; -P partial + progress; --delete mirror; --exclude; --dry-run; -e ssh -p 2222

rsync -avz -e 'ssh -p 2222' ./build/ ops@bastion:/srv/app/current/
sshfs <user>@<host>:<path> <mount>

Mount a remote filesystem over SSH (FUSE) — edit remote files with local tools.

-p PORT; -o reconnect; -o transform_symlinks; -C compress

sshfs ops@bastion:/srv/app ./remote -o reconnect,transform_symlinks
sftp <user>@<host>

Interactive / scripted file transfers over the SSH subsystem.

sftp -i id -P port; commands: get / put / sync / ls / lls / cd / lcd / chmod

sftp ops@bastion <<'EOF' mkdir /srv/app/releases/1.4.2 put -r dist/* /srv/app/releases/1.4.2/ EOF

Troubleshooting

ssh -vvv <host>

Trace the connection: KEX, auth, channel setup. Best for 'why is this failing?'

-v / -vv / -vvv; -E file write to file

ssh -vvv -E /tmp/ssh.dbg ops@bastion 2>&1 | grep -E 'Authentications|method|Permission denied'
ssh-keygen -y -f <private>

Derive the public key from a private key (when you only have the private half).

-f file; -E hash algorithm

ssh-keygen -y -f ~/.ssh/id_ed25519 > /tmp/derived.pub && diff ~/.ssh/id_ed25519.pub /tmp/derived.pub && echo OK
ssh -o ConnectTimeout=<N> -o ConnectionAttempts=<K>

Tune connection timeouts / retries for flaky networks or warm jump hosts.

ssh -o ConnectTimeout=5 -o ConnectionAttempts=2 ops@bastion
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3

Keep idle SSH connections alive through NAT / firewalls.

ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -L 5432:db:5432 -N ops@bastion

Trusted Forwarding

ssh -W %h:%p <proxy>

Use as ProxyCommand for a chained connection — old-style alternative to ProxyJump.

ProxyCommand ssh -W %h:%p myjumphost nc -q0 %h %p

ssh -o ProxyCommand='ssh -W %h:%p bastion.example.com' internal-db

Maintenance

ssh -O stop / ssh -M -S <sock>

ControlMaster — share a single SSH session across many terminals for speed.

-M master mode; -S socket path; -O check|forward|exit

ssh -M -S ~/.ssh/cm-%h bastion; ssh -S ~/.ssh/cm-%h bastion -O check

Related command cheatsheets

About OpenSSH

OpenSSH is the de facto standard secure-shell implementation, originally written by Tatu Ylönen in 1995 as proprietary software and re-implemented as open source by Theo de Raadt and the OpenBSD team in 1999. The current portable line is OpenSSH 9.x, shipped by default on every Linux distro, macOS (since 10.1 Panther), and available for Windows via the optional OpenSSH client/server feature and the Win32-OpenSSH port. OpenSSH provides encrypted remote login (`ssh`), secure file transfer (`scp`, `sftp`), port forwarding (local `-L`, remote `-R`, dynamic `-D` for SOCKS), jump hosts (`-J`), and an agent (`ssh-agent`) that holds decrypted private keys in memory so you do not retype passphrases. Authentication supports passwords, public-key (Ed25519 is the current recommendation; RSA-3072+ or ECDSA-P256 are acceptable fallbacks), FIDO2 hardware tokens via `sk-` key types, and Kerberos / GSSAPI on enterprise networks. The user config file `~/.ssh/config` is the most under-used feature — declare hosts once, then `ssh prod` works everywhere. Treat your private key like a password: passphrase-protect it, never copy it to shared machines, and use `ssh-keygen -t ed25519` instead of older RSA / DSA key types.

Cheatsheet version 1.0.0