SSH and OpenSSH Cheat Sheet

SSH quick reference: keys, the config file, file transfer with scp and rsync, port forwarding, sshd hardening, and the Windows and ESXi specifics that trip people up.

Start here

Make a key
ssh-keygen -t ed25519
Install it on a server
ssh-copy-id user@host
Connect on another port
ssh -p 2222 user@host
Copy a file down
scp user@host:/path .
Reach a port through the server
ssh -L 8080:localhost:80 user@host
Host key changed warning
ssh-keygen -R host
This works from Windows too. Windows has its own OpenSSH client, so ssh, scp, sftp and ssh-keygen run in PowerShell with the same syntax and nothing here needs PuTTY. Confirm it with ssh -V; if the command is not recognised, add it with Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0. The walk-through is in Connect to a Linux server from Windows.

Connecting

TaskCommand
Basic connectionssh user@host
Non-standard portssh -p 2222 user@host
Pick a specific keyssh -i ~/.ssh/id_ed25519 user@host
Run one command and exitssh user@host "df -h"
Through a jump hostssh -J jump@bastion user@target
Why is it refusing messh -v user@host, more detail with -vvv
Accept a new host key without promptingssh -o StrictHostKeyChecking=accept-new user@host
Ignore the agent and any config, for testingssh -o IdentitiesOnly=yes -i key user@host
Forget a changed host keyssh-keygen -R host
Look up what is stored for a hostssh-keygen -F host

Keys

TaskCommand
Create a modern keyssh-keygen -t ed25519 -C "zaur@workstation"
Create an RSA key, for old systemsssh-keygen -t rsa -b 4096 -C "zaur@workstation"
Key in a specific filessh-keygen -t ed25519 -f ~/.ssh/id_srv01
Install the public key on a serverssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
See what it would do firstssh-copy-id -n user@host
Fingerprint of a keyssh-keygen -lf ~/.ssh/id_ed25519.pub
Recover the public key from a private onessh-keygen -y -f ~/.ssh/id_ed25519
Change or add a passphrasessh-keygen -p -f ~/.ssh/id_ed25519
Load a key into the agentssh-add ~/.ssh/id_ed25519
What is loaded right nowssh-add -l
FileRequired permissions on Linux
~/.ssh700
~/.ssh/id_ed25519600
~/.ssh/id_ed25519.pub644
~/.ssh/authorized_keys600
~/.ssh/config600
Wrong permissions look like a wrong key. OpenSSH silently refuses a private key that others can read, and refuses key authentication when the home directory or ~/.ssh is group writable. The error says permission denied, never “fix your permissions”. ssh -v shows which key was offered and rejected.

The config file

Stop retyping ports, users and keys. This lives in ~/.ssh/config, and on Windows in C:\Users\you\.ssh\config.

Host srv01
    HostName 10.0.0.21
    User zaur
    Port 2222
    IdentityFile ~/.ssh/id_srv01

Host *.dmz
    ProxyJump bastion
    ServerAliveInterval 60

Host bastion
    HostName bastion.example.com
    User jump
    IdentitiesOnly yes
DirectiveWhat it does
HostNameThe real address. Host is just the nickname you type.
IdentityFileWhich key to offer
IdentitiesOnly yesOffer only that key, not everything in the agent
ProxyJumpGo through a bastion, same as -J
ServerAliveInterval 60Keep idle sessions from being dropped by a firewall
ForwardAgent yesLet the next hop use your local keys. Use sparingly.
StrictHostKeyCheckingyes, no or accept-new
The config applies to scp and rsync too. Once srv01 is defined, scp file srv01:/tmp/ and rsync -av dir/ srv01:/backup/ both inherit the port, user and key. That is the real payoff.

Moving files

TaskCommand
Upload a filescp report.csv user@host:/tmp/
Download a filescp user@host:/var/log/messages .
A whole directoryscp -r dist/ user@host:/opt/app/
Non-standard port, note the capital Pscp -P 2222 file user@host:/tmp/
Interactive transfersftp user@host
Sync a tree, resumable and incrementalrsync -avh --progress dir/ user@host:/backup/
Mirror, deleting what is gonersync -avh --delete dir/ user@host:/backup/
See what it would do firstrsync -avhn --delete dir/ user@host:/backup/
rsync over a non-standard portrsync -avh -e "ssh -p 2222" dir/ user@host:/backup/
The trailing slash decides everything in rsync. dir/ copies the contents of dir, dir copies the directory itself into the target. Combined with --delete, getting it wrong nests or wipes a tree. Always dry run with -n first.

Tunnels

GoalCommand
Reach a service that only the server can reachssh -L 8080:10.0.0.50:80 user@host
Reach something on the server itselfssh -L 5432:localhost:5432 user@dbhost
Expose your local service to the serverssh -R 9000:localhost:3000 user@host
SOCKS proxy for a browserssh -D 1080 user@host
Tunnel without a shell sessionssh -N -L 8080:localhost:80 user@host
Send it to the backgroundssh -f -N -L 8080:localhost:80 user@host
Read -L left to right. The first port is on your machine, the rest is what the server will connect to on your behalf. So -L 8080:10.0.0.50:80 means your localhost:8080 arrives at port 80 on 10.0.0.50, as seen from the server. This is how you reach an iLO or a vCenter that is not routable from your desk.

The server side

TaskCommand or setting
Config file/etc/ssh/sshd_config, plus drop-ins in sshd_config.d/
Check the config before restartingsshd -t
Apply changes, RHEL family and Photon OSsystemctl restart sshd
Apply changes, Debian and Ubuntusystemctl restart ssh
Turn off password loginsPasswordAuthentication no
Keys only, explicitlyPubkeyAuthentication yes
Root login policyPermitRootLogin no or prohibit-password
Limit who may connectAllowUsers zaur svc-backup
Change the portPort 2222, and open it in the firewall first
Who is logged in nowwho, or ss -tnp state established '( dport = :22 or sport = :22 )'
Failed attempts, RHEL familyjournalctl -u sshd -p err or /var/log/secure
Failed attempts, Debian and Ubuntujournalctl -u ssh or /var/log/auth.log
Keep the session open. Test a changed sshd config from a second terminal before closing the one you are in. sshd -t catches syntax errors, but it will not tell you that AllowUsers just excluded you, and on a remote server that mistake needs console access to undo.

Windows and VMware specifics

SituationWhat to do
Where the client keys live on WindowsC:\Users\you\.ssh\
Agent on WindowsSet-Service ssh-agent -StartupType Automatic, then Start-Service ssh-agent and ssh-add
Key file rejected as too open on WindowsRemove inherited rights: icacls key /inheritance:r /grant:r "$env:USERNAME:R"
Install the OpenSSH server on WindowsAdd-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Keys for a normal user on Windows serverC:\Users\user\.ssh\authorized_keys
Keys for an administrator on Windows serverC:\ProgramData\ssh\administrators_authorized_keys
Enable SSH on an ESXi hostvim-cmd hostsvc/enable_ssh, or from the host UI. Disable it again afterwards.
Root key on ESXi/etc/ssh/keys-root/authorized_keys
Shell on the vCenter applianceConnect, then type shell to leave the appliance shell
The administrators_authorized_keys trap. On Windows Server, a key for any account in the Administrators group is read from that single ProgramData file, not from the user’s profile, and it must be owned by Administrators or SYSTEM with inheritance removed. A key that works for a standard user and fails for an admin is almost always this.

FAQ

Permission denied (publickey) and the key is definitely right.
Run ssh -v and read which keys were offered. The usual causes are file permissions on the client, a home directory that is group writable on the server, SELinux context on ~/.ssh after the file was copied in, or the server simply not listing that user in AllowUsers. On the RHEL family, restorecon -Rv ~/.ssh fixes the SELinux case.
Warning about a changed host key. Is it an attack?
Usually the server was rebuilt or you are reaching a different node behind the same address. Verify the fingerprint out of band if the machine matters, then clear the old entry with ssh-keygen -R host. Never disable host key checking permanently to make the message go away.
The session dies after a few minutes of inactivity.
A firewall or NAT device is timing out the idle connection. Set ServerAliveInterval 60 in your client config, which is friendlier than changing the server. For long jobs, run them under tmux or screen so a dropped session does not kill the work.
ed25519 or RSA?
ed25519 by default: shorter, faster and supported everywhere modern. Keep a 4096-bit RSA key for old appliances and network gear that predate it. Both can sit in the agent, and IdentityFile in the config picks the right one per host.
Can I avoid typing the passphrase every time?
That is what the agent is for: ssh-add once per session on Linux, or the ssh-agent service on Windows. A key with no passphrase at all is a file that grants access to anyone who copies it, which is a reasonable trade only for a tightly scoped automation account.