How to generate an SSH key on Linux

The same commands work on Ubuntu, Debian, Fedora, Arch and nearly every other distribution: create an Ed25519 key, load it into ssh-agent and install it on a server.

updated

Quick answer. Run the first command and press Enter at each prompt, typing a passphrase when asked. The second installs the public key on a server; for GitHub, paste the output of cat ~/.ssh/id_ed25519.pub instead.

ssh-keygen -t ed25519 -C "[email protected]"
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host

What you are creating

ssh-keygen creates a key pair: a private key that never leaves your machine and a public key you install wherever you want to log in. When you connect, the server checks a signature made with the private key against the public key in its authorized_keys file. No secret crosses the network, nothing can be guessed, and once every user has a key the server can stop accepting passwords.

The same pair works for git hosting. GitHub, GitLab and Bitbucket accept the public key on your account page, and git push stops asking for tokens.

Use the Ed25519 type. It is the default in current OpenSSH, small, fast and supported by every maintained server. RSA is for old systems that do not know Ed25519; the trade-offs are in Ed25519 vs RSA.

How to generate an SSH key on Linux

  1. Make sure the OpenSSH client is installed

    Almost every desktop and server distribution includes it. Run ssh -V; if the command is missing, install the client package for your distribution:

    sudo apt install openssh-client     # Debian, Ubuntu, Mint
    sudo dnf install openssh-clients    # Fedora, RHEL, Rocky, Alma
    sudo pacman -S openssh              # Arch, Manjaro
    sudo apk add openssh-client         # Alpine
  2. Check for existing keys

    Look in ~/.ssh. If id_ed25519 is already there, either reuse it or choose a different file name in the next step so you do not overwrite a key that servers already trust.

    ls -al ~/.ssh
  3. Generate an Ed25519 key

    Run ssh-keygen with a comment that identifies the key. Accept the default path with Enter and type a passphrase twice.

    ssh-keygen -t ed25519 -C "[email protected]"

    The private key is saved as ~/.ssh/id_ed25519, the public key as ~/.ssh/id_ed25519.pub. For a server that predates OpenSSH 6.5, use ssh-keygen -t rsa -b 4096.

  4. Load the key into ssh-agent

    Most desktops (GNOME, KDE) already run an agent; echo $SSH_AUTH_SOCK prints its socket if so. Otherwise start one for this shell, then add the key and type the passphrase once:

    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/id_ed25519
  5. Copy the public key to a server

    ssh-copy-id logs in with your password one last time, appends the key to ~/.ssh/authorized_keys on the server and sets its permissions:

    ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host

    Then connect with ssh user@host. You should be asked for the key passphrase (or nothing, if the agent has it), not the account password.

What the output means

A full run of step 3 looks like this:

$ ssh-keygen -t ed25519 -C "[email protected]"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/you/.ssh/id_ed25519):
Created directory '/home/you/.ssh'.
Enter passphrase for "/home/you/.ssh/id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/you/.ssh/id_ed25519
Your public key has been saved in /home/you/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:I2McFhOvOOgBGIf3aLmk0z7TTKxZoLZ32hK6Bxbk7Tw [email protected]
The key's randomart image is:
+--[ED25519 256]--+
|...   +.         |
|o+.    +         |
|=..+  o .        |
| +*o.+ o         |
| **+o * S        |
|+=oE+o o .       |
|oo=Bo            |
| o*++.           |
| .+++.           |
+----[SHA256]-----+
  • Created directory appears only if ~/.ssh did not exist; ssh-keygen creates it with mode 700.
  • The passphrase prompt reads Enter passphrase (empty for no passphrase): on OpenSSH releases before 10. Typing shows nothing on screen.
  • The fingerprint identifies the public key. GitHub and GitLab show the same value next to the key, so you can tell keys apart later (more on fingerprints).
  • The randomart is a picture of the same fingerprint. You can ignore it.

The public key is one line: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... [email protected]. The private key file starts with -----BEGIN OPENSSH PRIVATE KEY----- and must never be pasted anywhere.

File permissions that ssh expects

If permissions are looser than this, the client refuses the key or the server silently ignores authorized_keys.

PathModeWhy
~/.ssh700Only you may list or add keys.
~/.ssh/id_ed25519600The client rejects a private key others can read.
~/.ssh/id_ed25519.pub644Public by design.
~/.ssh/authorized_keys600sshd's StrictModes ignores a writable file.
~/.ssh/config600ssh refuses a config others can write.
Your home directorynot group or world writableStrictModes checks every parent folder.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/authorized_keys ~/.ssh/config
chmod 644 ~/.ssh/id_ed25519.pub

Ownership matters as much as mode: every file in ~/.ssh must belong to you. ls -la ~/.ssh shows both.

Keep the key unlocked with ssh-agent

ssh-agent holds the decrypted key in memory, so you type the passphrase once instead of on every connection. Check whether one is running and what it holds:

$ ssh-add -l
256 SHA256:I2McFhOvOOgBGIf3aLmk0z7TTKxZoLZ32hK6Bxbk7Tw [email protected] (ED25519)

"The agent has no identities." means an agent runs but is empty; "Could not open a connection to your authentication agent." means there is none in this shell.

Add keys automatically on first use

Add this to ~/.ssh/config and the key joins the agent the first time you use it:

Host *
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519

ssh-add -l lists the keys the agent holds, ssh-add -t 8h ~/.ssh/id_ed25519 adds a key that expires after eight hours, and ssh-add -D forgets them all.

Desktops

GNOME (through GNOME Keyring or gcr-ssh-agent, depending on the release) and most KDE Plasma setups start an agent with your session. They may offer to remember the passphrase in the desktop keyring, which unlocks at login.

Servers, WSL and minimal systems

Without a desktop, nothing starts an agent. The keychain utility, packaged by most distributions, starts one agent and shares it between all your shells. Add this line to ~/.bashrc or ~/.zshrc:

eval "$(keychain --eval --quiet id_ed25519)"

It asks for the passphrase in the first shell after a reboot and reuses the agent after that.

Copy the public key to the clipboard

For GitHub, GitLab or a web control panel you need the public key on the clipboard:

cat ~/.ssh/id_ed25519.pub                          # print it and select it
wl-copy < ~/.ssh/id_ed25519.pub                    # Wayland (wl-clipboard)
xclip -selection clipboard < ~/.ssh/id_ed25519.pub # X11 (xclip)

Copy the whole line starting with ssh-ed25519, never the file without .pub. Where to paste it on each git host is covered in SSH key for GitHub, GitLab and Bitbucket.

Install the key on a server with ssh-copy-id

A first run of ssh-copy-id prints something like this:

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/you/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
user@host's password:

Number of key(s) added: 1

Now try logging into the machine, with: "ssh -i /home/you/.ssh/id_ed25519 'user@host'"
and check to make sure that only the key(s) you wanted were added.

Use -p 2222 for a different port. If the server has password logins turned off already, you need another way in: a cloud provider's key field, a console, or someone who can append the key for you. The manual method, restricted keys and how to turn off passwords safely are in adding a key to a server.

Use multiple SSH keys with ~/.ssh/config

Name each extra key with -f, then tell ssh which key goes with which host. Without this, ssh tries id_ed25519 and the other default names, plus everything in the agent, in order.

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_work -C "[email protected]"
Host work-db
  HostName db.internal.example.com
  User alice
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes

Host *
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519

Now ssh work-db uses the work key and only that key. For each option the first value found wins, so keep Host * at the end. ssh -G work-db prints the settings that apply to a host.

SELinux on Fedora, RHEL, Rocky and Alma

On distributions with SELinux enforcing, sshd may only read files labelled ssh_home_t. A .ssh folder created by mv from elsewhere, restored from a backup or copied with cp -a can keep a wrong label, and key logins fail although the modes are right. Restore the default labels on the server:

restorecon -R -v ~/.ssh

ls -Z ~/.ssh shows the current labels. The audit log (sudo ausearch -m avc -ts recent) records the denial if SELinux is the cause.

Keys from the browser generator

You can also generate a key in your browser with the sshkeygen.dev generator. Move the downloaded files into place and set the permissions:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
mv -i ~/Downloads/id_ed25519 ~/Downloads/id_ed25519.pub ~/.ssh/
chmod 600 ~/.ssh/id_ed25519

Troubleshooting

"WARNING: UNPROTECTED PRIVATE KEY FILE!"

Permissions 0644 for '/home/you/.ssh/id_ed25519' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.

The private key is readable by other users. Run chmod 600 ~/.ssh/id_ed25519.

"sign_and_send_pubkey: signing failed: agent refused operation"

The agent holds a key it cannot use, often after the files moved. Run ssh-add -D, fix the permissions and add the key again.

"Could not open a connection to your authentication agent"

No agent runs in this shell. Start one with eval "$(ssh-agent -s)". Note that running ssh-agent without eval only prints the variables and does not set them.

"Permission denied (publickey)"

Run ssh -v user@host. Lines with Offering public key show which keys were tried; if yours is missing, add -i or an IdentityFile line. If it is offered and refused, the server does not have it in the right account, or the server's permissions are wrong. On a Fedora, RHEL or Rocky server with correct permissions, the SELinux labels may be wrong: run restorecon -Rv ~/.ssh there.

"Bad owner or permissions on /home/you/.ssh/config"

Run chmod 600 ~/.ssh/config. If ls -l shows root as the owner, the file was edited with sudo; fix it with sudo chown "$USER": ~/.ssh/config.

"Host key verification failed"

The server's key no longer matches ~/.ssh/known_hosts, which happens after a reinstall and also during an interception attempt. Verify the new fingerprint, then run ssh-keygen -R host. See SSH key fingerprints.

"Unable to negotiate ... no matching host key type found. Their offer: ssh-rsa"

The server only offers the SHA-1 RSA signature, disabled by default since OpenSSH 8.8. Upgrade the server; if that is impossible, allow it for that host only in ~/.ssh/config with HostKeyAlgorithms +ssh-rsa and PubkeyAcceptedAlgorithms +ssh-rsa.

"ssh-copy-id: ERROR: No identities found"

ssh-copy-id found no key to send. Pass the file explicitly with -i ~/.ssh/id_ed25519.pub, and check that the key was really created.

FAQ

Where are SSH keys stored on Linux?

Your own keys are in ~/.ssh, which is /home/your-name/.ssh (or /root/.ssh for root). The server's host keys, which identify the machine rather than you, are in /etc/ssh/ssh_host_*_key. Do not touch those when creating a personal key.

Do I run ssh-keygen with sudo?

No. Run it as the user who will connect. With sudo the key is written to root's home, or into yours but owned by root, and ssh then refuses it. If that happened, fix ownership with sudo chown -R "$USER": ~/.ssh.

Is the command the same on Ubuntu, Fedora and Arch?

Yes. All of them ship upstream OpenSSH, so ssh-keygen -t ed25519, ssh-agent, ssh-add and ssh-copy-id behave the same. Only the package name and the SSH server's service name differ.

How do I see my public key?

Run cat ~/.ssh/id_ed25519.pub. It is one line starting with ssh-ed25519. If the .pub file is lost, rebuild it from the private key with ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub.

Can I use the same key on several Linux machines?

It works, but one key per machine is safer: if a laptop is lost you remove one public key and every other machine keeps working. Copying a key also copies its weaknesses, such as a missing passphrase.

Should I generate a key without a passphrase?

Only for unattended jobs such as backups or CI, and then restrict what that key may do on the server. For a key you use interactively, set a passphrase and let ssh-agent remember it. See SSH key passphrases.

What is the difference between ssh-agent and keychain?

ssh-agent holds unlocked keys in memory for one login session. The keychain utility, packaged by most distributions, starts one agent and reuses it across shells and logins on the same machine, so you type the passphrase once per boot.