You do not need PuTTY anymore. Modern Windows ships the OpenSSH client built in, which means ssh user@server works directly in PowerShell exactly the way it does on macOS and Linux - same commands, same key files, same ~/.ssh/config. For anyone who has spent years exporting PuTTY sessions and converting keys to its private format, this is a quiet, genuine upgrade: your Windows machine now speaks the same SSH as every server you connect to.
The one thing that still trips people is where PowerShell keeps things and how a couple of Windows defaults differ. Get those straight and the PuTTY era is over.
Table of contents
- Confirm the client is there
- Generating and placing keys
- The ssh config file is the real win
- Port forwarding and tunnels
- Two Windows-specific gotchas
- How this fits the rest of the stack
- FAQ
Confirm the client is there
# In PowerShell
ssh -V
# OpenSSH_for_Windows_9.x, LibreSSL ...
If ssh is not recognized, the OpenSSH Client is an optional feature. Install it once from an elevated PowerShell:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
That is the whole install. From here, everything is standard OpenSSH - the knowledge transfers directly to and from any Unix box you have ever used.
Generating and placing keys
Keys live in C:\Users\you\.ssh, which PowerShell also knows as ~/.ssh. Generate a modern key:
ssh-keygen -t ed25519 -C "you@windows-laptop"
# Press Enter to accept ~/.ssh/id_ed25519, set a passphrase
Ed25519 is the right default in 2026 - shorter than RSA and just as strong. Copy the public key to the server. Windows has no ssh-copy-id, so use this one-liner:
Get-Content ~/.ssh/id_ed25519.pub | ssh user@server "cat >> ~/.ssh/authorized_keys"
After that, ssh user@server logs in with the key. No password, no PuTTYgen, no .ppk conversion. The key is a normal OpenSSH key that also works if you copy it to a Mac.
The ssh config file is the real win
Create ~/.ssh/config and give each server a short alias:
Host prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519
Port 22
Host db
HostName 203.0.113.20
User admin
ForwardAgent yes
Now ssh prod is the whole command. This is what PuTTY’s saved-sessions list was always trying to be, except it is a plain text file you can version-control, comment, and copy between machines. If you manage more than two servers, this file is the single biggest quality-of-life improvement available.
Port forwarding and tunnels
The tunnelling PuTTY buried in checkboxes is a flag here. To reach a database that only listens on the server’s localhost:
# Local 5432 -> server's localhost:5432
ssh -L 5432:localhost:5432 prod
# Now a local psql/GUI connects to 127.0.0.1:5432 as if the DB were local
-L local:host:remote is local forwarding, the one you want most often - it makes a remote private service look local so a desktop tool can reach it over the encrypted tunnel. -D 1080 sets up a SOCKS proxy; -R does remote forwarding. All three are one flag each, no dialog boxes.
Two Windows-specific gotchas
- Permissions on the private key. OpenSSH refuses to use a key that is too openly readable. On Windows this surfaces as a ‘bad permissions’ or ‘unprotected private key’ error. Fix it by removing inherited permissions and granting only your user, via the file’s Security properties or
icacls. - Line endings in authorized_keys. If you paste a public key edited in a Windows editor, a stray carriage return can break the match. Append it with the piping command above rather than copy-pasting into an editor and the problem never appears.
How this fits the rest of the stack
Native SSH on Windows removes a translation layer, and removing translation layers is the same instinct that makes deployment sane: fewer moving parts between you and the running server. When the server is a managed service, you often do not even need the SSH session - the platform exposes the logs and shell where the deploy happens. The RunxBuild hosting calculator shows what a service, its database, and its bandwidth cost as separate line items, and the RunxBuild dashboard gives you the logs and access without managing SSH keys on a box yourself.
Useful related references:
- SSL port: which port SSH and TLS actually use
- How to check your IP address on Ubuntu
- Services on RunxBuild
FAQ
Does PowerShell have SSH built in?
Yes. Modern Windows 10 and 11 ship the OpenSSH client, so ssh, scp, and ssh-keygen work natively in PowerShell with no PuTTY required. If the command is missing, install the OpenSSH Client optional feature with Add-WindowsCapability -Online -Name OpenSSH.Client. After that it behaves exactly like SSH on macOS or Linux.
Where does PowerShell store SSH keys?
In C:\Users<you>.ssh, which PowerShell also refers to as ~/.ssh. Keys, the config file, and known_hosts all live there, the same layout as Unix. Generate a key with ssh-keygen -t ed25519 and it defaults to that folder. Because it is standard OpenSSH, the keys are portable to other operating systems.
How do I copy an SSH public key to a server from Windows?
Windows has no ssh-copy-id, so pipe the key over an existing SSH session: Get-Content ~/.ssh/id_ed25519.pub | ssh user@server ‘cat >> ~/.ssh/authorized_keys’. This appends the public key correctly and avoids the stray carriage returns you can introduce by pasting the key into a text editor.
Why does SSH say my private key has bad permissions on Windows?
OpenSSH refuses to use a private key that other users can read. On Windows, remove inherited permissions on the key file and grant access only to your own user, using the file’s Security tab or icacls. Once your account is the sole principal with read access, the unprotected-private-key error goes away.
How do I set up an SSH tunnel in PowerShell?
Use the -L flag for local forwarding: ssh -L 5432:localhost:5432 prod forwards your local port 5432 to the server’s localhost:5432, so a local database client connects as if the database were on your machine. -D creates a SOCKS proxy and -R does remote forwarding. Each is a single flag, unlike PuTTY’s tunnelling dialog.