Developing with Strapi on Windows and WSL2

Introduction

I'd been looking for a "headless CMS" to provide the static content for one of my websites. After much looking around, I thought that Strapi looked like the best fit.

However, a test install on my Windows 10 PC proved harder than expected and almost led me to give up on Strapi. That would have been a shame - so this blog documents how I ended up running Strapi on Windows 10. It turned out to be an ideal way for me to run Strapi locally so I've documented it here in case it is useful for others.

The Problem

The install of Strapi was failing at the first hurdle - on "npm install". The main problem seemed to be around the version of the knex query builder. I don't think I'm the first person to encounter recent problems installing on Windows - there's at least a couple of Github issues and a forum post.

There was also some npm related magic needed that I only saw alluded to in in a Strapi Digital Ocean guide. Let's get that out of the way first. Specifically, there was a need to:

cd ~
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'

and add the following to your user's profile.

# set PATH so global node modules install without permission issues
export PATH=~/.npm-global/bin:$PATH

My Solution

So if installing Strapi on Windows wasn't straight forward, why didn't I install it directly on Ubuntu 20.04 somewhere - which is what my VPS runs anyway?

I'd recently been playing with version 2 of the Windows Subsystem for Linux and the much improved Docker Desktop experience on Windows 10 Home, so WSL2 was at the forefront of my mind. I already had a fully up to date Ubuntu 20.04 server install in place.

WSL 2

I love the fact that I can open Windows Terminal and have a real Ubuntu Linux running in about 2 seconds. This is so much better than the old Vagrant / VirtualBox set up I used to use and there are no perceptible delays when actually using the VM.

The next question was whether to have the Strapi codebase on the WSL2 mount (e.g. /home/user/strapi) or external (e.g. on the c: drive at /mnt/c/software/strapi).

I wanted to be able to view and edit the code in a Windows based IDE - which might suggest the later option. However, one difference between WSL1 and WSL2 is that disk access from within WSL2 to the host operating system is known to be really quite slow.

However, we can have our cake and eat it!

My preferred IDE for front end / Javascript type stuff, is Visual Studio Code (but Java / Scala stuff definitely remains in the hands of IntelliJ!). If you install the "Remote - WSL" extension for Visual Studio, you can then edit code in WSL directly from within the Visual Studio Code IDE on Windows! In WSL at the root of your project, type

code .

and this will launch Visual Studio Code on Windows

Visual Studio Code on Windows editing code on Ubuntu in WSL2

Database

The next question was where to run the database. I run MySQL on Windows for umpteen different projects and it seemed a bit of a waste to install it into the WSL Ubuntu when the product of interest was Strapi. Why not just access my Windows MySQL from the Strapi code in the WSL?

While applications running on Windows can simply access ports on WSL (e.g. run a webserver on port 80 in WSL and you can directly access as http://localhost:80/ on Windows), the same is not quite true the other way round. When WSL starts up it seems to assign a somewhat random IP address for the host Windows system. This IP address can be determined by running the following command in WSL:

cat /etc/resolv.conf

This means that the Strapi file <project-root>/config/database.js has to be edited for the Windows IP address every time WSL is started. That's a bit of a drag - but there is a better way!

In the screenshot above, you may be able to see that database.js has been edited to pick up the database IP address from an environment variable called STRAPI_DATABASE_HOST. If the user's profile could set that environment variable to the value from /etc/resolv.conf then it would be happy days.

So the .bashrc file for my WSL user is edited as follows:

# set PATH so global node modules install without permission issues
export PATH=~/.npm-global/bin:$PATH

export NODE_ENV="development"
export STRAPI_DATABASE_PORT="3306"
export STRAPI_DATABASE_NAME="cms-strapi"
export STRAPI_DATABASE_USERNAME="cmsuserstrapi"
export STRAPI_DATABASE_PASSWORD="not-a-real-password"
export STRAPI_DATABASE_HOST=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null)

The key last line is "borrowed" from this Reddit discussion.

Conclusion

So we're done. Ubuntu 20.04 - which is my production deployment target - starts up within WSL2 on Windows in a couple of seconds. Strapi starts quickly within WSL because it is on the WSL mount. And my favourite IDE for JavaScript starts up within a second or two accessing the Strapi code on Ubuntu while running on Windows.

Happy days!