Skip to content

Instantly share code, notes, and snippets.

@Th3w33knd
Last active March 26, 2026 19:16
Show Gist options
  • Select an option

  • Save Th3w33knd/f6eeafe6fdbc8958559b16cb9d48238f to your computer and use it in GitHub Desktop.

Select an option

Save Th3w33knd/f6eeafe6fdbc8958559b16cb9d48238f to your computer and use it in GitHub Desktop.
SSH in Host Windows

Complete Windows SSH Setup Guide (Revised)

Based on real troubleshooting - every step explains what you're doing and why.


How SSH Authentication Works (Read This First)

SSH key authentication is a lock-and-key system between two machines:

Concept Analogy File
Private Key Your physical house key (never share it) id_ed25519 on the Client
Public Key A lock you install on a door id_ed25519.pub → copied to the Host
Host The remote PC you want to control Stores the "lock" (public key)
Client Your laptop/controller Holds the "key" (private key)

The flow:

  1. Client says: "I have this key, let me in."
  2. Host checks its list of approved locks.
  3. If the key fits a lock → access granted, no password needed.
  4. If no match → falls back to asking for a password.

Why "Permission Denied" happens

  • The Host doesn't have your public key in the right file → password prompt
  • The file permissions are too loose → SSH ignores the key for security → password prompt
  • You used the wrong username → the account doesn't exist or has no password set → denied
  • You regenerated keys but forgot to update the Host → lock and key no longer match → denied

Part 1: The CLIENT (Your Laptop - The Controller)

Run these on the device you connect FROM. Regular PowerShell is fine.

Step 1: Generate Your SSH Key Pair

ssh-keygen -t ed25519
  • Press Enter to accept the default save location (C:\Users\YourName\.ssh\id_ed25519)
  • Press Enter twice to skip passphrase (or set one for extra security)

This creates two files:

File What it is Share it?
~/.ssh/id_ed25519 Your private key ❌ NEVER
~/.ssh/id_ed25519.pub Your public key ✅ Yes, copy to Host

Step 2: Copy Your Public Key

cat ~/.ssh/id_ed25519.pub

Copy the entire output. It looks like:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... yourname@YourPC

⚠️ WARNING - The Key Overwrite Trap If you ever run ssh-keygen again and overwrite the key, the fingerprint changes. The Host will no longer recognize you. You must re-copy the new public key to the Host every time you regenerate.

Save this output somewhere. You will paste it on the Host in Part 2.


Part 2: The HOST (The Remote PC You Want to Control)

Run ALL of these in an Administrator PowerShell window on the target machine.

Step 1: Find Your REAL Username

whoami

Expected output: COMPUTERNAME\hp or COMPUTERNAME\john, etc.

🔑 WHY THIS MATTERS: The part after the \ is your actual SSH username. This is often NOT your display name.

What you see on screen What SSH actually needs
Display Name: "Avitesh" ❌ Won't work
Microsoft email: avitesh@gmail.com ❌ Won't work
Folder: C:\Users\HP ✅ Username is hp

Write this username down. You will use it to connect.


Step 2: Install OpenSSH Server

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

Then start it and make it run on every boot:

Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

Checklist:

  • Command completed without errors
  • Get-Service sshd shows Status: Running

Step 3: Create the Authorized Keys File & Set Permissions

🔑 WHY administrators_authorized_keys instead of authorized_keys?

Windows SSH has a special rule: if your account is in the Administrators group (most home PCs), it ignores the normal user-level key file (C:\Users\hp\.ssh\authorized_keys) and ONLY checks a global file at C:\ProgramData\ssh\administrators_authorized_keys.

This is controlled by the Match Group administrators block in sshd_config. If you're an admin, your key must go in ProgramData.

Copy and paste this entire block at once:

# Create the directory (if it doesn't exist) and the key file
New-Item -ItemType Directory -Force -Path "C:\ProgramData\ssh"
New-Item -ItemType File -Force -Path "C:\ProgramData\ssh\administrators_authorized_keys"

# Lock down permissions - ONLY System and Administrators can touch this file
$path = "C:\ProgramData\ssh\administrators_authorized_keys"
$acl = Get-Acl $path
$acl.SetAccessRuleProtection($true, $false)  # Remove inherited permissions
$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) }  # Clear all existing rules
$admins = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl","Allow")
$system = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM","FullControl","Allow")
$acl.AddAccessRule($admins)
$acl.AddAccessRule($system)
Set-Acl $path $acl

🔑 WHY PERMISSIONS MATTER: The sshd service runs as LOCAL SYSTEM. If the SYSTEM account can't read the key file, the service can't verify your key, so it falls back to a password. If ANY other user (like "Everyone") has access, SSH considers the file "compromised" and ignores it entirely.

Checklist:

  • File exists at C:\ProgramData\ssh\administrators_authorized_keys
  • Running icacls "C:\ProgramData\ssh\administrators_authorized_keys" shows ONLY NT AUTHORITY\SYSTEM and BUILTIN\Administrators

Step 4: Paste Your Public Key into the File

notepad "C:\ProgramData\ssh\administrators_authorized_keys"
  • Paste the public key you copied from the Client (the ssh-ed25519 AAAAC3... string)
  • Save and close Notepad

Verify it's correct:

cat "C:\ProgramData\ssh\administrators_authorized_keys"

Checklist:

  • The output starts with ssh-ed25519
  • The output is a single line (no line breaks in the middle of the key)
  • The fingerprint matches what cat ~/.ssh/id_ed25519.pub shows on the Client

Step 5: Configure sshd_config

notepad "C:\ProgramData\ssh\sshd_config"

Settings to CHECK and CHANGE:

🔑 HOW sshd_config WORKS:

  • Lines starting with # are comments (ignored by SSH)
  • Settings are read top-to-bottom
  • The Match Group block at the bottom overrides everything above it for users in that group

Find and set these lines (remove the # if present):

Line to find Change to Why
#PubkeyAuthentication yes PubkeyAuthentication yes Enables key-based login. Commented = relies on default, which can be unreliable on Windows.
AuthorizedKeysFile .ssh/authorized_keys #AuthorizedKeysFile .ssh/authorized_keys Comment this OUT. For admin accounts, the Match Group block at the bottom handles this. Leaving it active can cause confusion.
#PasswordAuthentication yes PasswordAuthentication yes Keep this ON as a backup until keys work. Once confirmed, you can set to no to disable password login entirely.

At the very BOTTOM of the file, ensure these lines exist and are NOT commented:

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

⚠️ THE OVERRIDE RULE: Once Match Group administrators is active, the SSH server says: "For any user in the Administrators group, ignore ALL other AuthorizedKeysFile settings and ONLY look at __PROGRAMDATA__/ssh/administrators_authorized_keys."

This means:

  • ✅ Key in C:\ProgramData\ssh\administrators_authorized_keys → Works
  • ❌ Key in C:\Users\hp\.ssh\authorized_keys → Completely ignored
  • ❌ Key in C:\Users\hp\.ssh\administrators_authorized_keys → Wrong location, wrong filename for this folder

Your final sshd_config should look like this (showing only the changed/important lines):

PubkeyAuthentication yes

#AuthorizedKeysFile     .ssh/authorized_keys

PasswordAuthentication yes

Subsystem       sftp    sftp-server.exe

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

Save and close.


Step 6: Restart the SSH Service

Restart-Service sshd

The Host is now ready.


Part 3: Connect from the Client

Basic Connection

ssh hp@100.103.129.41

Replace hp with the username from whoami and the IP with your Host's IP (Tailscale IP, LAN IP, etc).

If it works, you'll see something like:

Microsoft Windows [Version 10.0.26200.8037]
(c) Microsoft Corporation. All rights reserved.

hp@LAPTOP-4Q6FRMSD C:\Users\HP>

No password prompt = success! 🎉


Set Up an Alias (So You Don't Have to Remember the IP)

On your Client, create/edit this file:

notepad ~/.ssh/config

Paste this:

Host remote-pc
    HostName 100.103.129.41
    User hp
    IdentityFile ~/.ssh/id_ed25519

Now you can connect with just:

ssh remote-pc

Troubleshooting Checklist

If you get "Permission denied" after following everything above, work through this list:

1. Verify the Key Match

On Client:

cat ~/.ssh/id_ed25519.pub

On Host:

cat C:\ProgramData\ssh\administrators_authorized_keys
  • Both outputs are identical (same key string, same fingerprint)
  • You haven't run ssh-keygen again since pasting the key

2. Verify the Username

On Host:

whoami
  • You are using the name after \ in your ssh command (e.g., hp, not Avitesh)

3. Verify File Permissions

On Host (Admin PowerShell):

icacls "C:\ProgramData\ssh\administrators_authorized_keys"
  • Shows ONLY NT AUTHORITY\SYSTEM:(F) and BUILTIN\Administrators:(F)
  • Does NOT show Everyone, Users, or any individual username

If permissions are wrong, fix with:

icacls "C:\ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "NT AUTHORITY\SYSTEM:(F)" /grant "BUILTIN\Administrators:(F)"

4. Verify sshd_config

On Host:

cat C:\ProgramData\ssh\sshd_config | Select-String -Pattern "PubkeyAuthentication|AuthorizedKeysFile|Match Group|PasswordAuthentication" | Where-Object { $_.Line -notmatch "^#" }
  • PubkeyAuthentication yes appears
  • Match Group administrators appears
  • AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys appears (indented under Match Group)

5. Use Verbose Mode to Diagnose

On Client:

ssh -v hp@100.103.129.41

Look for these lines in the output:

Line you see What it means
Offering public key: ... ED25519 SHA256:xxx ✅ Client is sending your key
Server accepts key ✅ Host recognized the key - you're in!
Authentications that can continue: password (after offering key) ❌ Host rejected the key - check permissions & file content

6. Check Server-Side Logs

On Host: Open Event Viewer → Applications and Services Logs → OpenSSH → Operational

Look for errors at the exact time you attempted to connect. Common messages:

  • "Authentication refused: bad ownership or modes" → Fix permissions (Step 3)
  • "Could not open authorized keys" → File doesn't exist or wrong path
  • "User not found" → Wrong username

Quick Reference Card

Item Admin User Standard User
Key file location on Host C:\ProgramData\ssh\administrators_authorized_keys C:\Users\USERNAME\.ssh\authorized_keys
Match Group administrators in config Uncommented (active) Commented out with #
Permissions on key file SYSTEM + Administrators only SYSTEM + that specific user only
Connect command ssh hp@IP ssh username@IP

Common Pitfalls Summary

Pitfall Why It Happens How to Avoid
Wrong username Display name ≠ account name Always run whoami on Host first
Key mismatch after regeneration ssh-keygen overwrites old key Update the Host's key file every time you regenerate
Key in wrong file/folder Admin accounts ignore user folders Admin → ProgramData; Standard → User folder
Loose permissions Any extra user = SSH ignores the file Strip inheritance, allow only SYSTEM + Admins
PubkeyAuthentication commented out Default should be yes, but Windows is inconsistent Always explicitly uncomment it
AuthorizedKeysFile conflict Top-level setting fights with Match Group block Comment out the top-level one for admin accounts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment