First, the most likely reason for it failing is as Ramhound mentioned in the comments -- Key permissions. You just mentioned copying over the private key from Windows to
~/.ssh/authorized_keys
, but you didn't mention changing the permissions. Try:chmod 600 ~/.ssh/authorized_keys
Hopefully, that will work, but if it doesn't, try:
sudo service ssh stop sudo mkdir /run/sshd sudo chmod 0755 /run/sshd sudo /usr/sbin/sshd -d
That will run
sshd
in the foreground with additional debugging. Hopefully that will tell you why the key is being denied.
Preferred Method of Enabling SSH into WSL2
The page you linked to in your question is the one that says:
DO NOT DO THE INSTRUCTIONS IN THIS POST until you have read the FOLLOW UP THE EASY WAY how to SSH into Bash and WSL2 on Windows 10 from an external machine and made the right decision for YOU!
So I'd be curious why you selected the older, port-forwarding method over the alternative that he proposes for setting the Windows OpenSSH shell to the bash.exe
(outdated info, but still works) command.
Regardless, I (and others) feel there's a much better alternative to either of Hanselman's techniques.
Advantages of this method:
- No port forwarding required
- Minimal firewall work needed since it relies on Windows services
- Works even if you have multiple WSL distributions installed
- Works with
sshfs
,scp
,sftp
, Ansible, and any app or service that requires a real SSH connection.
The summary is that:
- We rely on WSL2's ability to forward "localhost" connections on Windows to WSL (a.k.a. localhost forwarding).
- We use Windows OpenSSH server as a JumpHost to the WSL2 OpenSSH server.
The initial setup for this is the same as for Hanselman's "easy method". Start by enabling the Windows OpenSSH server on port 22.
As before(Especially for future readers) I recommend simply following the Microsoft docs for the latest information, saving this postbut I'm copying the relevant commands in here so thatas well. From PowerShell:
# Sounds like you had the Client already installed, at least Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 Start-Service sshd Set-Service -Name sshd -StartupType 'Automatic' # Confirm the Firewall rule is configured. It should be created automatically by setup. Run the following to verify if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) { Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..." New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 } else { Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists." }
Recommended if you haveare an Administrator on your Windows install -- Edit
C:\Program Data\ssh\sshd_config
and comment out the following lines:#Match Group administrators # AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
While you are editing that information while, I continueassume you will want to write up the alternative methodset:
PasswordAuthentication no
By default, Windows OpenSSH looks for enabling ssh
C:\Program Data\ssh\administrators_authorized_keys
(see this question). By commenting these lines out, you will use your%userprofile%\.ssh\authorized_keys
instead.Add your public key to
%userprofile%\.ssh\authorized_keys
. Make sure that permissions are restrictive per this answer (or related answers).Confirm that you can log to Windows OpenSSH from WSL using your key:
ssh -i <path_to_private_key> "${HOSTNAME}.local"
At this point, you really have terminal access to WSL2 through Windows OpenSSH already.
From any machine on the network:
ssh -t <windows_host_or_ip> wsl
This will simply run the wsl
command after the connection to Windows.
That works for shell access, but if you need "real" ssh access to WSL for Andible, sshfs, sftp, scp, etc., then read on ...
Next (for anyone else reading this) configure OpenSSH in WSL. You've done this part already. And port 2222
is a good option.
Copy over your public key to ~/.ssh/authorized_keys
(already done for you) and make sure your permissions are correct (as mentioned above).
If you haven't already, add your private key to ssh-agent
via:
eval $(ssh-agent) # under Linux
ssh-add <path_to_key
(Note: Windows also supports ssh-add
. Just make sure the "OpenSSH Authentication Service" is running).
At this point, you can use the Windows host as your JumpHost like so:
ssh -J <windows_host_or_ip> -p 2222 localhost
This connects to the Windows OpenSSH server (on port 22) which then turns around and connects to localhost:2222
, which is your WSL2 instance.
As mentioned, this will now work for scp
, sshfs
, etc.
Optionally:
This technique has one "side-effect", in that localhost
is stored as the same "known host" regardless of which port or jump host you use to connect. So if you do connect to multiple WSL instances in this way, ssh
will start complaining about potential man-in-the-middle issues.
The best way to avoid this (and simplify things in general) is to create a Host
entry in ~/.ssh/config
. Let's say your Windows host name is bubblegum
and your WSL distro is ubuntu
. Add the following to ~/.ssh/config
:
Host bubblegum_ubuntu # Can be whatever you want
Hostname localhost
User <username> # If needed
Port 2222
ProxyJump bubblegum
UserKnownHostsFile ~/.ssh/known_hosts_bubblegum_ubuntu
That will redirect the known_host
entry to a file that is only used for that particular host.
It also means that you can now:
ssh bubblegum_ubuntu
scp bubblegum_ubuntu:/home/username/filename .
sftp bubblegum_ubuntu
sshfs bubblegum_ubuntu:/ /mountpoint