SSH & SCP Cheat Sheet
Log in to remote machines securely and copy files between them. Works the same on Linux, macOS, Git Bash, WSL and Windows 10+ (OpenSSH is built in).
On this page
Connecting #
| Command | Action |
|---|---|
| Connect | |
| Connect on a different port | |
| Use a specific key | |
| Run one command and return | |
| Connect through a jump host | |
| Verbose output (debug connection problems) | |
exit or Ctrl + D | Disconnect |
Enter, then ~. | Kill a frozen session |
Keys #
| Command | Action |
|---|---|
| Create a key pair (recommended type) | |
| Install your public key on a server (then no password needed) | |
| Show your public key (this part is safe to share) | |
| then | Load the key into the agent (type the passphrase once) |
| Keys loaded in the agent | |
| Remove an old host key ("REMOTE HOST IDENTIFICATION HAS CHANGED") | |
| Change the passphrase |
Windows without ssh-copy-id:
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
~/.ssh/config (shortcuts) #
Host pi
HostName 192.168.1.50
User milan
Port 22
IdentityFile ~/.ssh/id_ed25519
Host *
ServerAliveInterval 60
Now ssh pi, scp file pi:~ and VS Code Remote-SSH all understand pi.
Copying Files (scp) #
| Command | Action |
|---|---|
| Upload | |
| Download to the current folder | |
| Upload a folder | |
| Custom port (capital P!) | |
| Copy between two remote hosts |
rsync (better for big or repeated copies) #
| Command | Action |
|---|---|
| Sync a folder (only sends changes) | |
| With progress | |
| Mirror (deletes extra files on the destination) | |
| Custom port | |
| Dry run: show what would happen |
A trailing / on src/ copies the contents. Without it, the folder itself is copied.
Port Forwarding (Tunnels) #
| Command | Action |
|---|---|
Local: your localhost:8080 → the server's port 80 | |
| Reach a private database through a server | |
| Remote: the server's port 9000 → your local 3000 | |
| SOCKS proxy through the server | |
| Tunnel only, in the background |
Server Side (sshd) #
| Command / setting | Action |
|---|---|
| Install the SSH server (Debian/Ubuntu) | |
/etc/ssh/sshd_config | Server configuration |
PasswordAuthentication no | Keys only (set up your key first!) |
PermitRootLogin no | Block root login |
Apply changes (sshd on Fedora/Arch) |
Permissions (common "bad permissions" error) #
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/authorized_keys ~/.ssh/config
chmod 644 ~/.ssh/id_ed25519.pub
sshLog in to another computer securely. ssh [options] [user@]host [command]
| Option | What it does |
|---|---|
-p 2222 | Port (default 22) |
-i ~/.ssh/key | Use a specific private key |
-l user | User name (same as user@host) |
-J jump@bastion | Go through a jump host |
-L 8080:localhost:80 | Local port forward: your 8080 → remote 80 |
-R 9000:localhost:3000 | Remote port forward: server 9000 → your 3000 |
-D 1080 | SOCKS proxy on local port 1080 |
-N | No remote command (just tunnels) |
-f | Go to the background after logging in |
-t | Force a terminal (for ssh host -t htop) |
-A | Forward your SSH agent (use with care) |
-X / -Y | Forward graphical apps (X11) |
-C | Compress traffic (slow connections) |
-o ServerAliveInterval=60 | Any config option on the command line |
-F file | Use another config file |
-q | Quiet |
-v / -vv / -vvv | Debug output (connection problems) |
-4 / -6 | IPv4 / IPv6 only |
In a session: Enter then ~. kills a frozen connection, ~? shows all escape keys.
ssh-keygenCreate and manage SSH keys. ssh-keygen [options]
| Option | What it does |
|---|---|
-t ed25519 | Key type (ed25519 recommended; rsa, ecdsa) |
-b 4096 | Key size (for RSA) |
-C "you@example.com" | Comment / label |
-f ~/.ssh/github | File name of the key |
-N "" | Passphrase (empty = none) |
-p -f key | Change the passphrase of a key |
-l -f key.pub | Show the fingerprint |
-y -f key | Print the public key from a private key |
-R host | Remove a host from known_hosts ("host key changed" errors) |
-F host | Find a host in known_hosts |
-a 100 | More KDF rounds (stronger passphrase protection) |
ssh-copy-idInstall your public key on a server so you can log in without a password. ssh-copy-id [options] user@host
| Option | What it does |
|---|---|
-i ~/.ssh/key.pub | Which key to install |
-p 2222 | SSH port |
-f | Force, even if the key seems installed |
-n | Dry run |
-o Option=value | Extra SSH option |
catPrint files (or join them). cat [options] file…
| Option | What it does |
|---|---|
-n | Number every line |
-b | Number non-empty lines only |
-s | Squeeze multiple empty lines into one |
-A | Show invisible characters: tabs as ^I, line ends as $ |
-E | Show $ at every line end (spot trailing spaces) |
-T | Show tabs as ^I |
cat a b > ab | Join files into a new one |
cat >> notes.txt | Type text and append it (end with Ctrl + D) |
ssh-agentKeeps your unlocked keys in memory. Start it: eval "$(ssh-agent -s)"
| Option | What it does |
|---|---|
-s | Print commands for sh/bash (use with eval) |
-c | Print commands for csh/fish-like shells |
-k | Stop the running agent |
-t 3600 | Keys expire after 1 hour |
ssh-addAdd keys to the SSH agent. ssh-add [options] [key]
| Option | What it does |
|---|---|
ssh-add | Add the default keys (~/.ssh/id_*) |
ssh-add ~/.ssh/github | Add a specific key |
-l / -L | List fingerprints / public keys of loaded keys |
-d key / -D | Remove one / all keys |
-t 3600 | Remove the key automatically after 1 hour |
-c | Confirm every use of the key |
--apple-use-keychain | macOS: store the passphrase in the Keychain |
scpCopy files over SSH. scp [options] source… target (remote = user@host:path)
| Option | What it does |
|---|---|
-r | Copy folders |
-P 2222 | Port (capital P, unlike ssh -p) |
-i ~/.ssh/key | Private key |
-p | Keep timestamps and permissions |
-C | Compress |
-l 8000 | Limit bandwidth (Kbit/s) |
-q | No progress meter |
-3 | Copy between two remote hosts through your computer |
-J jump@host | Through a jump host |
-o Option=value | Any SSH option |
-v | Debug output |
For large or repeated copies rsync is faster (it only sends changes).
rsyncFast, incremental copy and sync (local or over SSH). rsync [options] source destination
| Option | What it does |
|---|---|
-a | Archive: recursive + keep permissions, times, links (almost always used) |
-v | Verbose |
-z | Compress during transfer |
-h | Readable numbers |
-P | Show progress + keep partial files (resume) |
--progress | Progress only |
-n, --dry-run | Show what would happen, change nothing |
--delete | Delete files in the destination that are gone from the source (mirror) |
--exclude="node_modules" | Skip matching files (--exclude-from=file) |
--include="*.md" | Include pattern (combine with excludes) |
-e "ssh -p 2222" | SSH options such as a port |
-u | Skip files that are newer at the destination |
-c | Compare by checksum instead of time and size |
--remove-source-files | Move instead of copy |
--bwlimit=5m | Limit the speed |
-i | Itemize: show why each file changes |
--backup --backup-dir=old | Keep replaced files |
A trailing / on the source copies its contents: rsync -a src/ dst/.
aptalso: apt-getInstall and update software on Debian, Ubuntu, Mint and Raspberry Pi OS. sudo apt [options] command [packages]
| Command / option | What it does |
|---|---|
update | Refresh the package lists (do this first) |
upgrade | Upgrade installed packages |
full-upgrade | Upgrade, allowing packages to be added or removed |
install pkg… | Install (./file.deb installs a local file with dependencies) |
reinstall pkg | Reinstall |
remove pkg | Remove, keep config files |
purge pkg | Remove including config files |
autoremove | Remove dependencies that are no longer needed |
search word | Search packages |
show pkg | Package details |
list --installed / --upgradable | Installed / upgradable packages |
edit-sources | Edit the repository list |
-y | Answer "yes" to every question |
--no-install-recommends | Skip recommended extras (smaller installs) |
-s, --simulate | Show what would happen, change nothing |
--fix-broken | Repair broken dependencies (apt --fix-broken install) |
--only-upgrade pkg | Upgrade one package, don't install new ones |
-t bookworm-backports | Install from a specific release / repo |
-q | Less output |
systemctlControl systemd services (background programs). systemctl [options] command [service]
| Command / option | What it does |
|---|---|
status nginx | Is it running? Recent log lines |
start / stop / restart | Start / stop / restart now |
reload | Reload the config without stopping |
enable / disable | Start / don't start at boot |
enable --now | Enable at boot and start right away |
is-active / is-enabled | Yes/no answer (for scripts) |
list-units --type=service | All loaded services |
--failed | Services that crashed |
daemon-reload | Re-read service files after editing them |
cat nginx / edit nginx | Show / override a service file |
mask / unmask | Block a service completely / undo |
--user | Manage your own user services |
--no-pager, -l | Plain output, full lines |
reboot / poweroff | Restart / shut down the machine |
Nothing on this sheet matches “”.