80

After installing Ubuntu as WSL (Windows Subsystem for Linux), I've run (as root):

cd ~
python3 -m http.server

Output:

Serving HTTP on 0.0.0.0 port 8000 ...

And I tried to access to this web server from my windows machine, http://0.0.0.0:8000 or http://192.168.1.178:8000, but without any success. The web server is available only by the address http://127.0.0.1:8000 or http://localhost:8000. It means that I can't connect to this web server from another PC in my network. Is it possible to get access to WSL from the outside?

3
  • 3
    Maybe this can help you. Commented May 1, 2018 at 20:51
  • Thanks for help but server still available through the localhost only. And no ability to connect from another PC to this server.
    – Roman
    Commented Jul 14, 2018 at 8:47
  • This was actually helpful for working on a single machine :)
    – Mircea
    Commented Sep 11, 2023 at 18:56

14 Answers 14

45

In your VM, execute ifconfig.

You will see your IP address in the first section (eth0:) inet x.x.x.x

This x.x.x.x is the IP address you have to put in your browser.

2
39

None of the existing answers work for me, as WSL2 is running in its own VM and has its own network adapter. You need some sort of bridge or port forwarding for non-localhost requests to work (i.e. from another host on the same network).

I found a script in https://github.com/microsoft/WSL/issues/4150 that worked to resolve the issue:

$remoteport = bash.exe -c "ifconfig eth0 | grep 'inet '"
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( $found ){
  $remoteport = $matches[0];
} else{
  echo "The Script Exited, the ip address of WSL 2 cannot be found";
  exit;
}

#[Ports]

#All the ports you want to forward separated by coma
$ports=@(80,443,10000,3000,5000);


#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";


#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";

#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP";

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}

Running this script from an elevated/admin Powershell session did the trick for me. This allows accessing the WSL2 service running on a port to be accessible from the Windows host IP at that same port.

6
  • 4
    Worked really well for me -- make sure you have ifconfig installed on your WSL2 distro. This can also be added to Task Scheduler on login as powershell -executionpolicy bypass -f path\to\script.ps1 with a delay of at least 10 seeconds to allow WSL2 to launch first (making your Linux instance available to fetch the machine's IP from). Commented Jul 18, 2021 at 20:51
  • It does not help :( Do I need to restart my computer after that or anything?
    – Alexey
    Commented Mar 3, 2022 at 11:51
  • 1
    @Alexey This worked for me after restarting WSL: wsl --shutdown
    – GinoF
    Commented May 25, 2023 at 15:50
  • Here's a version of the script with better error handling and fixes some old mistakes of the author of the script.
    – Seangle
    Commented Feb 25 at 21:21
  • 2
    @Seangle author here. Glad to see the solution still being used! Commented Feb 28 at 14:31
15

Please follow the steps mentioned in the link shared by erazerbrecht and run your HTTP server by providing your IP address (instead of using localhost) and port number.

Example (as root):

cd ~
python3 -m http.server -b 192.168.1.178 8000

Output:

Serving HTTP on 192.168.1.178 port 8000 (http://192.168.1.178 :8000/) ...

Otherwise, you can also do this instead of following the link:

  1. Go to the Windows Defender firewall → Advanced settings from the left menu
  2. Select Inbound
  3. Create New rule; Next
  4. Select Program as a rule type; Next
  5. Select All Program; Next
  6. Select Allow the connection; Next
  7. Check all three (Domain, Private, and Public); Next
  8. Provide the rule with a name
  9. Press Finish
  10. You’re are good to go
7
  • 1
    These are the instructions Microsoft provides. Windows firewall is blocking connections exposed by WSL.
    – Drew
    Commented May 29, 2019 at 19:16
  • 1
    It does work. Ensure you replace IP with your local windows IP. Also while accessing the webpage use IP:PORT to access.
    – Guru
    Commented Jul 29, 2019 at 19:01
  • I can confirm that following all of these instructions does not work. For me viewing my IP at port 8000 shows the document tree of the Windows user profile directory in the browser. The Linux HTTP server does see and log the request however.
    – Sienile
    Commented Oct 17, 2019 at 21:30
  • 1
    Neither suggestion in this answer worked for me on WSL2. Service can't bind to the Windows IP address because WSL2 has its own network adapter. Same for the firewall. The ports were already working when running the service in Windows, so no use allowing them again.
    – mlibby
    Commented Mar 31, 2021 at 14:58
  • @mlibby Have you found the solution? 😐
    – JohnyL
    Commented Apr 3, 2021 at 20:42
11

it means that I can't connect to this web server from another pc in my network. Is it possible to getting an access to WSL from outside?

It should be noted, among all the answers here, that this question was originally for WSL1 (given when it was asked) and was self-answered by the OP as having been a WSL or Windows issue that was resolved by a Windows update.

Ironically, this is a known issue on WSL2 due to the way its networking typically worked (NAT), so years later, people started finding it (and answering it) in that context.

There are multiple solutions for this on WSL2. For historical purposes, I'll leave the two older solutions below, but the preferred and officially supported version is now the first listed:

WSL2 "Mirrored" Network Mode

As of the September 2023 WSL2 and Windows 11 updates, a new network mode setting is available - "Mirrored". When enabled, this mode will mirror the Windows network interfaces into Linux, enabling (according to the announcement):

  • IPv6 support
  • Connect to Windows servers from within Linux using the localhost address 127.0.0.1
  • Connect to WSL directly from your local area network (LAN)
  • Improved networking compatibility for VPNs
  • Multicast support

Huzzah!

To enable this mode:

  1. Edit the file .wslconfig located in your Windows user profile directory. This file does not exist by default. If you have any questions about making sure you have the correct file, use the following command from PowerShell (as your regular, non-elevated/Admin user):

    notepad ($env:USERPROFILE+"\.wslconfig")
    
  2. Ensure the following lines are present:

    [wsl2]
    networkingMode=mirrored
    

    Side-note: My understanding is that adding firewall=false should allow you to skip some of the next steps, but I've been unable to make that work, so perhaps my understanding is wrong. I'll update if I learn more. For now ...

  3. Exit all running WSL instances

  4. From an elevated, admin PowerShell, test that the WSL2 firewall is available:

    Get-NetFirewallHyperVVMCreator
    

    If this command returns an empty value, then you may be on an older, unsupported version of Windows, or your WSL needs to be updated (2.0.9.0 or higher is recommended (wsl --version)).

  5. Assuming you received a value from the previous command, then (still in the elevated, admin PowerShell) either:

    • Easiest (disables WSL2 firewall completely):

      Set-NetFirewallHyperVVMSetting -Name ((Get-NetFirewallHyperVVMCreator).VMCreatorId) -Enabled False
      
    • Safest (allows only traffic from Private networks):

      New-NetFirewallHyperVRule `
      -DisplayName 'Allow All Inbound Traffic to WSL in Private Network' `
      -Name 'WSL Private Inbound Rule' `
      -Profiles Private `
      -Direction Inbound `
      -Action Allow `
      -VMCreatorId ((Get-NetFirewallHyperVVMCreator).VMCreatorId) `
      -Enabled True
      

      Note: To delete this rule, run Remove-NetFirewallHyperVRule -Name 'WSL Private Inbound Rule'.

    ^ Credit to this Github user and comments

  6. Exit the Admin PowerShell session and return to your normal PowerShell:

    wsl --shutdown
    
  7. Restart your WSL instance and test using the original command from the question:

    python3 -m http.server
    

    From another device on the local network, you should now be able to access the service using:

    • IPv4 or IPv6: http://<ip_address>:8000
    • IPv6 mDNS on a broadcast local network: http://<windows_system_name>.local:8000
    • DNS name

Older solutions

  • WSL1: First, just use WSL1. For most (but not all) web development tasks where you need to access your app from another machine on the network, WSL1 will be better at networking and will run your application and tools just fine. WSL2 brings in real, virtualized Linux kernel, but the "fake kernel" (syscall translation layer) of WSL1 still works fine today for most tasks.

    When running python3 -m http.server under WSL1, you'll automatically be able to access it from other machines on the network via the Windows host's IP address (or DNS name). As the OP mentioned in the self-answer, that pesky WSL1 bug has been fixed for years now.


  • SSH reverse tunnel If you do need to use WSL2, here's an option that doesn't require port forwarding or any advanced firewall rules that need to be updated each time WSL restarts. The problem with those rules is that the IP address for WSL changes every time you restart, meaning those rules have to be deleted and recreated constantly.

    On the other hand, we can use SSH within WSL2 to connect to Windows, where the name, and perhaps even the IP address, is constant.

    One-time setup: Enable SSH

    There's some one-time setup for this, but it's useful regardless:

    First, install/enable Windows OpenSSH server. This is a feature that is built-in to Windows and just needs to be enabled. You'll find the full instructions here, but it's typically just a matter of (from an Admin PowerShell):

    Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
    Start-Service sshd
    Set-Service -Name sshd -StartupType 'Automatic'
    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."
    }
    

    Edit your C:\ProgramData\ssh\sshd_config and set GatewayPorts yes. This is what allows us to use SSH as a gateway from other devices on the network.

    Finally, of course, you'll need a firewall rule in Windows allowing the HTTP(s) (or other) port you'll be using. Example (from Admin PowerShell):

    New-NetFirewallRule -DisplayName "WSL Python 8000" -LocalPort 8000 -Action Allow -Protocol TCP
    

    And restart the OpenSSH Server service:

    Restart-Service sshd
    

    Create the tunnel

    With that in place, it's a simple matter to create the tunnel we need:

    ssh -R 8000:localhost:8000 NotTheDr01ds@$(hostname).local
    

    Replacing, of course, NotTheDr01ds with your own Windows username, if it differs from the WSL username

    That's going to use your Windows username and password since SSH is running on the Windows side.

    Once you have ensured that it works, two other recommendations:

    • Set up key-based authentication so that you don't need to enter a password each time
    • Change the SSH connection to:
      ssh -fN -R 8000:localhost:8000 NotTheDr01ds@$(hostname).local
      
      That will put the SSH session into the background and not allocate a terminal for it.
6
  • Would it be a better idea to use "GatewayPorts clientspecified" instead of "GatewayPorts yes"?
    – solamour
    Commented Jun 15, 2023 at 22:22
  • @solamour Good catch -- Probably. I haven't tested it thoroughly with that configuration, but I don't see any issues with it at first glance. Working well for you, I assume? Commented Jun 15, 2023 at 23:06
  • In this particular case, "GatewayPorts clientspecified" and "GatewayPorts yes" shouldn't make much difference. Anyhow "SSH reverse tunneling" (ssh from WSL2 to Windows) does work, although I ended up using a plain tunneling (ssh from Windows to WSL2), just to make things simpler on Windows. Thanks for the excellent tip.
    – solamour
    Commented Jun 16, 2023 at 6:00
  • @solamour Right - Now that WSL2 attempts to re-use the same IP address each time, it's easier to go the Windows->WSL route. I should probably edit that in based on the more recent release since I originally wrote it up. Commented Jun 16, 2023 at 10:54
  • 1
    @solamour Right - It used to get a different IP each time, which is why I came up with this reverse tunnel technique. However, about 6 months or so ago, the WSL team added a feature to have it attempt to use the same IP each time. With that in place, the "normal tunnel" that you use is now easier than the reverse tunnel that I recommended. Commented Jun 16, 2023 at 17:06
8

Avoid using firewall rules used in some answers on the web. I saw some of them create some kind of allow-all firewall rule (allow any traffic from any IP address and any port). This can cause security problems.

Simply use this single line from this answer which worked perfectly for me (it just creates a port proxy):

netsh interface portproxy add v4tov4 listenport=<windows_port> listenaddress=0.0.0.0 connectport=<WSL_port> connectaddress=<WSL_IP>

where <WSL_IP> is the IP address of WSL. You can get it by running ifconfig on WSL. Also <windows_port> is the port Windows will listen on and <wsl_port> is the port server is running on WSL.

You can list the current port proxies using:

netsh interface portproxy show all

2
  • 1
    This is helpful in that the single line of Powershell admin is sufficient to reveal the WSL2 port from my WSL2 service to Windows. However for my purposes I needed to make the port available to other machines on my home network, hence I needed to add a firewall rule from the answer you referenced. So long as the service provided isn't sensitive, this shouldn't be an issue if you turn off the public network option, and limit the incoming traffic to private and corporate networks.
    – TooTone
    Commented Oct 26, 2023 at 11:05
  • Also, ip -c a ought to replace ifconfig as the latter is deprecated (and not installed by default).
    – TooTone
    Commented Oct 26, 2023 at 11:06
7

For now, (March 2022) to access from outside an application running on WSL 2, we need to do the following:

  • Make rules in the firewall for accepting incoming (and maybe also outgoing) connections on the protocol and port on which the application is running (e.g., TCP/80)

  • Get WSL's VM IP address: hostname -I

  • As said on this page (Accessing a WSL 2 distribution from your local area network (LAN)), use this IP address to add, in Windows, a proxy that listens on the port and redirects to WSL's VM. This is done by the following command in a PowerShell running as administrator:

    netsh interface portproxy add v4tov4 listenport=80 listenaddress=0.0.0.0 connectport=80 connectaddress=192.168.101.100
    

Where 192.168.101.100 is the VM's IP address from hostname -I and 80 the port we want to open to the outside.

As WSL's IP address changes when rebooted, this should be automated in a PowerShell script, where the previous proxy is removed and a new one is set to the current IP address. All credit goes to Edwindijas on GitHub from who's script this one is heavily inspired:

$ports=@(80,21,22) # the ports you want to open
$addr='0.0.0.0';

$wslIP = bash.exe -c "hostname -I"
$found = $wslIP -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if(! $wslIP -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') {
  echo "WSL's IP cannot be found. Aborting";
  exit;
}

$portsStr = $ports -join ",";
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $portsStr -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $portsStr -Action Allow -Protocol TCP";

for ($i = 0; $i -lt $ports.length; $i++) {
  $port = $ports[$i];
  iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$wslIP";
}
6

Similar to countach’s answer, but using iproute2:

If using Ubuntu, type ip address in the WSL terminal. Look for the entry that says #: eth0 ... where # is some small number. There is an IP address there. Use that.

3

I faced the same issue where I have to access the localhost from my WSL machine (ubuntu)

server running in wsl

so direct access to the url will not work in your browser as this is a VM but you can imagine it as a machine running on the same local network and access it like that as well, to do that just open a new terminal in ubuntu and run

ifconfig

if not installed in your wsl just run

sudo apt install net-tools

there you can see the inet address which can be directly access on your browser

![broadcast address

for example in my case I can access the server in my browser by going to

http://172.23.157.59:8000/

0
3

Have a look at Microsoft documentation, Accessing Linux networking applications from Windows (localhost):

According to the docs if you are running an older version of Windows (Build 18945 or less), you will need to get the IP address of the Linux host VM

This should be a non-issue post the Windows 10 Build 18945 (2019-07-19).

0
2

enter image description here

There's a npm package for that now:

npx expose-wsl@latest
1
  • 2
    This works, but I'm struggling to understand what the exact problem is --- Every proposed solution I've seen doesn't work --- But this does. Commented Jan 4 at 6:29
2

I have written a PowerShell script, using two simple commands which worked perfectly for me.

# Get the IP address of the WSL
$str = wsl -- ip -o -4 -json addr list eth0 | ConvertFrom-Json | %{ $_.addr_info.local } | ?{ $_ }
echo "WSL IP address: $str"

# Establish the connection with the WSL
# listenport,connectport ports can be changes as per the needs
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=8080 connectaddress=$str

Create a .ps1 file using this code and execute it from the PowerShell terminal. It can be added to the scheduler, so that the script will run every time at Windows boot.

1
  • An explanation would be in order. E.g., how does it work? Why does it work? What is it supposed to do? What is the idea/gist? From the Help Center: "...always explain why the solution you're presenting is appropriate and how it works". Please respond by editing (changing) your answer, not here in comments (but *** *** *** *** *** without *** *** *** *** *** "Edit:", "Update:", or similar - the answer should appear as if it was written today). Commented Aug 8, 2023 at 19:32
1

I followed the answer by @toran-sahu about adding an inbound rule to Windows Defender Firewall but recently (after adding a 2nd wsl2 instance) it stopped working again. I came across this issue thread and running the following in cmd prompt got it working again for me.

wsl --shutdown

update: it seems this issue comes from having Fast Startup enabled https://stackoverflow.com/a/66793101/8917310

2
  • 2
    To be honest, this question probably wouldn't have been solved by the wsl --shutdown. When it's the Fast Startup issue, that makes even localhost forwarding break, so the original poster wouldn't have been able to the server via localhost in Windows. Since they say that worked, it's unlikely to be the issue you are thinking of. Commented Jul 9, 2021 at 21:58
  • wsl --shutdown by itself, without adding any firewall rules, actually worked for me.
    – 0x5453
    Commented Jan 1, 2022 at 19:18
0

Fix that works for me (network was unreacable after cisco vpn connect). Change value in NatNetwork and NatGatewayIpAddress with windows regedit Path -> HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss (e.g. 192.168.77.1 and a subnet within that range)

-3

I've tested on Update for Microsoft Windows (KB4532132) with a reinstalled WSL, and it works as expected.

It seems the issue was related to an old Windows version or old WSL version.

Not the answer you're looking for? Browse other questions tagged or ask your own question.