Linux & Shell guide · Last updated

How to Generate an SSH Key (Windows, macOS and Linux)

To generate an SSH key, run ssh-keygen -t ed25519 -C "[email protected]" in a terminal and press Enter to accept the default location. The same command works on macOS, Linux and Windows 10 or 11, because all of them ship the OpenSSH client. It creates two files: a private key that never leaves your machine and a public key (ending in .pub) that you give to GitHub, GitLab or a server. This guide walks through generating the key, choosing between Ed25519 and RSA, adding it to GitHub and testing the connection, loading it into ssh-agent so you type the passphrase once, organising multiple keys in ~/.ssh/config, fixing permissions and copying the key to a server.

Quick answer

The comment after -C is just a label to help you recognise the key later; an email address or name@laptop are both common. Use a passphrase: it encrypts the private key on disk, so a stolen laptop backup does not hand over access to every server you use. With ssh-agent you only type it once per session.

bash
ssh-keygen -t ed25519 -C "[email protected]"
# Enter file in which to save the key (/home/you/.ssh/id_ed25519): [Enter]
# Enter passphrase (empty for no passphrase): ********

cat ~/.ssh/id_ed25519.pub      # this is the public key you share

Ed25519 or RSA 4096?

Choose Ed25519 unless something prevents it. Ed25519 keys are short, fast and secure, and they are supported by GitHub, GitLab, Bitbucket, Azure DevOps and every OpenSSH server released since 2014. RSA is the fallback for old systems, some hardware appliances and legacy enterprise servers that do not accept Ed25519. If you need RSA, use at least 3072 bits; 4096 is the common choice. Avoid DSA and ECDSA keys for new setups: DSA is disabled by default in modern OpenSSH, and RSA keys signed with SHA-1 are rejected by GitHub and recent servers.

The optional -a flag increases the number of key-derivation rounds used to protect the passphrase, which slows brute-force attacks on a stolen key file. -f sets the file name, which is useful when you keep separate keys for work and personal accounts.

bash
# Recommended
ssh-keygen -t ed25519 -a 100 -C "[email protected]"

# Legacy systems that need RSA
ssh-keygen -t rsa -b 4096 -C "[email protected]"

# A second key with its own file name
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519_work

Generate an SSH key on macOS and Linux

Open Terminal and run ssh-keygen as above. The keys are written to ~/.ssh/id_ed25519 (private) and ~/.ssh/id_ed25519.pub (public). If a key with that name already exists, ssh-keygen asks before overwriting it. Say no unless you are sure: overwriting locks you out of every server that only knows the old key. On Linux, ssh-keygen comes with the openssh-client package, installed by default on nearly every desktop distribution (sudo apt install openssh-client on minimal Debian or Ubuntu images).

Generate an SSH key on Windows

Built-in OpenSSH (Windows 10 and 11)

Windows 10 version 1809 and later include the OpenSSH client, so ssh-keygen works in PowerShell, Command Prompt and Windows Terminal with no extra software. Keys are stored in C:\Users\<you>\.ssh. If the command is not found, add it under Settings, System, Optional features, OpenSSH Client. Git for Windows also bundles its own copy in Git Bash.

powershell
ssh-keygen -t ed25519 -C "[email protected]"
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard   # copy public key

PuTTYgen

If you use PuTTY or WinSCP, generate keys with PuTTYgen. Choose EdDSA (Ed25519) or RSA with 4096 bits, click Generate and move the mouse to add randomness, enter a passphrase, then Save private key to get a .ppk file. Copy the text from the box labelled "Public key for pasting into OpenSSH authorized_keys file"; that is what GitHub and servers expect. To use the same key with OpenSSH tools, use Conversions, Export OpenSSH key.

Add your SSH key to GitHub and test it

Copy the contents of the .pub file, never the private key. On GitHub go to Settings, SSH and GPG keys, New SSH key, give it a title such as the laptop's name, leave the type as Authentication Key and paste the key. GitLab's equivalent is Preferences, SSH Keys.

Then test the connection. The first time, SSH asks you to confirm GitHub's host key fingerprint; compare it with the fingerprints GitHub publishes in its documentation before typing yes. A successful test prints a greeting with your username. Finally, make sure your repositories use the SSH URL rather than HTTPS.

bash
# Copy the public key
pbcopy < ~/.ssh/id_ed25519.pub                 # macOS
xclip -sel clip < ~/.ssh/id_ed25519.pub        # Linux (X11)
clip < %USERPROFILE%\.ssh\id_ed25519.pub        # Windows cmd

# Test
ssh -T [email protected]
# Hi your-username! You've successfully authenticated, but GitHub does not provide shell access.

# Switch an existing clone from HTTPS to SSH
git remote set-url origin [email protected]:your-username/your-repo.git

Warning

Never paste, upload or commit your private key (the file without .pub). If it is ever exposed, delete the public key from GitHub and every server and generate a new pair.

Load the key into ssh-agent

ssh-agent keeps decrypted keys in memory so you do not retype the passphrase for every git push. Most Linux desktops and macOS start an agent automatically; on a server or in a plain shell, start one with eval "$(ssh-agent -s)". On macOS, --apple-use-keychain stores the passphrase in the Keychain (older macOS versions used -K), and the config lines below make SSH reload it after a reboot. On Windows, the agent is a service that is disabled by default; enable it once from an Administrator PowerShell.

macOS

bash
eval "$(ssh-agent -s)"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
text
# ~/.ssh/config
Host github.com
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519

Linux

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

Windows (Administrator PowerShell)

powershell
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519

Use ~/.ssh/config for multiple keys and servers

The SSH config file saves you from typing usernames, ports and key paths. Each Host block defines an alias. IdentitiesOnly yes tells SSH to offer only the listed key, which avoids "Too many authentication failures" when the agent holds several keys. A common pattern is a separate alias for a work GitHub account, used in the clone URL in place of github.com.

text
# ~/.ssh/config
Host prod
  HostName 203.0.113.10
  User deploy
  Port 2222
  IdentityFile ~/.ssh/id_ed25519

Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes
bash
ssh prod                                         # instead of ssh -p 2222 [email protected]
git clone git@github-work:acme/internal-api.git  # uses the work key

Fix SSH key permissions

OpenSSH refuses to use a private key that other users can read and prints "WARNING: UNPROTECTED PRIVATE KEY FILE!" followed by "bad permissions". The server side is just as strict: if ~/.ssh or authorized_keys is group- or world-writable, key login silently falls back to a password. Set the permissions below. Use our chmod calculator if the numbers are unfamiliar. On Windows, the private key must be readable only by your account; remove other users and inherited permissions in the file's Security tab if SSH complains.

bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/config ~/.ssh/authorized_keys
chmod 644 ~/.ssh/id_ed25519.pub

Copy your public key to a server

To log in to a Linux server with your key, its public half must be appended to ~/.ssh/authorized_keys for the target user. ssh-copy-id does that, creates the directory with the right permissions, and asks for the password one last time. Windows has no ssh-copy-id, so pipe the key over SSH instead. Once key login works, consider setting PasswordAuthentication no in the server's sshd_config, but keep a second session open while you test so you cannot lock yourself out.

bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
ssh [email protected]        # should not ask for the account password now
powershell
# Windows PowerShell
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Generate an SSH key: FAQ

Quick answers to common questions

Should I use Ed25519 or RSA for SSH keys?

Use Ed25519. It is shorter, faster and widely supported. Generate an RSA key with ssh-keygen -t rsa -b 4096 only for older servers or devices that do not accept Ed25519.

Where are SSH keys stored?

In the .ssh folder in your home directory: ~/.ssh on macOS and Linux, C:\Users\<you>\.ssh on Windows. The private key is id_ed25519 and the public key is id_ed25519.pub.

How do I check if I already have an SSH key?

Run ls -al ~/.ssh (or dir $env:USERPROFILE\.ssh on Windows) and look for files such as id_ed25519.pub or id_rsa.pub. If they exist, you can reuse them instead of generating a new pair.

Why does ssh -T [email protected] say Permission denied (publickey)?

GitHub did not receive a key it recognises. Check that the public key is added to your GitHub account, that the key is loaded with ssh-add -l, and run ssh -vT [email protected] to see which key files SSH tries.

How do I change the passphrase of an SSH key?

Run ssh-keygen -p -f ~/.ssh/id_ed25519. You enter the old passphrase and then the new one; the key itself does not change, so nothing needs updating on GitHub or servers.

Related tools and references

More developer guides