Setting up a PHP development environment for Symfony with Windows and WSL2

Setting up a PHP development environment for Symfony with Windows and WSL2

A consistent API and great documentation are key elements for providing an enticing developer experience. The third pillar is the development environment. An easy-to-setup software stack lowers the barrier to get your hands dirty. A fast and carefree dev environment keeps the focus on productive tasks in the long term. Developers should be developing, not shaving the yak.

Arguably PHP owes its popularity to the developer experience. And the simple code-refresh-code cycle remains compelling to this day. However to me the LAMP (Linux, Apache, MySQL, PHP) development experience on Windows was always a bit lackluster. Over the years there have been a number of efforts to improve this: WAMP, Vagrant, Docker… the list goes on and on.

While these efforts have enabled PHP development on the most popular desktop operating system, to me they've always felt non-native. And ultimately I would deploy to a Linux production environment where the app might behave just a bit differently. Compared to macOS, with its BSD underpinnings, Windows is just from a different world from the Unix realm that PHP stems from.

WSL2 sneaks in a Linux kernel to Windows

Microsoft has acknowledged that a vast majority of the Open Source development projects (PHP included) are based on Unix derived operating systems, GNU/ Linux being the most popular one. In August 2016, Microsoft released Windows 10 Anniversary Update that included a novel technology to enable developing and running Linux apps: Windows Subsystem for Linux (WSL)

WSL is a translation layer that allows running a Linux compatible shell by translating system calls from Linux kernel to their Windows kernel equivalents. This technology was used in reverse to allow Microsoft to run their MS SQL Server database product on the Linux operating system, in addition to Windows Server. In addition to translating syscalls, WSL also implements a filesystem compatibility layer that allows sharing files between the Windows Shell and WSL terminals.

In the years following its release the WSL has been improved, addressing some key issues like slow disk access. But ultimately the team decided that trying to replicate everything. In May 2019 Microsoft announced the WSL would be succeeded by WSL2. The second iteration of the technology runs on a native Linux Kernel on HyperV, fully supported by Microsoft. Hard to imagine for those of us who remember the time when Microsoft CEO called Linux a cancer.

Fast forward a year from announcement, and WSL2 is ready for primetime. Microsoft plans to release WSL2 in the Windows 10 2020 May Update (also known as Windows 10 2004). Yes, Microsoft is still terrible at naming things, but their engineering recent efforts are impressive. WSL2 will ship as an optional package with an expected release date on the last week of May.

Installing Symfony and eZ Platform on WSL2

While the official release is still some weeks away, enthusiasts can already get their hands on WSL2 by installing an Insider Build. This is close to the final, undergoing testing and validation.

Installing a stack to run eZ Platform (or any Symfony 5 application) on WSL2 includes these steps:

  • Enable WSL2
  • Install a Linux distribution
  • Install system software (PHP, MariaDB, composer, etc.)
  • Install Symfony CLI
  • Install application (e.g. eZ Platform v3.0.3)
  • Run and develop your app ? 

Enable WSL2 and Virtual Machine Platform

The first step is to enable Windows Subsystem for Linux (WSL2) and the Virtual Machine Platform. Start PowerShell as administrator and run the following commands:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

Once this is complete you have the infrastructure to run an embedded Linux environment.

Install a Linux distribution

If you open up a system prompt (command.exe) and type "wsl", you will get the following notice:

PS C:\Users\LattePanda> wsl
Windows Subsystem for Linux has no installed distributions.
Distributions can be installed by visiting the Microsoft Store:
https://aka.ms/wslstore
PS C:\Users\LattePanda>

This indicates that a Linux distro needs to be installed. We'll do that soon, but before that let's set the default WSL version to 2. WSL1 will continue to work, but we want explicitly to use WSL2:

C:\Users\LattePanda>wsl --set-default-version 2
For information on key differences with WSL 2 please visit https://aka.ms/wsl2

Installation is done from the Windows Store: https://aka.ms/wslstore. In the store you can choose from a number of different available Linux distributions. For our case we will choose Ubuntu 20.04 LTS because of its long support cycle and recent default system packages.

Ubuntu 20.04 ships with PHP 7.4. In this article will install eZ Platform v3.0 which is compatible with PHP 7.4, but for previous versions of eZ Platform you might want to install Ubuntu 18.04 LTS with an older default PHP version. Alternatively you can install a compatible version by hand.

Once you've downloaded the package, the installation wizard will ask you for a username and password. These are exclusively used for the embedded Linux instance within your Windows 10 installation. While you're in the store I recommend installing the new Windows Terminal.

After installation you can verify you've got a functioning WSL2 distro from a Windows terminal:

PS C:\Users\LattePanda> wsl --list --verbose
  NAME            STATE           VERSION
* Ubuntu-20.04    Running         2
PS C:\Users\LattePanda>

Install system software

Once you've installed a distribution, you will use its standard tools to manage system packages and updates. In the case of Ubuntu and other Debian derivatives, you will use APT.

NOTE: At the time of writing there is a known bug related to realtime clock with Ubuntu 20.04 and the WSL2. To prevent this bug from surfacing, we configure APT to freeze our installed libc6 version to the one from the original distribution by issuing the following command:

sudo apt-mark hold libc6

Once this is in place it is safe to start using APT tools, first by updating all the packages:

sudo apt update
sudo apt upgrade

Next let's install the core dependencies to run eZ Platform (and many other Symfony apps):

sudo apt install composer php-xml php-intl php-gd php-curl php-fpm

I deliberately left out the database service from above to illustrate that eZ Platform is compatible with both MySQL/MariaDB and PostgreSQL databases. Choose the one suited for your needs. I chose to use MariaDB for this tutorial. Install MariaDB server and the PHP MySQL extension:

sudo apt install mariadb-server php-mysql

Next start the MariaDB server instance and and log in as the root user:

sudo service mysql start
sudo mysql

To add a database for eZ Platform, issue the following SQL statements:

CREATE DATABASE ezp;
GRANT ALL ON ezp.* TO 'ezp'@'localhost' IDENTIFIED BY 'wsl2ezp';
FLUSH PRIVILEGES;
EXIT;

Finally verify that you can access the database:

mysql -uezp -pwsl2ezp ezp

A Linux environment with PHP, MariaDB and the composer package manager is ready to go:

janit@W1ND0Z1337:~$ php -version
PHP 7.4.3 (cli) (built: May  5 2020 12:14:27) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies
janit@W1ND0Z1337:~$ composer --version
Composer 1.10.1 2020-03-13 20:34:27
janit@W1ND0Z1337:~$ mysql --version
mysql  Ver 15.1 Distrib 10.3.22-MariaDB,
       for debian-linux-gnu (x86_64) using readline 5.2

Since we use Symfony Encore for front end asset management, we will install the Yarn packet manager from the project repository. This will also install Node.js as a dependency:

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update
sudo apt install yarn

Install Symfony CLI

What you may have noticed gone missing from the above installation procedure is the A in LAMP and the E in LEMP. In plain English: Our stack has no web server installed. Traditionally a PHP stack has included a separate web server. A fully-fledged HTTP server is still a for production installs, but for development I've gravitated towards a simpler option: Symfony Local Web Server

The Symfony CLI is a stand-alone command line application that you can install from your WSL terminal. Remember to follow the Linux instructions, NOT the Windows ones:

wget https://get.symfony.com/cli/installer -O - | bash

The above installs it to your user directory, but you can make it available globally by moving it:

sudo mv /home/janit/.symfony/bin/symfony /usr/local/bin/symfony

We can now verify that our stack is working by creating a new hello world Symfony app and run the web server:

symfony new hello-world
cd hello-world
symfony serve

Open a browser window at http://localhost:8000/ to view the app running. The first time you run you might get a prompt from Windows whether this traffic is allowed. Now you should have a bare bones Symfony app running in Windows using WSL2 as shown in the screenshot below.

For more details on setting up TLS, multiple PHP versions, etc. head over to the Symfony docs.

Installing eZ Platform and accessing files

Next up is installing and running a full Symfony app. This works like in any Linux environment (because it is one!). We'll install a copy of eZ Platform by using composer. Behind the scenes composer will clone the meta repository, check out a release and install the packages used:

composer create-project ezsystems/ezplatform ezplatform ^3
cd ezplatform

To install our database we need to define the database configuration and run the installer:

echo "DATABASE_URL=mysql://ezp:wsl2ezp@127.0.0.1:3306/ezp?serverVersion=10.3" > .env.local
composer run-script ezplatform-install

Once this is complete you can enter the project directory and start the Symfony web server:

symfony serve

The output shows that the Symfony web server detects and uses the installed copy of PHP-FPM:

May 11 21:11:40 |DEBUG| PHP    Reloading PHP versions
May 11 21:11:40 |DEBUG| PHP    Using PHP version 7.4.3 (from default version in $PATH)
May 11 21:11:40 |INFO | PHP    listening path="/usr/sbin/php-fpm7.4" php="7.4.3" port=38257
May 11 21:11:40 |DEBUG| PHP    started
May 11 21:11:40 |INFO | PHP    'user' directive is ignored when FPM is not running as root
May 11 21:11:40 |INFO | PHP    'group' directive is ignored when FPM is not running as root
May 11 21:11:40 |INFO | PHP    fpm is running, pid 15263
May 11 21:11:40 |INFO | PHP    ready to handle connections
May 11 21:11:40 |INFO | PHP    systemd monitor interval set to 10000ms

 [OK] Web server listening
      The Web server is using PHP FPM 7.4.3

      http://127.0.0.1:8000

Now if you open a browser (in Windows) and head to http://localhost:8000/ you can see the application running. To access the files from Windows, you can execute the following command to open up a Windows Explorer window in your current working directory:

explorer.exe .

From here you can pick things up and use whatever Windows IDEs (or even notepad.exe!) you want to use for development. If you want to access the MariaDB database from Windows tools be sure to read this blog post on connecting to a MySQL DB from the Windows host with WSL2.

You can watch the whole installation process in this video:

Conclusion

The original WSL was something that brought Windows closer to the native PHP ecosystem, but it was lacking in performance and compatibility in some areas. WSL2 is a new take on the same task (running Linux applications on Windows), that should help alleviate the previous pain points. I wouldn't be surprised to find some corner cases where it fails, but it's definitely a good start.

It is also worth noting that while this tutorial focused on creating a minimalist development environment, many real-world projects are more complicated. You've got dependencies to additional daemons like ElasticSearch, Redis, RabbitMQ and maybe a host of microservices.

As a cherry on top, many of us need to work on multiple complex project setups like this simultaneously. For these cases tools like Docker and Kubernetes are valid choices. Changes done in WSL2 make it possible to run these workloads on Windows better than before, too.

P.S. Now that you've got a copy of eZ Platform by Ibexa installed on your local environment, why not learn more about what eZ Platform offers for developers and kick the tires a bit? :)

eZ Platform is now Ibexa DXP

Ibexa DXP was announced in October 2020. It replaces the eZ Platform brand name, but behind the scenes it is an evolution of the technology. Read the Ibexa DXP v3.2 announcement blog post to learn all about our new product family: Ibexa Content, Ibexa Experience and Ibexa Commerce

Introducing Ibexa DXP 3.2

Insights and News

NEWS
By Molly Faure
03/03/2024 | 4 Min read
PRODUCT
By Nicole Gajda
01/03/2024 | 3 Min read
PRODUCT
By Nicole Gajda
29/02/2024 | 3 Min read