Cheatsheets:LinuxCLI/ssh: Difference between revisions

From Wikibase
Jump to navigation Jump to search
Remove stray placeholder line in the Agent section. AI-assisted (RonzzWikiCowriter) (via update-page on MediaWiki MCP Server)
Add Category:LinuxCLI (LinuxCLI backfill) (via update-page on MediaWiki MCP Server)
Line 236: Line 236:


Wiki: wikibase.ronzz.org
Wiki: wikibase.ronzz.org
[[Category:LinuxCLI]]

Revision as of 20:40, 29 September 2026

Languages: English · français · Esperanto

Quick reference for smart people — part of our Linux cheatsheets collection.

The everyday OpenSSH client: log into a remote machine, run one-off commands, copy files, and tunnel ports over an encrypted channel. Everything here is typed on your local Linux machine; the remote side only needs a running sshd.

New to SSH? Every command has a built-in manual — try man ssh, man ssh_config or tldr ssh for short examples.

Basic example: set up key login

ssh user@host                            # first connection: type the password
ssh-keygen -t ed25519 -C "user@laptop"   # create ~/.ssh/id_ed25519 and its .pub
ssh-copy-id user@host                    # install the public half on the server
ssh user@host                            # no password from now on

The private key never leaves your machine; the server only stores the public half, one key per line, in ~/.ssh/authorized_keys.

Connecting

ssh host                              # same username as your local one
ssh user@host                         # log in as another user
ssh -p 2222 user@host                 # non-standard port
ssh user@host uptime                  # run one command instead of a shell
ssh user@host 'df -h; free -h'        # several commands: quote them for the remote shell
ssh -t user@host tmux attach          # -t: force a TTY, for interactive programs
ssh -J bastion user@host              # jump through bastion (ProxyJump)
ssh -J user@bastion:2222 user@host    # jump host with its own user and port
ssh -o ProxyCommand="ssh -W %h:%p bastion" user@host   # same, on OpenSSH < 7.3
ssh -v user@host                      # debug the connection; -vv and -vvv go further
Flag Effect
-p port connect to a port other than 22
-i key authenticate with a specific private key
-t / -T force / disable pseudo-terminal allocation
-N no remote command: forward ports only
-f go to the background just before running the command
-J host connect via a jump host; comma-separated for several
-L / -R / -D port forwarding (see below)
-A forward your local ssh-agent to the server (see the caution below)
-o OPT=value set any ssh_config option on the command line

Escape sequences are recognised only at the start of a line, inside an interactive session:

Escape Action
~. disconnect
~^Z suspend ssh, back to the local shell
~# list the forwarded connections
~C command line: add -L, -R or -D to the live session
~? list all escapes

Keys

ssh-keygen -t ed25519                        # new key in ~/.ssh/id_ed25519 (+ .pub)
ssh-keygen -t ed25519 -f ~/.ssh/id_work -C "deploy@laptop"   # a named key, with a comment
ssh-keygen -t rsa -b 4096                    # RSA, when a server is too old for ed25519
ssh-keygen -p -f ~/.ssh/id_ed25519           # change the passphrase
ssh-keygen -y -f ~/.ssh/id_ed25519           # print the public half of a private key
ssh-keygen -l -f ~/.ssh/id_ed25519.pub       # fingerprint of a key
ssh-keygen -R host                           # forget a host's key in known_hosts
ssh-copy-id user@host                        # install the default key on a server
ssh-copy-id -i ~/.ssh/id_work.pub user@host  # install one specific key
ssh -i ~/.ssh/id_work user@host              # use a key without touching any config

Permissions are enforced: ssh silently ignores a private key that anyone else can read. Keep ~/.ssh at 700 and private keys at 600 (chmod 600 ~/.ssh/id_ed25519). Protect the key with a passphrase and load it into an agent rather than leaving it unencrypted.

~/.ssh/config

The place to turn a long command line into a name you can type.

Host web                       # `ssh web` connects as deploy@203.0.113.10 on port 2222
    HostName 203.0.113.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_work

Host *.internal.example.com
    ProxyJump bastion

Host legacy
    HostKeyAlgorithms +ssh-rsa          # for old servers only
    PubkeyAcceptedAlgorithms +ssh-rsa

Host *                         # global defaults: keep this block LAST
    ServerAliveInterval 30     # ping every 30 s, so idle NAT and firewall sessions survive
    ServerAliveCountMax 3
    AddKeysToAgent yes         # load a key into the agent on first use
    ControlMaster auto         # reuse one TCP connection for every later session
    ControlPath ~/.ssh/cm/%C
    ControlPersist 10m
mkdir -p ~/.ssh/cm              # ControlPath does not create the directory
ssh -G web                      # print the configuration and options actually used
ssh -F ~/.ssh/otherconf host    # use an alternative config file
ssh -o StrictHostKeyChecking=accept-new host   # accept an unknown host key once
ssh -O check host               # is a shared connection open?
ssh -O exit host                # close it, and every session using it

For each option, the first value found wins. Put the specific Host blocks at the top of the file and the catch-all Host * at the bottom, or the defaults will shadow the specifics. IdentityFile is the exception: every entry is tried in order.

Connection sharing (the ControlMaster block) makes the second and later connections to a host start instantly, because they reuse the first, already-authenticated one; later scp, rsync and git calls to that host skip the handshake too.

Copying files

scp file1.txt user@host:/tmp/          # upload
scp user@host:/tmp/file1.txt .         # download to the current directory
scp -r dir/ user@host:/tmp/            # a whole directory
scp -P 2222 file1.txt user@host:/tmp/  # note: -P (capital) is scp's port flag
scp 'user@host:/var/log/*.log' .       # quote the remote glob
rsync -avz --progress dir/ user@host:/tmp/   # only what changed, resumable
sftp user@host                         # interactive: ls, get, put, bye

scp has spoken SFTP since OpenSSH 9.0, and it reads the same ~/.ssh/config blocks: scp web:file1.txt . works once Host web exists. For large or repeated transfers prefer rsync, which transfers only the differences and can resume — it must be installed on both machines.

Port forwarding

ssh -L 8080:localhost:80 user@host        # local 8080 → port 80, as seen from the server
ssh -L 5432:db.internal:5432 user@host    # reach a host only the server can reach
ssh -R 9000:localhost:3000 user@host      # the server's 9000 → your local 3000
ssh -D 1080 user@host                     # SOCKS5 proxy on localhost:1080
ssh -N -f -L 8080:localhost:80 user@host  # tunnel only, in the background
ssh -O exit user@host                     # close the backgrounded tunnel
Flag Listens on Traffic goes to
-L 8080:host:80 your machine, port 8080 host, as resolved from the server
-R 9000:host:3000 the server, port 9000 host, as resolved from your machine
-D 1080 your machine, port 1080 whatever the SOCKS client asks for

The same forwardings in config, for a tunnel you start by name:

Host dbtunnel
    HostName db.example.com
    LocalForward 5432 localhost:5432   # 5432 as seen from the server
    SessionType none                   # no shell, just the tunnel (OpenSSH 8.4+)

-L listens on your machine, -R on the server's. Both bind to loopback by default, so only that machine can reach the port — exposing it to a network needs an explicit bind address (-L 0.0.0.0:8080:localhost:80), and ports below 1024 require root.

Agent

eval "$(ssh-agent -s)"            # start an agent in this shell
ssh-add ~/.ssh/id_ed25519         # load a key; asks for the passphrase once
ssh-add -t 8h ~/.ssh/id_ed25519   # ... dropping it again after 8 hours
ssh-add -l                        # fingerprints of the loaded keys
ssh-add -L                        # full public keys
ssh-add -d ~/.ssh/id_ed25519      # remove one key
ssh-add -D                        # remove every key
ssh-agent -k                      # kill this agent
ssh -A user@host                  # forward the agent to the server
ssh-add -c ~/.ssh/id_ed25519      # ...or make every use of a key prompt for confirmation

Avoid ssh -A on hosts you do not fully trust: anyone able to read the agent socket there (root, mostly) can authenticate as you for as long as the session lasts, without ever seeing the key. Prefer -J (ProxyJump), where authentication stays end-to-end. AddKeysToAgent yes in ~/.ssh/config loads keys into the agent on first use.

Troubleshooting

Symptom Fix
Permission denied (publickey) the key is not installed: ssh-copy-id user@host; check chmod 600 ~/.ssh/id_ed25519; ssh -v lists the keys the client offers
Too many authentication failures the agent offers more keys than the server allows attempts: add IdentitiesOnly yes to that host's block
REMOTE HOST IDENTIFICATION HAS CHANGED! the server's key really did change — confirm with its admin before running ssh-keygen -R host
Connection refused wrong port, sshd down, or a firewall: test with nc -vz host 22
Connection timed out nothing answers at all: a firewall is dropping the packets, or the host is unreachable
the session freezes after an idle spell ServerAliveInterval 30 in the config file
which key, which options, which file? ssh -G host prints the effective configuration, ssh -vvv host everything the client tries

For more

  • man ssh, man ssh_config, man ssh-keygen, man sshd_config — the built-in manuals, always installed
  • ssh(1) — every client flag, escape sequence and environment variable
  • ssh_config(5) — every client option, including the forwarding and multiplexing ones
  • ssh-keygen(1) — certificates, FIDO keys, key format conversion
  • sshd_config(5) — the server side: authorized_keys, PermitRootLogin, PasswordAuthentication
  • OpenSSH — release notes and security advisories
  • tldr — community-maintained short examples
  • explainshell.com — annotate any command line

Wiki: wikibase.ronzz.org