Step-by-step tutorial, 2026
How to generate an SSH key on Windows. Tested, start to finish.
Every command on this page was run on a real Windows 11 PC against a real Linux server, and the terminal output you see is what came back. Including the errors.
Your Windows PC
Your server
The short answer
Open PowerShell and run ssh-keygen -t ed25519. Press Enter to keep the location, type a passphrase twice, and your key pair lands in C:\Users\you\.ssh: id_ed25519 stays on your PC, id_ed25519.pub goes to the server.
Windows has no ssh-copy-id, so copy the public key with one PowerShell line (below), then log in with ssh user@your-server. Our free command builder fills in every command for your server.
Passwords get guessed. Our own server saw more than 14,000 password attempts in its first three days online.
An SSH key can’t be guessed. It’s a pair of files: a private key that never leaves your PC, and a public key you hand to the server. When you log in, the server checks that you hold the matching private key. No password crosses the internet at all.
Here’s the catch. Most Windows guides stop after ssh-keygen. Then they tell you to run ssh-copy-id, which Windows doesn’t have. Several still say the default key type is RSA, which stopped being true in 2023.
So we did it properly. We ran every step on Windows 11 against an Ubuntu 24.04 server, broke it on purpose four different ways, and wrote down exactly what each error looks like and how to fix it.
In this guide you’ll learn
- Check that OpenSSH is on your PC, in one command
- Create an Ed25519 key, with a passphrase and a label that doesn’t leak your name
- Copy it to your server without
ssh-copy-id - Log in with one word using a config file and ssh-agent
- Use it in PuTTY, and convert between PPK and OpenSSH
- Fix “Permission denied (publickey)” with the real server logs
Chapter 1
The short answer
Here’s the whole job in four PowerShell commands. Replace [email protected] with your server’s user and address, or let the builder below do it.
| Step | Command | What it does |
|---|---|---|
| 1. Check | ssh -V | Confirms the built-in OpenSSH client is installed |
| 2. Create | ssh-keygen -t ed25519 -C "laptop-2026" | Makes id_ed25519 and id_ed25519.pub in C:\Users\you\.ssh |
| 3. Copy | The one-liner in step 3 below | Adds your public key to ~/.ssh/authorized_keys on the server |
| 4. Connect | ssh [email protected] | Logs in with the key instead of a password |
Chapter 2
Get your exact commands
Type your server’s address, user and port. The builder writes every command in this tutorial for your server, in the same form we tested. It runs only in your browser.
ssh-keygen -t ed25519 -C "laptop-2026" -f "$HOME\.ssh\id_ed25519"Press Enter to accept the file, then type a passphrase twice.
$pubKey = (Get-Content "$HOME\.ssh\id_ed25519.pub" | Out-String); ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '$pubKey' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"Asks for your server password one last time.
ssh -i "$HOME\.ssh\id_ed25519" [email protected]Host myvps
HostName 203.0.113.10
User root
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesThen just type: ssh myvps
icacls "$HOME\.ssh\id_ed25519" /inheritance:r
icacls "$HOME\.ssh\id_ed25519" /grant:r "${env:USERNAME}:R"No server yet? Deploy a Lite 2 and paste your .pub key at deploy: you skip step 2 and log straight in. Billed by the hour.
Each step below explains what these commands do and what you should see, so you’re never pasting blind.
Chapter 3
Step 1: Check OpenSSH is installed
Windows ships Microsoft’s build of OpenSSH, the same software Linux and macOS use. Open PowerShell (press Start, type PowerShell) and ask it for its version:
PS C:\Users\you> ssh -VOpenSSH_for_Windows_9.5p2, LibreSSL 3.8.2PS C:\Users\you> Get-Service ssh-agent | Select-Object Status, StartTypeStatus StartType------ ---------Stopped Disabled
If you see a version, skip to step 2. If PowerShell says ssh isn’t recognised, install it. OpenSSH has been an optional Windows feature since Windows 10 build 1809:
- Windows 11: Settings, System, Optional features, View features, then search for OpenSSH Client and add it.
- Or in PowerShell as administrator:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Chapter 4
Step 2: Create your key
Run this in PowerShell. You don’t need administrator rights:
ssh-keygen -t ed25519 -C "laptop-2026"
It asks three things: where to save the key (press Enter for the default), then a passphrase, twice. Here’s what comes back:
PS C:\Users\you> ssh-keygen -t ed25519 -C "litekeep-test"Generating public/private ed25519 key pair.Your identification has been saved in C:\Users\you\.ssh\id_ed25519Your public key has been saved in C:\Users\you\.ssh\id_ed25519.pubThe key fingerprint is:SHA256:JKnwhfyuOT429Sv/HeX4e/KgruZKIptps4IqhTB3SAU litekeep-testThe key's randomart image is:+--[ED25519 256]--+| Eo. || .. . . || ...o + . ||o oo.+ o ||.+ .o . S . ||. . .. + || o ..o.. o o ||o . BB.o. .. +...||+ =O* o+*+o+ o=.|+----[SHA256]-----+
Why Ed25519?
It’s short, fast and strong, and it’s been the default since OpenSSH 9.5 in 2023. On our PC, plain ssh-keygen made an Ed25519 key too. We still type -t ed25519 so the command works the same on older builds. Only use RSA (-t rsa -b 4096) for an old system that rejects Ed25519.
Use a passphrase
The passphrase encrypts the private key file. If your laptop is stolen, the key is useless without it. Don’t leave it empty. Step 6 shows how to type it once per session instead of every time.
Mind the label
The text after -C is a comment saved inside the public key. Without it, OpenSSH fills in your user@host: your Windows username and your PC’s name. That label ends up on every server you add the key to. Most tutorials tell you to put your email there. Use something neutral that tells you which device it is.
Chapter 5
Step 3: Put the public key on your server
The server needs your public key in a file called ~/.ssh/authorized_keys. On Mac and Linux, ssh-copy-id does that. Windows doesn’t include it, so use this one line instead:
$pubKey = (Get-Content "$HOME\.ssh\id_ed25519.pub" | Out-String); ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '$pubKey' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
It reads your public key, logs in one last time with your password, creates the .ssh folder if needed, adds the key, and sets the permissions the server insists on: 700 for the folder, 600 for the file. In our test it finished silently, which is what success looks like.
- Deploying on LiteKeep? Paste the contents of
id_ed25519.pubwhen you deploy the server and skip this step entirely. Your first login already uses the key. - Different SSH port? Add
-p 2222afterssh. The builder above does it for you. - Never send the file without .pub. That’s your private key.
MythYou need ssh-copy-id from a third-party installer.
You don’t. It only appends one line to a text file, and the PowerShell line above does exactly that, with the right permissions.
MythThe public key is secret.
It’s meant to be shared. The private key, the file with no extension, is the one to guard.
Chapter 6
Step 4: Log in with your key
Now connect. OpenSSH tries id_ed25519 automatically, so this is usually all you need:
ssh [email protected]
The first time, it shows the server’s fingerprint and asks if you trust it. Compare it with your server’s fingerprint if you have it, then type yes. It’s saved in known_hosts and won’t ask again.
Then it asks for your key’s passphrase, not the server password. That difference is how you know the key worked. If you saved the key under another name, point at it with -i:
ssh -i "$HOME\.ssh\id_ed25519" [email protected]
Chapter 7
Step 5: Log in with one word
Typing users, addresses and ports gets old. OpenSSH on Windows reads a config file at %USERPROFILE%\.ssh\config. Create it in Notepad (no file extension) and add:
Host myvps
HostName 203.0.113.10
User user
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesNow ssh myvps is the whole command. In our test, a config like this logged straight in. Add Port 2222 if you use a different port, and one Host block per server.
IdentitiesOnly yes tells SSH to offer only that key. Without it, a PC with many keys can hit the server’s limit on attempts before the right key gets its turn.
Chapter 8
Step 6: Type your passphrase once
ssh-agent holds your unlocked key in memory, so you type the passphrase once instead of on every connection. On Windows the agent is disabled by default, and on our PC it was.
Open PowerShell as administrator once and run:
Get-Service ssh-agent | Set-Service -StartupType Automatic Start-Service ssh-agent
Then, in a normal PowerShell window, add your key and type the passphrase one last time:
ssh-add "$HOME\.ssh\id_ed25519"
From now on, ssh myvps connects without asking. Automatic keeps the agent running after a restart; Manual would mean starting it yourself each time.
Chapter 9
Using PuTTY or PuTTYgen instead
Some tools, like WinSCP and older PuTTY setups, want keys in PuTTY’s own .ppk format. PuTTYgen converts in both directions.
- OpenSSH key to PPK: open PuTTYgen, choose Conversions, Import key, pick
id_ed25519, enter its passphrase, then Save private key. - PPK to OpenSSH: Load the
.ppk, then Conversions, Export OpenSSH key. - The public key for the server is the box labelled Public key for pasting into OpenSSH authorized_keys file. Copy from there, not from the “Save public key” file, which uses a different, multi-line format the server won’t accept.
- Old PuTTY? New PPK files are version 3. Only PuTTY 0.74 and older need version 2.
Chapter 10
Fix “Permission denied (publickey)”
This message is frustrating because it’s the same for every cause. We triggered each cause on our test server. Here’s what the client said, what the server’s log said, and the fix. For all twelve causes we reproduced, and a free error decoder, see our Permission denied (publickey) guide.
| Cause | Server log says | Fix |
|---|---|---|
| Wrong user name | Invalid user deploy | Use the user the key was added for, often root on a new server |
| Wrong key offered | Connection closed … [preauth], no reason given | Point at the right key with -i, or IdentityFile in the config |
| authorized_keys writable by everyone (666) | bad ownership or modes for file …/authorized_keys | chmod 600 ~/.ssh/authorized_keys |
| .ssh folder writable by everyone (777) | bad ownership or modes for directory …/.ssh | chmod 700 ~/.ssh |
| Private key readable by others on Windows | Nothing: the client refuses before sending it | The icacls fix below |
A surprise from our test: making authorized_keys group-writable (664) did not break login, because OpenSSH allows it when the group contains only you. Many guides say any loose permission breaks it. Only world-writable did.
See which key SSH is offering
Add -v and look for these lines:
PS C:\Users\you> ssh -v -i .\other_key [email protected]debug1: Authentications that can continue: publickeydebug1: Offering public key: .\other_key ED25519 SHA256:EMQ9pBYv… explicitdebug1: Authentications that can continue: publickeydebug1: No more authentication methods to try.[email protected]: Permission denied (publickey).
“UNPROTECTED PRIVATE KEY FILE” on Windows
If other accounts can read your private key, OpenSSH refuses to use it. We gave Everyone read access to a copy of our key to see it happen:
Bad permissions. Try removing permissions for user: \Everyone (S-1-1-0) on file C:/Users/you/.ssh/id_ed25519.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ WARNING: UNPROTECTED PRIVATE KEY FILE! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Permissions for 'C:\Users\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.[email protected]: Permission denied (publickey).
The fix: remove inherited permissions and give only yourself read access. These two lines fixed it in our test (if the warning names an account, like Everyone, also run icacls "$HOME\.ssh\id_ed25519" /remove Everyone):
icacls "$HOME\.ssh\id_ed25519" /inheritance:r
icacls "$HOME\.ssh\id_ed25519" /grant:r "${env:USERNAME}:R"- Right user?How to check: The key is added per user. root and deploy have separate authorized_keys files.
- Right key?How to check: Run with
-vand check the “Offering public key” line. - Server permissions?How to check:
chmod 700 ~/.sshandchmod 600 ~/.ssh/authorized_keys, run on the server. - Key on one line?How to check: Each key in authorized_keys must be a single line starting with ssh-ed25519.
- Lost the .pub file?How to check:
ssh-keygen -y -f "$HOME\.ssh\id_ed25519"prints it again from the private key. It worked in our test.
Chapter 11
Next: close the password door
Your key works. But while password logins stay on, bots can keep guessing. The last step is to turn passwords off on the server.
Do it in the order our VPS security guide lays out: create your own sudo user, give it your key, test in a second window, and only then disable root and password logins. Its free generator writes the commands for your server.
- New laptop? Make a new key on it and add that one too. Don’t copy private keys between machines.
- Lost a device? Delete its line from
~/.ssh/authorized_keyson every server. - Running Windows Server too? Admin accounts there use administrators_authorized_keys in
C:\ProgramData\ssh, not the file in your user folder.
Need a server to try this on? A Lite bills by the hour, so a practice run costs cents. Deploy a Lite 2 with your new key pasted in, and your first login is already passwordless. Or run Windows itself on a Windows VPS.
Now it’s your move
That’s the whole thing: one key pair per device, the public half on each server, a passphrase you type once per session, and a config file that turns every login into one word.
If something goes wrong, the error is almost always one of the five causes above, and -v plus the server log will point at it.
Your key is ready. Give it a server. Paste it in when you deploy a Lite, log in with one word, and pay only for the hours it runs.