I am developing this blog with Hugo in a Docker container which is running in WSL (not Docker Desktop – I barely use the GUI anyway). Hugo has a web server which allows me to see how the website looks like as I make changes.

With host networking mode under Docker, in WSL, Hugo’s port 1313 is published on localhost. I can test it in Firefox and in Chromium Edge. However, to test it on my phone, in Safari, I first need to push changes to my Github repo before pulling to my Nginx LXC container, because ports on WSL only listens to localhost. This is not ideal.

Getting around the problem

One way to get around this is by proxying TCP connections from LAN to WSL so that I can simply run Hugo’s web server and access it using my computer’s IP address.

But how? I am not familiar with networking on Windows. In Linux, one can set up iptables’ MASQUERADE and DNAT rules to achieve this, or use rinetd. Apparently, rinetd does have a Windows binary, but I ended up using netsh to achieve what I want.

Finding out WSL’s internal IP address

First, you’ll need to find out the internal IP address for WSL. You can find out by using the following command…

$ wsl hostname -I
172.23.118.3 172.17.0.1

… which gives me two IP addresses – I am not sure why. In this case, the first IP address is WSL’s.

Proxying TCP

Start a terminal with administrator rights to set up a port proxy. The command I used is as follows. listenaddress and listenport pertains which address and port the host machine will listen on from LAN. connectaddress and connectport defines which address and port Windows will proxy received connection to.

$ netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=1313 connectaddress=172.23.118.3 connectport=1313 protocol=tcp

It’s worth to note that WSL will change its IP address on every restart, so you may need to configure it again in the future.

To show all proxied ports.

$ netsh interface portproxy show all

And to delete a port proxy configuration.

$ netsh interface portproxy v4tov4 delete listenport=<listenport> listenaddress=<listenaddress>

Firewall configuration

Windows will block connections to the port you have set to listen on, so you will have to create an allow rule to that port.

Alt text

Set rule type to port and configure ports you want allowed accordingly. After this, you should be able to access the service in WSL through the IP address of your computer.

Hugo-specific

Any URLs in pages served by Hugo web server will have its base URL set as ’localhost’ along with a trailing port number. E.g. http://localhost:1313/path/here. Clicking any link from your LAN will redirect you to localhost. Also, by default, Hugo only listens to localhost. To fix this, start the Hugo web server with the following arguments.

$ hugo server --bind 0.0.0.0 --baseURL=/ --appendPort=false

Now every link in web pages served by Hugo should be relative, i.e, /path/here.

Caveat

netsh can only proxy TCP connections. For UDP, you have to look for other utilities. Newer versions of rinetd support UDP proxying in addition of TCP.