Trying out NodeJs Development on Windows using WSL 2
I try my hand at using the Windows Subsystem for Linux (WSL 2) for a modern NodeJs / ReactJs development workflow.
I recently built a desktop PC and I wanted to use it to host my Sleep-Timer project as well as other things like Minecraft servers for the kids, etc.
I have been a developer for many years and hardly any of it has been on Windows.
Developing on windows gives me flashbacks of tools like XAMPP, which did the job, but were a pain to work with.
These days Microsoft has mostly admitted defeat and have created their Windows Subsystem for Linux (WSL).
WSL 2 is out now, so I thought I would give it a try to see if I could make it work and at the same time, see if using typical Unix style tools like NodeJs is any easier than back in my PHP days.
Installing WSL 2 wasn't too tricky. There is pretty good documentation on Microsoft's dev site.
The main issue that I had was trying to figure out how to enable virtualization on my new MSI B550 motherboard. I eventually found a video that showed the process. I was scouring the BIOS options for the word
virtual*, but the option was called
SVM Mode. ¯\_(ツ)_/¯
Not bad, Microsoft
Once Ubuntu was installed and with the VS Code Remote WSL Extension installed, the process of checking out my code from GitHub, making the necessary codebase config tweaks, installing node and getting the code running in development mode was all pretty straightforward.
For most day to day NodeJs or modern JS development the experience up to this point is actually pretty enjoyable.
With a dev server working so well, I was confident that I could statically compile the code, point Nginx at it and be done with it.
All down hill from here
This is where I started hitting into the limitations of the current WSL implementation.
Certain parts surprised me, like being able to symbolically link my projects folder in windows directly to the
/var/www folder on Ubuntu. I have had to fight with Linux virtual machines not liking Microsoft filesystems in the past.
I had 2 major hurdles to overcome:
- WSL connects to the host via a NAT connection and is therefore not available outside of the host. And I need it to be available outside of the host so that we can use our phones to interact with the Sleep Timer app.
- Getting windows to start the WSL instance at login/startup AND getting Nginx to start when Ubuntu boots were surprisingly difficult to achieve.
Solving the Network Woes
To be honest, I expected this part to be tricky, but I had no idea of just how tricky it would be.
I could access Nginx inside the WSL from the host by pointing a browser at the WSL IP address, but as mentioned before, this address wasn't accessible outside of the host.
Somewhere along the way, while tumbling further down the rabbit-hole, I found that there was a GitHub issue related to this problem... that has been open for over a year.
There were many suggestions for what to do to work around the issue, all of them seemed complicated and just as likely to break things than fix them.
I found a few references online to one comment in particular.
The work around is essentially a script that opens the necessary ports on the host as well as set up IP forwarding from the host to the WSL. The commenter suggests to schedule this script to run a few seconds after login.
After a bit of trial and error (not being that familiar with PowerShell slowed me down a bit) I got this to work.
I checked a few times and indeed, after login PowerShell comes up, the script runs and the ports are all set up and ready to go. Unfortunately at this point, Nginx was not ready to go, so I would have to manually start Nginx on each login.
So, one hurdle down and one to go.
SystemCtl work around on WSL
I am still not 100% sure why
systemctl doesn't work on WSL, but when you try to use it, it yells at you.
System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down
There were a few different solutions that I saw. Most of them involved replacing
systemctl with varying degrees of sketchiness in the level of their weird side effects.
I stumbled onto a neat work around.
Commands can be executed inside of the WSL from the host.
wsl sudo service nginx start
The trick is to make a script to start Nginx, from outside of Ubuntu, that can be run on login/startup.
There was a little fiddling around to make sure that my Ubuntu user could start Nginx without needing my password, but once that was sorted out, it all came together.
All that was needed was a quick log out, log in and test from my phone and I could confirm it was all working.
As I mentioned before, for "normal" day-to-day development with development servers running directly on NodeJs and only needing to be accessed by the host, the current state of NodeJs development on Windows is actually quite pleasant.
I could actually see myself opting out of a MacBook in favor of a Windows PC if I was the one paying for the development equipment.
However, the Nginx experience demonstrates that the solution is not perfect yet.
Thankfully, strangers on the internet have come to the rescue in this particular case, but if I decide to host more Unix based apps on my home network and if Microsoft hasn't solved these issues, I might look at getting a cheap Linux box instead.