Skip to content

Instantly share code, notes, and snippets.

@vanakema
Last active September 2, 2022 16:56
Show Gist options
  • Save vanakema/a09f89cbbc01f7446e68c728bdd1df10 to your computer and use it in GitHub Desktop.
Save vanakema/a09f89cbbc01f7446e68c728bdd1df10 to your computer and use it in GitHub Desktop.
Setting up an ssh tunnel into WSL2 Ubuntu

Setting up an ssh tunnel into your WSL2 Ubuntu instance

I am writing this up in order to have it documented how I got an SSH tunnel into my WSL2 Ubuntu environment, as I kept having issues along the way. So I wanted to document things more clearly for myself in the future, and I hope this helps someone else along the way

I started with this guide

This is going to be a story

First issue I ran into is that wsl hostname -I command in the sshd.bat didn't work due to -I not being an option in the default WSL2 distro (the one that WSL launches into if you don't install any other distros). I ran wsl hostname --help and learned there was a -i, so I changed it to that, since that does spit out an IP. It just turns out that's not the IP you want. This was my point of failure.

I kept running into a kex_exchange_identification: Connection closed by remote host error. After some hours of debugging, I realized the ip address spit out by hostname -i did not match what ifconfig spit out, so I then searched for a function that would spit out the ip address I expected, and then learned that hostname -I indeed exists in Ubuntu, and the reason I was having issues was that the WSL2 default distro was set to whatever the underlying default distro you get upon first installing WSL2 is.

I fixed this by running wsl --set-default ubuntu. Once I did this, it made it so the original sshd.bat script provided in that guide worked.

Alternatively, if you want to not have to set your default distro to the one you're trying to ssh into, you can add --distribution <distro_of_choice> to your wsl commands, and it should work

End of the story

Below I will document the steps outlined in the article for sake of posterity in case Julio Merino's blog goes down for whatever reason, as well as add steps that would've helped me to do so from a clean installation. I want to be clear, almost all the credit to the following steps goes to Julio Merino:

  1. Install WSL2 following these steps
  2. Install distro of choice from the Microsoft store (I used Ubuntu, so the rest of the guide will reflect that, but should largely be transferrable to other distros)
  3. Set default distro to Ubuntu (or your choice)
wsl --set-default ubuntu
  1. Install OpenSSH server (I think this was already installed in my ubuntu distro however)
sudo apt install openssh-server
  1. Configure OpenSSH to listen on port 2022 (not necessary, but can be useful if you want to support sshing into your Windows box too)
sudo sed -i -E 's,^#?Port.*$,Port 2022,' /etc/ssh/sshd_config
sudo service ssh restart
  1. Allow the default WSL user to start SSH without a password (due to services having to have sudo permission)
sudo sh -c "echo '${USER} ALL=(root) NOPASSWD: /usr/sbin/service ssh start' >/etc/sudoers.d/service-ssh-start"
  1. Confirm passwordless sudo is enabled for starting sshd
sudo /usr/sbin/service ssh start
  1. Copy the provided sshd.bat file into your Windows home directory
  2. Copy the task.xml somewhere easily accessible
  3. Open Task Scheduler from Start menu
  4. Click Import Task, and choose the task.xml file
  5. Under the General tab, click Change User or Group..., and provide your username in the field that takes in a username that pops up
  6. Under the Triggers tab, confirm that it says At startup under the trigger column, and that it is enabled
  7. Under the Actions tab, edit the Start a program action to point to the sshd.bat script in your Windows home directory (instead of pointing to jmmv)
  8. Click OK
  9. Punch a hole in the firewall by running this in Powershell
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd) for WSL' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 2022

You should be good to go at this point

@echo off
setlocal
wsl --distribution ubuntu -- sudo /usr/sbin/service ssh start
C:\Windows\System32\netsh.exe interface portproxy delete v4tov4 listenport=2022 listenaddress=0.0.0.0 protocol=tcp
for /f %%i in ('wsl --distribution ubuntu -- hostname -I') do set IP=%%i
C:\Windows\System32\netsh.exe interface portproxy add v4tov4 listenport=2022 listenaddress=0.0.0.0 connectport=2022 connectaddress=%IP%
endlocal
@echo off
setlocal
C:\Windows\System32\bash.exe -c "sudo /usr/sbin/service ssh start"
C:\Windows\System32\netsh.exe interface portproxy delete v4tov4 listenport=2022 listenaddress=0.0.0.0 protocol=tcp
for /f %%i in ('wsl hostname -I') do set IP=%%i
C:\Windows\System32\netsh.exe interface portproxy add v4tov4 listenport=2022 listenaddress=0.0.0.0 connectport=2022 connectaddress=%IP%
endlocal
# Figured I'd add my sshd_config just to make it easier for myself in the future
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
Port 2022
#AddressFamily any
ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
# PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
KbdInteractiveAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the KbdInteractiveAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via KbdInteractiveAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2021-12-05T16:32:19.159532</Date>
<Author>CHERRY\jmmv</Author>
<URI>\Start WSL SSH</URI>
</RegistrationInfo>
<Triggers>
<BootTrigger>
<Enabled>true</Enabled>
<Delay>PT30S</Delay>
</BootTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>S-0-0-00-0000000000-0000000000-0000000000-0000</UserId>
<LogonType>Password</LogonType>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>C:\Users\youruser\sshd.bat</Command>
</Exec>
</Actions>
</Task>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment