Setting up a PHP/Laravel environment on WSL2 and Windows

Intro

To most, choosing an operating system to work in is a voluntary choice, at least for their hobby projects. To some, me included, that isn't quite a luxury we can afford. Varing levels of accessibility, as well as screenreader maturity and the breathing room to run damage control if something suddenly becomes inaccessible or collapses in some other way make Windows 10 the most expedient and effective operating system for most people who are trying to be productive in tech, be it as a developer, data scientist or cybersecurity professional. Unfortunately, where development dependencies, tools and applications are concerned, especially these days, Windows is often a second-class citizen. If there are bugs, they will usually happen on the Windows side of things, often with hard to diagnose problems as a result. Enter WSL2, essentially a lightweight virtual machine that allows for the use of tools written for Linux within a Windows environment. This opens up a whole bunch of doors that we previously needed to set up a complicated virtual machine strategy for. In this article, I'll go over setting up a PHP/Laravel environment on WSL2, running on Windows 10.

Set up WSL2

The easiest way to set up WSL2 is to follow the official wsl2 setup guide. No accessibility gotchas should be encountered here in most cases. There are some reports about AMD users getting an odd prompt when enabling HyperV, I will edit this post if I encounter this myself and add remediation steps if any are required.

Now, we are in 2021, so we are doing this the spiffy way. WSL2, VS Code, Docker, the works.

Set up Docker to work with WSL2

I could wax poetic about this process, but there really isn't all that much to say. First, Install Docker and subsequently make sure you set it up correctly with WSL2. Why Docker? Ehh ...it's the thing to do these days, it normalizes development dependencies like database versions and a tool we get to a little bit later really, really likes it. Ok, onwards! :)

Set up PHP, composer, tweaks

First, let's make sure we have all the PHP modules we might need down the line installed, Pick and choose from this apt invocation:

sudo apt-get update
sudo apt install unzip php php-cli php-fpm php-json php-intl php-common php-mysql php-zip php-gd php-mbstring php-curl php-xml php-pear php-bcmath -yqq

The flags essentially make it so apt doesn't bother us while setting all that up, this shouldn't take super long but at least this way you can do something else while it's happening.

Now next, we need to install composer, the PHP package manager. A nifty little oneliner:

curl -sS https://getcomposer.org/installer | php \
            && sudo mv composer.phar /usr/local/bin/ \
            && sudo ln -s /usr/local/bin/composer.phar /usr/local/bin/composer

Quick little aside, you ideally want to stay within the Linux filesystem while doing wsl2 stuff. The mounted folder where your windows user folder is is significantly slower within WSL2, so doing a quick cd ~so you can operate from within your Linux home folder is probably worth it. Next, in order to prepare for Laravel Valet, which is normally mac only but was ported to Linux, we need to make a small change in /etc/resolv.conf. Add:

[network]
generateResolvConf=false

These lines may already be there, just commented out. If so, have them not be commented out anymore. ;)

Laravel Valet, Takeout, all the good stuff

First, let's install the Linux port of Valet and the takeout docker container manager using composer:

composer global require cpriego/valet-linux tightenco/takeout

Composer does not automatically add its global bin folder to the PATH variable, so let's do that so we can run commands in there without having to go to the directory every time. Add this to ~/.bashrc:

export PATH=~/.config/composer/vendor/bin:$PATH

And then run a simple “source ~/.bashrc” to load in the changes.

Next, run valet install to set up the valet tool. Valet messes with our /etc/resolv.conf , thee file we edited just now, turning it into a symlink. We don't want this, as that will make WSL reinitialize it on every restart. So:

sudo unlink /etc/resolv.conf
sudo cp /opt/valet-linux/valet-dns /etc/resolv.conf

On searching around a little, it seems we also need to add a file to preempt any odd DNS bugs. Here goes:

touch /opt/valet-linux/dns-servers
sudo nano /opt/valet-linux/dns-servers

Just adding “nameserver 1.1.1.1” without the quotes in there should be enough. That is the Cloudflare DNS which is pretty speedy, you can also use 8.8.8.8 for the Google DNS, for example. Ok! We're going places! Now, we can start things off with:

valet start
sudo service php7.4-fpm start 

The second command is a failsafe; sometimes valet start on ubuntu doesn't seem to start that service properly. Now, cd to the folder where your laravel projects will live, say ...~/projects/php, and run valet park.

Next, we need to enable the database. I prefer Postgresql, but there's a handful that takeout currently supports. There's two ways to do this; running “takeout enable” gives a menu you can arrow through, but given Windows screenreaders haven't figured out console highlight tracking yet, you'll probably want to provide the service name yourself, e.g. “takeout enable postgresql”. Follow the instructions and postgres will run on 127.0.0.1 for projects to use.

Setting up DNS resolution to the WSL2 instance

A cool thing about Valet is that it autoconfigures new projects to be reachable on the *.test domain invocation, routing those to localhost. Except ...WSL2's localhost isn't our localhost. We can add entries for individual sites to C:/Windows/System32/drivers/etc/hosts to route hosts to 127.0.0.1 individually, or we can use the .localhost top-level domain. To my knowledge, only Chrome currently supports this. If you want to go that route:

valet domain localhost

Installing Laravel

We can install Laravel in several ways, here's a few.

Using Docker and Laravel Sail

Given we already have docker set up, we can use a relatively new addition to the Laravel ecosystem, Laravel Sail. to do this, run the following, where the bit after the TLD is the name of the folder for the project:

curl -s https://laravel.build/helloWorld | bash

This will do a whole bunch of docker magic, after which your application will be accessible on projectname.localhost from chrome. You can read more about Laravel Sail here.

Using Composer

We have composer installed and ready to go, so an alternate way of doing this is by using our already existing infrastructure:

composer global require laravel/installer
laravel new <project name>

Conclusion

From here, the existing docs can take over. VS Code is a topic in itself, and will probably merit its own post at some point. Using the various extensions it provides, you can work within the WSL2 container, set up your PHP tools on the WSL2 site in order to get linting and static checking support etc. That's enough out of me for now.