OpenSSH on Windows Server 2022

Windows Server 2022 ships with OpenSSH as an optional built-in feature, eliminating the need for third-party SSH servers like Bitvise or freeSSHd. The OpenSSH Server implementation is maintained by Microsoft and based on the open-source OpenSSH project, with Windows-specific adaptations. It provides a standards-compliant SSH server that supports key-based authentication, SFTP, port forwarding, and custom default shells. For administrators accustomed to managing Linux servers over SSH, OpenSSH on Windows Server 2022 significantly reduces the cognitive overhead of managing mixed environments — the same SSH client, keys, and tooling work regardless of the target OS.

OpenSSH on Windows Server 2022 is particularly valuable for Ansible automation (using the ansible_connection: ssh plugin), for developers connecting to Windows development servers, for secure file transfers via SFTP, and as an alternative to WinRM in environments where SSH is the established standard. The OpenSSH Server runs as a Windows service (sshd) and listens on TCP port 22 by default.

Installing OpenSSH Server

On Windows Server 2022, OpenSSH Server is an optional Windows capability. Check whether it is already installed:

Get-WindowsCapability -Online | Where-Object Name -like "OpenSSH*"

The output shows two capabilities: OpenSSH.Client and OpenSSH.Server. Install the server component:

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

The tilde-separated version suffix (~~~~0.0.1.0) is required for this capability. If you are in a disconnected environment without Windows Update access, use DISM with a mounted Windows Server 2022 ISO as the source:

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 -Source D:sourcessxs

After installation, verify both components are present:

Get-WindowsCapability -Online | Where-Object Name -like "OpenSSH*" | Select-Object Name, State

Both should show State: Installed.

Starting and Configuring the sshd Service

After installation, the sshd service exists but is not started or set to automatic. Configure it to start automatically and start it immediately:

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

Verify the service is running:

Get-Service sshd | Select-Object Name, Status, StartType

The ssh-agent service (for key management) is also installed. Enable it if you plan to use SSH key forwarding or Pageant-style key storage:

Start-Service ssh-agent
Set-Service -Name ssh-agent -StartupType Automatic

Configuring the Windows Firewall Rule for Port 22

The installation process creates a firewall rule automatically, but verify it is configured correctly:

Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" | Select-Object Name, Enabled, Direction, Action, LocalPort

If the rule was not created (for example, if the firewall service was offline during installation), create it manually:

New-NetFirewallRule `
    -Name "OpenSSH-Server-In-TCP" `
    -DisplayName "OpenSSH Server (sshd)" `
    -Enabled True `
    -Direction Inbound `
    -Protocol TCP `
    -Action Allow `
    -LocalPort 22

For tighter security, restrict inbound SSH to specific source IPs or subnets:

Set-NetFirewallRule `
    -Name "OpenSSH-Server-In-TCP" `
    -RemoteAddress 10.0.0.0/8, 192.168.1.0/24

The sshd_config File

The OpenSSH server configuration file on Windows is located at C:ProgramDatasshsshd_config. This directory and its files are created during installation. The sshd_config syntax is identical to OpenSSH on Linux, making it familiar to Unix administrators. To edit it, open an elevated PowerShell session:

notepad C:ProgramDatasshsshd_config

Or use PowerShell to modify specific directives programmatically. Key settings to review and configure:

# Disable password authentication (after setting up keys)
(Get-Content C:ProgramDatasshsshd_config) -replace '#PasswordAuthentication yes','PasswordAuthentication no' | Set-Content C:ProgramDatasshsshd_config

# Allow only specific users
Add-Content C:ProgramDatasshsshd_config "`nAllowUsers Administrator ansible-svc deploy-user"

# Change the listening port (optional)
(Get-Content C:ProgramDatasshsshd_config) -replace '#Port 22','Port 2222' | Set-Content C:ProgramDatasshsshd_config

After modifying sshd_config, always restart the sshd service for changes to take effect:

Restart-Service sshd

Configuring Key-Based Authentication

Key-based authentication is more secure than password authentication and is required for automation. On Windows Server 2022, the authorized_keys file location depends on the user:

For standard users, the authorized_keys file is at: C:Users<username>.sshauthorized_keys

For the Administrator account (and members of the Administrators group), the sshd_config default redirects to a centralized location: C:ProgramDatasshadministrators_authorized_keys

This is configured in sshd_config via the Match Group directive. Check these lines in sshd_config:

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

To set up key-based auth for the Administrator account, create the file and set correct ACLs:

# Create the authorized_keys file
$adminKeysPath = "C:ProgramDatasshadministrators_authorized_keys"
New-Item -ItemType File -Path $adminKeysPath -Force

# Add your public key
Add-Content $adminKeysPath "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@controlnode"

# Fix ACLs — only SYSTEM and Administrators should have access, not regular users
icacls $adminKeysPath /inheritance:r
icacls $adminKeysPath /grant "SYSTEM:F"
icacls $adminKeysPath /grant "BUILTINAdministrators:F"

For a non-admin user, place the key in their profile directory:

$userKeysPath = "C:Usersdeployuser.sshauthorized_keys"
New-Item -ItemType Directory -Path "C:Usersdeployuser.ssh" -Force
New-Item -ItemType File -Path $userKeysPath -Force
Add-Content $userKeysPath "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... deploy@controlnode"

icacls $userKeysPath /inheritance:r
icacls $userKeysPath /grant "SYSTEM:F"
icacls $userKeysPath /grant "deployuser:F"

Setting the Default Shell to PowerShell

By default, OpenSSH on Windows uses cmd.exe as the shell. For PowerShell 7 (recommended) or Windows PowerShell 5.1, configure the default shell via the registry:

# Set PowerShell 7 as the default shell
New-ItemProperty -Path "HKLM:SOFTWAREOpenSSH" `
    -Name DefaultShell `
    -Value "C:Program FilesPowerShell7pwsh.exe" `
    -PropertyType String `
    -Force

# Set the default shell arguments (optional)
New-ItemProperty -Path "HKLM:SOFTWAREOpenSSH" `
    -Name DefaultShellCommandOption `
    -Value "/c" `
    -PropertyType String `
    -Force

For Windows PowerShell 5.1:

New-ItemProperty -Path "HKLM:SOFTWAREOpenSSH" `
    -Name DefaultShell `
    -Value "C:WindowsSystem32WindowsPowerShellv1.0powershell.exe" `
    -PropertyType String `
    -Force

SFTP Configuration and the SSH Subsystem

The SFTP subsystem is enabled by default in Windows OpenSSH. The sftp-server binary is located at C:WindowsSystem32OpenSSHsftp-server.exe and is referenced in sshd_config:

Subsystem sftp sftp-server.exe

No additional configuration is needed to use SFTP. Connect from any SFTP client:

sftp [email protected]

Or use PowerShell 7’s built-in scp support to transfer files to Windows Server 2022:

scp -i ~/.ssh/id_ed25519 /local/path/file.zip [email protected]:"C:/Installers/file.zip"

Configuring a Login Banner (MOTD)

Display a legal warning or informational banner before authentication using the Banner directive in sshd_config:

# Create the banner file
Set-Content "C:ProgramDatasshbanner.txt" @"
**********************************************************************
WARNING: This system is restricted to authorized users only.
All activity is monitored and logged. Unauthorized access is prohibited.
**********************************************************************
"@

# Add to sshd_config
Add-Content C:ProgramDatasshsshd_config "`nBanner C:ProgramDatasshbanner.txt"
Restart-Service sshd

Testing SSH Login and Using OpenSSH with Ansible

Test the SSH connection from your control node or another machine:

ssh -i ~/.ssh/id_ed25519 -v [email protected]

The -v flag shows verbose connection details including authentication method negotiation and key exchange. For Ansible, configure the inventory to use SSH instead of WinRM:

[windows]
winserver2022.contoso.com

[windows:vars]
ansible_connection=ssh
ansible_shell_type=powershell
ansible_user=administrator
ansible_ssh_private_key_file=~/.ssh/id_ed25519
ansible_become=false

Test Ansible connectivity using win_ping over SSH:

ansible windows -i inventory.ini -m win_ping

SSH-based Ansible on Windows Server 2022 eliminates the need for WinRM configuration and the pywinrm Python library, simplifying the automation stack considerably — especially in environments with existing SSH infrastructure and PKI.