PHP Development with the Windows Subsystem for Linux

If you've seen my Microsoft video, you know it's possible to run the Bash shell in Ubuntu Linux on Windows. It's an unbelievable fact for many folks unfamiliar with the modern Windows OS. But it's true.

It's called the Windows Subsystem for Linux (or just WSL), and it supports Ubuntu Linux out of the box. However, Microsoft announced at its most recent BUILD conference that it will also support SUSE Linux and Fedora Linux in the Windows 10 Fall Creators Update coming Fall 2017.

WSL is how I develop PHP on Windows. I can use the same exact tools on Windows as I do on my production servers. It's beautiful.

Turn on WSL

If you have not already, enable WSL on Windows. You can follow this step-by-step tutorial on Microsoft's website:

Upgrade Ubuntu

When you start the Bash shell for the first time, you should install any outstanding Ubuntu updates.

sudo apt-get update
sudo apt-get upgrade

Install PHP

Next, of course, you need PHP. Install PHP 7.x using the popular ppa:ondrej/php repository.

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.1-bcmath \
                     php7.1-bz2 \
                     php7.1-cli \
                     php7.1-curl \
                     php7.1-dev \
                     php7.1-dom \
                     php7.1-exif \
                     php7.1-fileinfo \
                     php7.1-intl \
                     php7.1-json \
                     php7.1-libsodium \
                     php7.1-mbstring \
                     php7.1-pdo \
                     php7.1-pdo-mysql \
                     php7.1-pdo-sqlite \
                     php7.1-simplexml \
                     php7.1-sockets \
                     php7.1-ssh2 \
                     php7.1-uuid \
                     php7.1-xdebug \
                     php7.1-xml \
                     php7.1-xmlreader \
                     php7.1-xmlwriter \

I purposefully omit PHP-FPM and a database server like MySQL or PostgreSQL. WSL does not persist long-running processes when the last WSL terminal is closed. If you need to run a database server, I recommend you run it on Windows proper and reference it from WSL when necessary.

The WSL filesystem

There are a few rules you should follow to make your life easier using WSL. First, WSL mounts your Windows C:\ drive at /mnt/c. You should keep all of your editable project files beneath /mnt/c in WSL. This allows you to edit your files in both WSL and Windows without running into weird permissions problems between the two environments.

For example, in Windows I keep my code repositories in C:\Users\josh\work. I access these same files in WSL at /mnt/c/Users/josh/work.

If there is a caveat to WSL, it's the lack of a Linux kernel. There isn't one. WSL is a real-time translation layer between userland Linux and the underlying Windows kernel. This means you won't be able to install and run software that relies on a true Linux kernel, like VirtualBox.

Use Windows programs inside WSL

You can call Windows executables from inside WSL. This means you can invoke Visual Studio Code, for example, from inside WSL to edit your files.

To expedite this workflow, I alias Visual Studio Code in my ~/.bash_profile file like this:

PATH=$PATH:"/mnt/c/Program Files (x86)/Microsoft VS Code"
alias code="Code.exe"

Now I can edit a project with Visual Studio Code using this command in my Bash shell:

code /path/to/project/

PHP linting in Visual Studio Code

Currently, Visual Studio Code can lint PHP code only with a PHP executable installed on Windows proper. However, I have a pending pull request that will let Visual Studio Code use a PHP linter via Cmd.exe, Powershell.exe, Git Bash, or WSL Bash. This example configuration lets me lint PHP code with a PHP binary from WSL Bash:

    "php.validate.executablePath": "/usr/bin/php",
    "php.validate.runInShell": {
        "shellArgs": ["-c"],
        "shellExecutable": "C:\\Windows\\system32\\bash.exe"

You can also use this simplified configuration to use the pre-defined shell from your ComSpec environment variable:

    "php.validate.executablePath": "/usr/bin/php",
    "php.validate.runInShell": true

I'm working with the Visual Studio Code team to finalize and, I hope, merge my pull request soon.


With regards to SSH, you should consider your WSL installation a separate computer from its Windows host. There are byzantine workarounds to share Windows SSH keys with WSL, but I've found it easier to create a unique SSH keypair in WSL to enable password-less SSH authentication between WSL and my remote servers.

Run this command in your WSL Bash shell and follow the instructions:

ssh-keygen -t rsa -b 4096 -C ""

Other odds and ends

WSL is Ubuntu Linux. It's not an emulation. It's really Linux, and it runs the same Linux ELF binaries that you'd install on your production Linux server. You are free to install any software you need with the Aptitude package manager, like Git:

sudo apt-get install git-core

You can learn more about the Windows Subsystem for Linux at: