Last Updated: June 23, 2025
Authorship: This guide was developed in a collaborative session between a user and Google's Gemini assistant.
This guide details a robust method to configure the Windows OpenSSH Server to provide users with a direct and seamless WSL/Linux shell.
The primary benefit of this configuration over simply launching bash.exe
from a default CMD/DOS shell is that it provides a native Linux environment for all SSH protocols. This allows tools like scp
, sftp
, and git
to work correctly with Linux-style paths (e.g., ~/file.txt
or /etc/profile
) right out of the box, which is not possible when operating through a conventional Windows shell.
- A modern Windows machine (Windows 10/11 or Server 2019/2022).
- WSL installed with at least one Linux distribution (e.g., Ubuntu).
- OpenSSH Server for Windows installed and running.
Note: OpenSSH Server can be installed via Settings -> System -> Optional features -> Add a feature, and searching for "OpenSSH Server".
The core of this solution is a PowerShell "shim" script that intelligently directs ssh
and scp
requests. This script will be called by the OpenSSH service.
-
Create the file
%ProgramData%\ssh\wsl_shim.ps1
. -
Paste the following code into the file. This script is designed to be generic; it receives the target WSL username as a parameter from the
sshd_config
file. For security, it will fail the connection if this parameter is not provided.# # Filename: wsl_shim.ps1 # Author: FNGarvin # License: MIT # A generic shim to route OpenSSH requests to the appropriate WSL user shell. # It accepts a '-WslUser' parameter to specify the target user within WSL. # param ( # Define a string parameter named WslUser. Default to an empty string. [string]$WslUser ) # Check if the -WslUser parameter was provided and is not an empty string. if (-not $WslUser) { # If not, write an error and exit with a non-zero code. # sshd will see the failure and terminate the client connection. # This is a "fail-fast" approach to prevent misconfiguration. Write-Error "FATAL: The -WslUser parameter was not provided in the sshd_config ForceCommand. Aborting for security." exit 1 } # If validation passes, set the username from the parameter. $wsl_username = $WslUser # Check the SSH_ORIGINAL_COMMAND environment variable set by sshd. # This is the reliable way to detect non-interactive sessions (scp, sftp, etc.). if ($env:SSH_ORIGINAL_COMMAND) { # If the variable exists, execute its contents in a bash shell as the specified WSL user. & wsl.exe -u $wsl_username -- /bin/bash -c "$($env:SSH_ORIGINAL_COMMAND)" } else { # If the variable is not set, it's an interactive session. Start a login shell. & wsl.exe -u $wsl_username --exec /bin/bash --login } #END OF wsl_shim.ps1
-
Secure the Shim File. In an Administrator PowerShell window, run the following commands to harden the script's permissions. This is a critical security step.
# Reset permissions, removing rights for standard users. icacls "$env:ProgramData\ssh\wsl_shim.ps1" /inheritance:r # Grant only necessary permissions: SYSTEM (Read/Execute), Administrators (Full). icacls "$env:ProgramData\ssh\wsl_shim.ps1" /grant "SYSTEM:(RX)" /grant "BUILTIN\Administrators:(F)"
Open your sshd_config
file (located at %ProgramData%\ssh\sshd_config
) as an Administrator. Go to the very end of the file and paste the following consolidated block of code. This block contains all necessary changes and is clearly marked for easy identification.
# === CUSTOM WSL CONFIGURATION START ===
# This block contains all custom settings for enabling WSL-based SSH sessions.
# Global settings overrides. These will take precedence over any defaults set earlier in the file.
PubkeyAuthentication yes
PasswordAuthentication no
# --- Authentication and ForceCommand Rules ---
# Block 1: Define the authentication method for all administrators.
# It specifies a central authorized_keys file on the Windows filesystem.
Match Group administrators
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
# Block 2: For a specific Windows user, force their connection through the shim.
# This passes the target WSL username as a parameter to the script.
Match User YOUR_WINDOWS_USERNAME
ForceCommand powershell.exe -ExecutionPolicy Bypass -File %PROGRAMDATA%\ssh\wsl_shim.ps1 -WslUser "your_wsl_username"
# To add more users, copy the 'Match User' block for each additional user.
# Match User Another_Windows_User
# ForceCommand powershell.exe -ExecutionPolicy Bypass -File %PROGRAMDATA%\ssh\wsl_shim.ps1 -WslUser "another_wsl_username"
# === CUSTOM WSL CONFIGURATION END ===
This architecture uses a single, central file on the Windows host to manage SSH keys, which is simpler and more secure than managing keys inside each user's WSL home directory.
-
Ensure the file exists at
%ProgramData%\ssh\administrators_authorized_keys
. -
Set Permissions: For security, this file should only be writable by Administrators. Open an Administrator PowerShell and run:
# Create an empty file first if it doesn't exist New-Item -Path "$env:ProgramData\ssh\administrators_authorized_keys" -ItemType File -Force # Get the Access Control List (ACL) of the parent ssh folder $acl = Get-Acl "$env:ProgramData\ssh" # Apply that same restrictive ACL to our new keys file Set-Acl -Path "$env:ProgramData\ssh\administrators_authorized_keys" -AclObject $acl
-
Add User Public Keys: Open this file in a text editor. Paste the public key (the content of the user's
id_ed25519.pub
file) for each user who needs access, one key per line.
To apply all changes, restart the OpenSSH service in an Administrator PowerShell window:
Restart-Service sshd
Your configuration is now complete. Users can connect with ssh YOUR_WINDOWS_USERNAME@SERVER
to get a WSL prompt, and scp
and sftp
will work correctly against their specified WSL home directory.
- Multi-User Support: The provided configuration is already designed for multiple users. Simply add a new
Match User Another_Windows_User
block to yoursshd_config
for each additional user, specifying their target WSL username in the-WslUser
parameter. - Mismatched Usernames: This guide's design explicitly supports mismatched usernames. The
Match User YOUR_WINDOWS_USERNAME
directive identifies the connecting Windows account, while the-WslUser "your_wsl_username"
parameter directs them to the correct, possibly different, username inside WSL. - Targeting a Specific WSL Distribution: If you have multiple WSL distributions (e.g., Ubuntu-20.04 and Debian) and need to target a non-default one, you can add the
-d <DistroName>
flag to thewsl.exe
commands inside thewsl_shim.ps1
script.- Example:
& wsl.exe -d Debian -u $wsl_username -- /bin/bash -c ...
- Example:
- Security Disclaimer: This guide provides a functional configuration based on collaborative development with an AI (Gemini). System administrators are responsible for understanding each component and securing their systems in accordance with their organization's security policies. This configuration should be reviewed and adapted to your specific requirements.