How to connect to MongoDB from WSL2
Asked Answered
R

1

3

I started a MongoDB server mongod.exe on my local Win11 machine and want to connect to it with pymongo from within WSL2 (from a Jupyter Notebook started in WSL2; ip address taken from ifconfig below):

import pymongo as pm
import datetime as dt

host = 'mongodb://192.168.72.32'
port = 27017
client = pm.MongoClient(host, port)
client.admin.command('ismaster')

I keep on getting a ServerSelectionTimeoutError: 192.168.72.32:27017: [Errno 111] Connection refused error.

The problem is how to expose the server/port from Windows to WSL2. I already opened ports in netsh (as described in official docs here). Output from ifconfig on WSL2 end:

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.72.32  netmask 255.255.240.0  broadcast 192.168.79.255
        inet6 fe80::215:5dff:fe96:9d57  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:96:9d:57  txqueuelen 1000  (Ethernet)
        RX packets 662495  bytes 168890186 (168.8 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 170242  bytes 369162848 (369.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 99019  bytes 163040786 (163.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 99019  bytes 163040786 (163.0 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

What am I doing wrong?

Regime answered 24/7, 2022 at 15:58 Comment(0)
D
3

There are (at least) three things that need to be in place to access any network application/service running in Windows from WSL2:

  • *Configure the service to listen on the correct Windows network interface (not localhost), a.k.a. the "bind address".

  • Open the necessary firewall port(s)

  • Use the correct address from WSL2 (again, not localhost)

You may just be missing the first part, as MongoDB binds to localhost by default. According to the doc:

MongoDB binaries, mongod and mongos, bind to localhost by default. If the net.ipv6 configuration file setting or the --ipv6 command line option is set for the binary, the binary additionally binds to the localhost IPv6 address.

More detail provided below on each of these requirements (mostly copied, with some slight tweaks for your particular use-case, from my related answer on Super User):

Bind address

Many applications or services default to binding to localhost, which (obviously) means that you can only connect to them from the host on which the service is running. Because WSL2 runs on a "separate network", you won't be able to access a service in Windows that is listening only on localhost. You'll probably want to bind to 0.0.0.0 (for IPv4) and/or :: (for IPv6) to listen on all interfaces.

The method of configuring the service will, of course, vary for different applications, but usually you'll find the setting labeled something like "Bind Address", "Listen On", or something similar. Instructions for MongoDB specifically are linked above.

Make sure to restart the application/service after changing this setting.

Side note: It's possible to bind only to the WSL2 interface as I describe in this answer (buried somewhere in the middle), but it's probably overkill, as the firewall can be used more easily to block connections from non-WSL networks if desired.

Firewall configuration

By default, Windows Defender Firewall (and others) will block incoming connections to the host from another network. Since we've already established that WSL2 is running in a separate network, you'll need to open a firewall port for your service.

You can do this selectively from PowerShell (in an Administrative shell) with something like:

New-NetFirewallRule -DisplayName "MongoDB from WSL2" -InterfaceAlias "vEthernet (WSL)" -Direction Inbound -Protocol TCP -LocalPort 27017 -Action Allow 

Of course, you can drop either:

  • the InterfaceAlias, in which case it will open 8545 from all networks
  • or the LocalPort, in which case it will act like the "disable" option above and always accept incoming traffic from the WSL network interface.

Finding the correct Windows address to use from WSL2

There are several methods (and IP addresses) you can use. The easiest way is simply to use the IP address of the Windows host, if you know it. However, if it is dynamically assigned and changes frequently (which is, I believe, fairly unusual nowaways), then you may need to change your WSL2 code each reboot.

In your case, it looks like you likely have a static address in the 192.168.0.0/32 private address space, so you may not need the following.

However, it's probably best practice anyway to use a mDNS name that will (usually) resolve correctly for static or dynamic address assignments.

Assuming that you haven't overridden the default /etc/resolv.conf that WSL generates, this can be done by taking the Windows computer name and simply appending .local. For instance, if your computer name is bubblegum, then bubblegum.local should be the correct address.

From Python, this can be obtained with:

import socket
server = f'{socket.gethostname()}.local' # Generic form
host = f'mongodb://{socket.gethostname()}.local' # For your example

You should find that this is the same address as found with:

echo $(ip route list default | awk '{print $3}')

If, however, you have overridden the /etc/resolv.conf (necessary in some cases due to VPNs or other networking configurations), then you may need something more complicated like:

echo $(host `hostname --long` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r')

(Credit to @ChaiAng's answer on Ask Ubuntu for this method).

However, note that it is substantially slower than mDNS.

Duo answered 24/7, 2022 at 16:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.