To connect to a server over SSH, open a terminal (or PowerShell on Windows 10 and 11) and type ssh user@IP, for example ssh root@203.0.113.10. The first time, you confirm the server's fingerprint, enter the password and land on the server's command line. Password logins, however, are both less secure and more tedious; the right way is to log in with an SSH key.

Generating an SSH key on Windows, Linux and macOS takes one command: ssh-keygen -t ed25519. It creates two files: a private key that stays on your machine and a public key (ending in .pub) that you put on the server or on GitHub. Below we walk through every step: creating the key, copying it to the server, shortening the connect command with a config file, adding the key to GitHub, and fixing common errors.

Short answer: To connect over SSH, run ssh user@IP in a Linux or macOS terminal or in PowerShell on Windows 10 and 11. For passwordless login, generate a key pair with ssh-keygen -t ed25519 and put the public key (the .pub file) on the server with ssh-copy-id or by appending it to ~/.ssh/authorized_keys. The private key should never leave your machine.

Make an ed25519 key, copy it to the server, log in without a password and use a short host name.

How do SSH keys work?

An SSH key is a cryptographic key pair. The public key is like a lock: you can install it on as many servers as you like, and it does no harm if someone sees it. The private key is the key to that lock and must never leave your machine. When you connect, the server sends a challenge that only the holder of the private key can answer, and no password ever crosses the network.

The recommended algorithm today is ed25519: its keys are short, fast and secure, and every recent version of OpenSSH and GitHub supports it. You only need RSA when dealing with very old systems, and then with at least 4096 bits.

Diagram: the public key is copied to the server's authorized_keys, the private key stays on your computer and signs the login
The private key never leaves your computer; the server only holds the public half.

Generate an SSH key on Linux and macOS

Open a terminal and run:

bash
ssh-keygen -t ed25519 -C "you@example.com"

The -C part is just a comment so you know later whose key this is; people usually put an email address or machine name. The command asks two questions:

  1. Where to save it: the default is ~/.ssh/id_ed25519. Press Enter unless you already have a key with that name.
  2. Passphrase: a password that locks the private key itself. If your laptop is stolen, this is what stops someone using the key. We recommend not leaving it empty.

The result is two files:

text
~/.ssh/id_ed25519       ← private key; never share it
~/.ssh/id_ed25519.pub   ← public key; this goes on the server

To avoid typing the passphrase on every connection, hand the key to ssh-agent once:

bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

On macOS and most Linux desktops the agent is already running, so ssh-add alone is enough.

Generate an SSH key on Windows

Windows 10 (version 1809 and later) and Windows 11 include the OpenSSH client, so you no longer need PuTTY. Open PowerShell and run the same command:

powershell
ssh-keygen -t ed25519 -C "you@example.com"

The files are created in C:\Users\<username>\.ssh\. If you get "ssh-keygen is not recognized", install "OpenSSH Client" from Settings → System → Optional features.

The ssh-agent service is disabled by default on Windows. Open PowerShell as Administrator once and run:

powershell
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent

Then, in a normal PowerShell window, add the key:

powershell
ssh-add $env:USERPROFILE\.ssh\id_ed25519

Copy the public key to the server

With ssh-copy-id (Linux and macOS)

The simplest way:

bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@203.0.113.10

It asks for the user's password once, appends the key to ~/.ssh/authorized_keys on the server, and sets the permissions correctly.

Manually (and on Windows)

Windows has no ssh-copy-id, but this one-liner in PowerShell does the same job:

powershell
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh deploy@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

If you have another way into the server (such as your provider's web console), you can copy the contents of the .pub file and paste it on a new line in ~/.ssh/authorized_keys. Each key is exactly one line; make sure your editor does not wrap it.

Now test it:

bash
ssh deploy@203.0.113.10

If you get in without being asked for the user's password (or are only asked for the key's passphrase), it works. At this point you can disable password login on the server; the details are in the first hour on a new Linux server. Test the login in a new window before closing your current session, so you do not lock yourself out.

File permissions: 700 and 600

OpenSSH is strict about file permissions. If the directory or files are writable by other users, it ignores the key and falls back to asking for a password. On the server:

bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod go-w ~

And on your own machine (Linux and macOS):

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

If you see UNPROTECTED PRIVATE KEY FILE when connecting, it is precisely the private key's permissions that are wrong.

Shorten your connect command with ~/.ssh/config

Once you have several servers with different users, ports and keys, remembering them all gets hard. The ~/.ssh/config file (on Windows, C:\Users\<username>\.ssh\config) gives each server a short alias:

~/.ssh/config
Host app
    HostName 203.0.113.10
    User deploy
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Host staging
    HostName 198.51.100.20
    User deploy
    IdentityFile ~/.ssh/id_ed25519_staging
    IdentitiesOnly yes

Host *
    ServerAliveInterval 60

From now on, instead of the long command you just type ssh app. The same alias works with scp and rsync: scp backup.sql app:/tmp/. IdentitiesOnly yes makes SSH try only the key you specified rather than every key in the agent, which prevents the "Too many authentication failures" error. ServerAliveInterval keeps idle sessions from being dropped.

Add an SSH key to GitHub

With an SSH key, git push and git pull stop asking for a username and token.

  1. Copy the public key:
    • Linux: cat ~/.ssh/id_ed25519.pub
    • macOS: pbcopy < ~/.ssh/id_ed25519.pub
    • Windows: Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard
  2. On GitHub, go to Settings → SSH and GPG keys and click New SSH key.
  3. Give it a title (such as the laptop's name), set the type to Authentication Key and paste the key.

Now test the connection:

bash
ssh -T git@github.com

The first time, you need to confirm GitHub's fingerprint; compare it with the official list in GitHub's documentation. A successful response looks like this:

text
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

From now on, clone repositories using the SSH URL: git clone git@github.com:username/repo.git. If you previously cloned a repository over HTTPS, switch its remote:

bash
git remote set-url origin git@github.com:username/repo.git

For a server that only needs to pull one repository, use a deploy key in that repository's settings instead of your personal key, so the server's access is limited to that one repository. The everyday Git commands are covered in essential Git commands.

Common errors and fixes

Permission denied (publickey)

The server accepted none of the keys you offered. Check, in order:

  • Are you connecting as the right user? Is the key in that user's authorized_keys, not root's?
  • Was the public key copied completely, on a single line?
  • Are the 700 and 600 permissions correct on the server?
  • If you have several keys, did you specify the right one with -i or IdentityFile?

The best diagnostic tool is verbose mode, which shows which keys were tried:

bash
ssh -v deploy@203.0.113.10

If you have another way into the server, the server-side log tells you the exact reason:

bash
sudo journalctl -u ssh -n 50

REMOTE HOST IDENTIFICATION HAS CHANGED

SSH stores each server's fingerprint in ~/.ssh/known_hosts on first connect. If it changes later, you get this big warning. The usual cause is harmless: you reinstalled the server, or the old IP was assigned to a new machine. But this warning exists precisely to detect man-in-the-middle attacks, so before moving on make sure the change was yours. Then remove the old fingerprint:

bash
ssh-keygen -R 203.0.113.10

and reconnect to record the new one.

Connection refused or Connection timed out

Neither has anything to do with keys. refused means the server is reachable but nothing is listening for SSH on that port (the service is down or the port has changed). timed out means packets are not reaching the server at all; check the IP, the server's firewall (ufw) or your provider's firewall.

Frequently asked questions

Where are SSH keys stored?

On Linux and macOS they live by default in ~/.ssh/id_ed25519 (private key) and ~/.ssh/id_ed25519.pub (public key); on Windows, in the .ssh folder inside your user folder, C:\Users\<username>\.ssh\. On the server, authorised public keys go in that user's ~/.ssh/authorized_keys file.

Do I need PuTTY for SSH on Windows?

No. Windows 10 from version 1809 and Windows 11 include the OpenSSH client, so ssh and ssh-keygen work directly in PowerShell. If they are missing, install OpenSSH Client from Optional features in Settings.

ed25519 vs. RSA: which SSH key type should I use?

ed25519 is the recommended algorithm today: its keys are shorter, faster and secure, and all recent versions of OpenSSH and GitHub support it. RSA is only needed for very old systems, and then it should be at least 4096 bits.

Can I use the same SSH key on multiple servers?

Yes. The public key works like a lock that you can install on any number of servers and on GitHub, and exposing it carries no risk. For a server that only needs to pull one specific repository, though, a deploy key for that repository is better than your personal key.

Should I set a passphrase on my SSH key?

It is optional but recommended, because if your computer or laptop falls into someone else's hands, the passphrase is what stops them using the private key. Add the key to ssh-agent once and you will not have to type the passphrase on every connection.

Wrap-up

An SSH connection starts with a single ssh user@host, but proper work is done with keys: generate one once with ssh-keygen -t ed25519, protect it with a passphrase, put the public key on your servers with ssh-copy-id or by hand and on GitHub, and give each server a short name in ~/.ssh/config. Do not forget the 700 and 600 permissions, and reach for ssh -v first whenever something fails. After that, the real work on the server begins; essential Linux commands for servers is a good next step.