SSH Tips: Keys, Config File, Port Forwarding, rsync and More

Networking · 9 min read · Updated 25 Oct 2026

On this page
  1. Create an SSH key
  2. Install the key on a server
  3. Type your passphrase once: ssh-agent
  4. The ~/.ssh/config file
  5. Port forwarding
  6. Jump hosts with ProxyJump
  7. Copying files: scp vs rsync
  8. Keeping connections alive
  9. Sensible client settings
  10. Quick reference

If you manage even one server, you use SSH every day. Most people stop at ssh user@host and typing a password. A few minutes of setup gives you password-free logins, short host names, secure tunnels to remote databases, and connections that do not freeze when you step away.

All examples use OpenSSH, the client that ships with Linux, macOS and current versions of Windows.

Create an SSH key

Key-based login is both safer and more convenient than passwords. Create a key pair with the Ed25519 algorithm, which is fast, short and secure:

$ ssh-keygen -t ed25519 -C "alice@laptop"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alice/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):

Press Enter to accept the default location, and choose a passphrase. The passphrase encrypts the private key on disk, so a stolen laptop or backup does not mean a stolen login. The -C comment is just a label to help you recognize the key later.

You now have two files:

  • ~/.ssh/id_ed25519: the private key. Never copy it to servers or share it.
  • ~/.ssh/id_ed25519.pub: the public key. This is what you put on servers.

Only very old servers lack Ed25519 support; for those, ssh-keygen -t rsa -b 4096 is the fallback. To add or change the passphrase of an existing key, run ssh-keygen -p -f ~/.ssh/id_ed25519.

Install the key on a server

ssh-copy-id appends your public key to ~/.ssh/authorized_keys on the server and fixes the permissions. You log in with your password one last time:

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

If ssh-copy-id is not available, do the same by hand:

$ cat ~/.ssh/id_ed25519.pub | ssh [email protected] 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'

SSH is strict about permissions. If key login silently falls back to a password, check that ~/.ssh is 700 and authorized_keys and private keys are 600 on the relevant machine, and that your home directory is not writable by others. The permissions guide explains these numbers.

Type your passphrase once: ssh-agent

An agent holds your unlocked key in memory, so you enter the passphrase once per session instead of on every connection. Most desktops start one automatically. On a server or a bare terminal:

$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_ed25519
$ ssh-add -l          # list loaded keys

The ~/.ssh/config file

Instead of typing ssh -p 2222 [email protected], give each server a short name in ~/.ssh/config:

Host web01
    HostName 203.0.113.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519

Host db
    HostName 10.0.0.5
    User admin
    ProxyJump web01

Host *.internal.example.com
    User alice

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Now ssh web01 is enough, and the same short name works with scp, rsync, git and anything else that uses SSH. A few rules to know:

  • For each setting, the first value found wins. Put specific Host blocks at the top and the general Host * block at the end.
  • Host patterns can use * and ?, and list several names separated by spaces.
  • Create the file with permissions 600: chmod 600 ~/.ssh/config.
To see the settings SSH will actually use for a host, without connecting, run ssh -G web01. It prints the final configuration after all matching blocks are applied, which makes config mistakes easy to spot.

Port forwarding

SSH can carry other network traffic through its encrypted connection. Add -N when you only want the tunnel and no remote shell.

Local forwarding (-L): reach a remote service from your machine

A database on a server usually listens only on that server's localhost, for good reasons. To use it from your laptop:

$ ssh -N -L 3307:127.0.0.1:3306 web01

While that runs, connecting to 127.0.0.1:3307 on your laptop reaches port 3306 on web01. The format is -L local_port:destination:destination_port, and the destination is resolved from the server's point of view, so 127.0.0.1 there means the server itself. The same trick opens an admin web page that is bound to localhost: ssh -N -L 8080:127.0.0.1:80 web01, then browse to http://localhost:8080.

Remote forwarding (-R): share a local service with the server

$ ssh -N -R 9000:127.0.0.1:3000 web01

This is the reverse: port 9000 on web01 now leads to port 3000 on your machine, for example a development server you want to test from the server. By default the remote port listens only on the server's localhost.

Dynamic forwarding (-D): a SOCKS proxy

$ ssh -N -D 1080 web01

This starts a SOCKS5 proxy on your machine at localhost:1080. Point a browser at it and its traffic leaves from your server, which is useful on untrusted Wi-Fi or for checking how a site looks from your server's location.

Tunnels you use often can go in the config file with LocalForward 3307 127.0.0.1:3306, RemoteForward and DynamicForward.

Jump hosts with ProxyJump

Many networks expose one "bastion" host and keep everything else private. -J connects through the bastion in a single command, and your key never needs to be copied onto it:

$ ssh -J [email protected] [email protected]

In the config file, ProxyJump does the same, as the db entry above shows: ssh db goes through web01 automatically. Separate several hops with commas.

Copying files: scp vs rsync

scp is simple and works like cp:

$ scp report.pdf web01:/tmp/
$ scp -r web01:/var/log/nginx ./nginx-logs
$ scp -P 2222 file.txt [email protected]:~/    # note: capital -P for the port

rsync is better for anything big or repeated. It copies only what changed, can resume, preserves permissions and times, and shows progress:

$ rsync -avz --progress ./site/ web01:/var/www/site/
$ rsync -avz -e 'ssh -p 2222' ./site/ [email protected]:/var/www/site/
$ rsync -avzn ./site/ web01:/var/www/site/      # -n: dry run, show what would change

-a (archive) keeps permissions, times and symlinks and recurses into directories, -v lists files, and -z compresses in transit. The trailing slash on the source matters: ./site/ copies the contents of site, while ./site creates a site directory inside the destination. rsync must be installed on both ends.

rsync --delete removes files on the destination that are not in the source. Combined with a wrong path or a missing trailing slash, it can wipe a directory. Always run it once with -n first and read the list.

Keeping connections alive

Idle SSH sessions often freeze or drop because a router or firewall forgets the connection. ServerAliveInterval 60 in your config makes the client send a small message every 60 seconds, and ServerAliveCountMax 3 gives up after three unanswered ones, so a dead connection ends cleanly instead of hanging.

When a session does hang, you do not need to close the terminal. Press Enter, then type ~. (tilde, period) to make the client disconnect. ~? lists the other escape commands.

If you open many connections to the same server, connection sharing makes every new ssh, scp or git command start almost instantly:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h:%p
    ControlPersist 10m

Sensible client settings

A few settings make your own SSH client safer. Add them to the Host * block at the end of ~/.ssh/config:

Host *
    IdentitiesOnly yes
    ForwardAgent no
    HashKnownHosts yes
    AddKeysToAgent yes
  • IdentitiesOnly yes offers only the keys you configure, instead of every key in your agent, which avoids "too many authentication failures" errors and avoids revealing unrelated keys to servers.
  • ForwardAgent no is the default; keep it, and enable it only for specific hosts you fully trust. Anyone with root on a server you forward to can use your agent while you are connected. ProxyJump usually removes the need for forwarding.
  • HashKnownHosts yes stores host names in ~/.ssh/known_hosts in hashed form, so the file does not list every server you use.
  • AddKeysToAgent yes adds a key to the running agent the first time you unlock it.

Pay attention to host key warnings. The first time you connect, SSH shows the server's key fingerprint; compare it with the one your hosting provider or administrator gives you. If SSH later warns that the host key has changed, find out why before continuing. When you know the change is legitimate (for example, you reinstalled the server), remove the old entry with ssh-keygen -R web01. Do not set StrictHostKeyChecking no to make the warning go away.

When something does not work, ssh -v web01 shows each step of the connection, including which keys are offered and why authentication fails. Every option is documented in ssh(1) and ssh_config(5).

Quick reference

TaskCommand
Create a keyssh-keygen -t ed25519 -C "label"
Install key on serverssh-copy-id user@host
Load key into agentssh-add ~/.ssh/id_ed25519
Show effective configssh -G host
Local tunnelssh -N -L 3307:127.0.0.1:3306 host
Remote tunnelssh -N -R 9000:127.0.0.1:3000 host
SOCKS proxyssh -N -D 1080 host
Through a bastionssh -J bastion target
Sync a directoryrsync -avz src/ host:dest/
Kill a frozen sessionEnter then ~.
Forget an old host keyssh-keygen -R host
Debug a connectionssh -v host

To run commands on many servers in a loop, see the note about ssh -n in the loops guide.