# How to create SSH keys and manage multiple keys

How to create SSH keys, copy them safely to a server, and configure a different
key for each server or Git hosting account.

## Check for existing SSH keys

SSH keeps user configuration and keys in the hidden `~/.ssh` directory. List its
contents before creating anything so you do not accidentally overwrite an
existing key:

```shell
ls -la ~/.ssh
```

It is normal for the directory not to exist yet. Create it with permissions that
allow only your user to access it:

```shell
mkdir -p ~/.ssh
chmod 700 ~/.ssh
```

For a generated key pair, the file ending in `.pub` is the public key and the
matching file without that suffix is the private key.

Never publish, email, commit, or copy a private key to a server.

## Generate an SSH key

Create an Ed25519 key on your local machine. Ed25519 is the default in current
OpenSSH releases and is a good choice for most users:

```shell
ssh-keygen -t ed25519 -C "bob@laptop for example.net" -f ~/.ssh/id_ed25519_example
```

The comment supplied with `-C` is only a label. A descriptive label makes the
key easier to recognize later. The `-f` option gives this key a unique name,
which is useful when you manage more than one identity.

If the server does not support Ed25519, create an RSA key instead. A 3072-bit
RSA key is sufficient for most uses:

```shell
ssh-keygen -t rsa -b 3072 -C "bob@laptop for example.net" -f ~/.ssh/id_rsa_example
```

`ssh-keygen` asks for a passphrase. Use a strong, unique passphrase so a stolen
private-key file cannot immediately be used. An SSH agent can remember the
unlocked key during your session, so you do not need to type the passphrase for
every connection.

The Ed25519 command creates two files:

`~/.ssh/id_ed25519_example`

The private key. Keep it secret and only on devices from which you connect.

`~/.ssh/id_ed25519_example.pub`

The public key. Install this on servers and services you want to access.

You may inspect or copy the public key:

```shell
cat ~/.ssh/id_ed25519_example.pub
```

It is one line and looks approximately like this:

```text
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG9exampleonlynotarealkey bob@laptop for example.net
```

To identify a key without displaying all of it, print its fingerprint:

```shell
ssh-keygen -lf ~/.ssh/id_ed25519_example.pub
```

## Copy the public key to a server

Cloud providers often let you add a public key while creating a server. If you
do that, the provider installs it for the user you selected. Do not assume it
belongs in `/root`: the usual location is `~/.ssh/authorized_keys` in the
account you will log in to.

If the server already accepts your password or another key, install the new
public key with one of the following methods.

### Method 1: `ssh-copy-id`

If `ssh-copy-id` is installed, it is the simplest option:

```shell
ssh-copy-id -i ~/.ssh/id_ed25519_example.pub user@123.45.56.78
```

For a server listening on port `5555`, add `-p`:

```shell
ssh-copy-id -i ~/.ssh/id_ed25519_example.pub -p 5555 user@123.45.56.78
```

Some systems, including macOS, may not include `ssh-copy-id` by default. The
next method only needs the standard SSH client.

### Method 2: send it over SSH

This command appends the public key and applies permissions accepted by the
usual `sshd` configuration:

```shell
cat ~/.ssh/id_ed25519_example.pub | ssh -p 5555 user@123.45.56.78 \
  'umask 077; mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'
```

Omit `-p 5555` if the server uses the default SSH port, `22`. Running the
command more than once may add duplicate lines, which is harmless but untidy.

### Method 3: copy it manually

Display the public key:

```shell
cat ~/.ssh/id_ed25519_example.pub
```

Log in to the server and paste that entire single line into
`~/.ssh/authorized_keys`. Then fix the remote permissions:

```shell
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
```

Only copy the file ending in `.pub`. The private key never belongs in
`authorized_keys` or anywhere else on the remote server.

## Verify the server and test the connection

On the first connection, SSH shows the server's host-key fingerprint. Verify it
against a fingerprint supplied by the server administrator or cloud-provider
console before accepting it. This check protects you from connecting to an
impostor.

Keep your current server session open while testing the new key in a second
terminal. That way you can repair `authorized_keys` if the new login fails:

```shell
ssh -i ~/.ssh/id_ed25519_example -o IdentitiesOnly=yes -p 5555 \
  user@123.45.56.78
```

The `-i` option selects the private identity file. If authentication fails, add
`-v` for diagnostic output, or `-vvv` for more detail:

```shell
ssh -vvv -i ~/.ssh/id_ed25519_example -o IdentitiesOnly=yes \
  user@123.45.56.78
```

## Use an SSH agent

An SSH agent keeps decrypted private keys in memory. Many desktop environments
start one automatically. If yours does not, start an agent and add the key:

```shell
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519_example
```

List the keys currently available through the agent with:

```shell
ssh-add -l
```

The agent saves you from repeatedly entering a passphrase, but it does not
replace one. A private key protected by a passphrase is safer at rest.

## Manage multiple SSH keys

You do not need a separate key for every server. A key per client device is a
common starting point because you can revoke a lost device without disrupting
the others. Separate keys can also be useful for personal and work accounts or
other trust boundaries.

OpenSSH recognizes default private-key names such as `id_ed25519` and `id_rsa`.
For custom names, or when an agent holds several keys, use `~/.ssh/config` to
select the right identity for each destination.

Create the config file as your own user, without `sudo`, and restrict its
permissions:

```shell
touch ~/.ssh/config
chmod 600 ~/.ssh/config
```

Add one `Host` block per destination:

```ssh-config
Host myserver
  HostName 123.45.56.78
  User bob
  Port 5555
  IdentityFile ~/.ssh/id_ed25519_example
  IdentitiesOnly yes

Host mysecondserver
  HostName example.org
  User alice
  IdentityFile ~/.ssh/id_ed25519_example_org
  IdentitiesOnly yes
```

The options mean:

`Host`
  A local alias used on the command line.
  `HostName`
  The server's domain name or IP address.
  `User`
  The account name on the remote server.
  `Port`
  The SSH port. Leave it out when the server uses port 22.
  `IdentityFile`
  The local private key to use, without the `.pub` suffix.
  `IdentitiesOnly`

Offer only the configured identity instead of trying every key in the agent.
    This also avoids “Too many authentication failures” errors.

You can now connect using the alias:

```shell
ssh myserver
```

To see the final configuration SSH will use, run:

```shell
ssh -G myserver
```

### Multiple accounts on the same Git host

Aliases are also useful when you have personal and work accounts on the same Git
provider:

```ssh-config
Host github-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_github_personal
  IdentitiesOnly yes

Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_github_work
  IdentitiesOnly yes
```

Use the matching alias in each repository's remote URL:

```shell
git remote set-url origin git@github-work:company/project.git
```

The alias changes only how your local SSH client chooses a key. Both entries
still connect to `github.com`.

## Rotate or revoke a key

If a private key may be compromised, remove its public-key line from every
server's `~/.ssh/authorized_keys` file and every service account where you
registered it. Remove it from the agent with
`ssh-add -d ~/.ssh/id_ed25519_example`, then generate a new key.

For routine rotation, install and test the replacement key before removing the
old one so you do not lock yourself out. Keep a known-working session open until
the replacement login succeeds.

The OpenSSH [`ssh-keygen`](https://man.openbsd.org/ssh-keygen),
[`ssh_config`](https://man.openbsd.org/ssh_config), and
[`sshd`](https://man.openbsd.org/sshd) manual pages contain the complete option
and file-format references.
