Windows Subsystem for Linux

The Windows Subsystem for Linux lets developers run GNU/Linux environment -- including most command-line tools, utilities, and applications -- directly on Windows, unmodified, without the overhead of a virtual machine.

You can:

  • Choose your favorite GNU/Linux distributions from the Windows Store.
  • Run common command-line free software such as grep, sed, awk, or other ELF-64 binaries.
  • Run Bash shell scripts and GNU/Linux command-line applications including:
    • Tools: vim, emacs, tmux
    • Languages: Javascript/node.js, Ruby, Python, C/C++, C# & F#, Rust, Go, etc.
    • Services: sshd, MySQL, Apache, lighttpd
  • Install additional software using own GNU/Linux distribution package manager.
  • Invoke Windows applications using a Unix-like command-line shell.
  • Invoke GNU/Linux applications on Windows.

For more information visit: Windows Subsustem for Linux Documentation

Installing Windows Subsystem for Linux

The installation of Windows Subsystem for Linux is well described by Microsoft's own document Install the Windows Subsystem for Linux. Instead of the standard Ubuntu distro mentioned in the installation guide, search for and choose the latest Ubuntu 18.04 LTS.

To initialize and update the Ubuntu installation follow Initializing a newly installed distro. This step may be skipped if you have already initialized the Ubuntu distro in the previous step.

An important aspect of WSL is that Windows tools are not able to access files stored inside Ubuntu. However, Ubuntu can (almost) freely read/write the Windows filesystem. Therefore, files that need to be accessed by Windows tools (e.g. your IDE, Backup) need to be stored on the Windows filesystem.

When accessing the Windows filesystem from within the bash shell, you need to prepend the path with /mnt/c/. Although not required, it is best to use the exact same file path casing when creating symlinks.

Installing Apache

Use the following command in the bash shell to install Apache:

sudo apt install apache2

The terminal used by WSL does not support the pasting of text as you are used to. Use right-click for pasting.

Create a project folder for your websites. For reasons mentioned above, this folder needs to be outside of the WSL filesystem. You could use for example: C:/Users/<Username>/Documents/Development/Web/webroot, or simply C:/webroot.

In Ubunto, create a symbolic link to the webroot folder.

sudo ln -s /mnt/c/your/path/to/webroot /var/www/webroot

Open the Apache default virtual host configuration file:

sudo nano /etc/apache2/sites-available/000-default.conf

Remove existing content by keeping the Shift-key pressed and scroll down using the -key. Then press Ctrl+K to cut the selection.

Insert the following VirtualHost configuration:

<VirtualHost *:80>

    ServerName localhost

    ServerAdmin webmaster@localhost
    DocumentRoot  /var/www/webroot

    <Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined


Save the file by pressing Ctrl+O, and hit Enter to confirm. Exit with Ctrl+X.
(In the command bar: ^ meants Ctrl and M means Alt)

Open your favorite Windows editor/IDE, and create an index.html file in your webroot folder with the following content:

<!DOCTYPE html>
<html lang="en">
  <meta charset="utf-8">
  <title>It works!</title>
  <h1>It works!</h1>

Start the Apache service:

sudo service apache2 start

You will probably get the following known error message which you can ignore:
(92)Protocol not available: AH00076: Failed to enable APR_TCP_DEFER_ACCEPT

Open http://localhost in your browser and you should see the text 'It works!'.

For your future Grav sites to work properly, the Apache module rewrite needs to be enabled.

sudo a2enmod rewrite

Installing PHP

Use the following command to install the latest PHP version:

sudo apt install php

To verify that PHP is installed and checking its version, run the following command:

php -v

You should get a response similar to this:

PHP 7.2.7-0ubuntu0.18.04.2 (cli) (built: Jul  4 2018 16:55:24) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

To meet Grav's PHP requirements, a few extra PHP extensions need to be installed:

sudo apt install php-mbstring php-gd php-curl php-xml php-zip

Restart Apache to pick up the changes:

sudo service apache2 restart

Installing Grav

You can install Grav either from within Windows or from within Ubuntu.

Option 1: Windows

Install Grav by downloading the ZIP package and extracting it:

  1. Download the latest-and-greatest Grav or Grav + Admin package.
  2. Extract the ZIP file into the webroot you have created before.
  3. Rename the extracted folder to mysite.
  4. Open http://localhost/mysite in the browser and you should have a working Grav installation.

Option 2: Ubuntu

Run the following commands to install Grav inside the default webroot of Apache:

wget -O
sudo apt install unzip  # unzip is not installed by default on WSL/Ubuntu
unzip -d /var/www/webroot
mv /var/www/webroot/grav /var/www/webroot/mysite

Open http://localhost/mysite in the browser and you should have a working Grav installation.

For other installation options, visit Grav's Installation documentation.

Installing XDebug (optional)

If you are a developer and want to develop your own plugins and themes, you probably inevitably need to debug your code at some point...

Install XDebug using the following command:

sudo apt install php-xdebug

XDebug needs to be enabled in php.ini.
Open the editor:

sudo nano /etc/php/7.2/apache2/php.ini

And add the following lines to the end of the file:

xdebug.remote_enable = 1

In Nano, you can use Alt+/ to jump to the bottom of the file.

Restart Apache again:

sudo service apache2 restart

Activating debugger

In order to start debugging, you first need to activate the debugger on the server. For this, you need to set a special GET/POST or COOKIE parameter. You can do that manually, but it is much more convenient to use a browser extension. It allows you to enable the debugger with the click of a button. When the extension is active, it sends the XDEBUG_SESSION cookie directly, instead of going through XDEBUG_SESSION_START. Below you can find a table with the link to the relevant extension for your browser.

Browser Helper extension
Chrome Xdebug Helper
Firefox Xdebug Helper or The easiest Xdebug
Opera Xdebug launcher

When you want to switch on/off debugging for a website, just toggle 'Debug' in the browser extention.

Launching debugger in Visual Studio Code (optional)

When using Vistual Studio Code, the default PHP debug launchers won't work when Apache/PHP is running in WSL, because of the file mappings.

Insert the following configuration into an already created PHP launch configuration in .vscode/launch.json:

    "name": "LSW Listen for XDebug",
    "type": "php",
    "request": "launch",
    "port": 9000,
    "pathMappings": {
        "/mnt/c": "c:/",

Adding extra virtual hosts (optional)

During the different stages in the lifecycle of our site (development, testing, production) different Grav configurations may be needed. Take for example caching or asset pipelines. You might want to switch them off during development and switch them on when testing performance. For more information see the documentation on Automatic Environment Configuration.

  • Start an editor as Administrator and open file C:/Windows/System32/drivers/etc/hosts. You could, for example, add the following hosts: mysite-dev mysite-prod

    Hosts defined in Windows hosts file will automatically be available in /etc/hosts in WSL/Ubuntu.

  • Create new VirtualHost config files in folder /etc/apache2/sites-available.

    sudo nano /etc/apache2/sites-available/mysite-dev.conf

    Past the following into the editor:

    <VirtualHost *:80>
        ServerName mysite-dev
        ServerAdmin webmaster@localhost
        DocumentRoot  /var/www/webroot/mysite
        <Directory /var/www/>
            Options Indexes FollowSymLinks
            AllowOverride All
            Require all granted
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

Repeat the above commands for mysite-prod.conf and use ServerName mysite-prod as server.

Enable the new VirtualHosts in the Apache configuration:

sudo a2ensite mysite-*
sudo service apache2 reload
sudo service apache2 restart

Now you can point the browser to http://mysite-dev and it will open the Grav installation at C:/your/path/to/webroot/mysite using the config files in folder /user/mysite-dev/config/.

Automatically start Apache (optional)

For starting and stopping Apache, elevated privileges are required. And to be granted the elevated privileges, a password is requested. To prevent Ubuntu asking for a password you can grant yourself permanent elevated privileges for certain services.

Start the visudo editor to edit the sudoer file:

sudo visudo -f /etc/sudoers.d/services

Copy the following lines into the editor:

%sudo ALL=(root) NOPASSWD: /usr/sbin/service *
%wheel ALL=(root) NOPASSWD: /usr/sbin/service *

Apache can now be started with elevated privileges without providing a password.

To start Apache whenever an Ubuntu shell is started, the sudo service apache2 start command needs to be added to the .bashrc startup script. This script is run whenever you start a WSL terminal.

nano .bashrc

Add the following script to the end of the file:

## Start apache2 if not running
status=`service apache2 status`
if [[ $status == *"apache2 is not running" ]]
  sudo service apache2 start

And add the following to .bash_logout to stop Apache when closing the bash shell.

## Stop apache2 if running
status=`service apache2 status`
if [[ $status == *"apache2 is running" ]]
  sudo service apache2 stop

Tips and Tricks

GUI Linux terminal emulator

If you're not a fan of the default terminal experience and would like to install a "native" Linux GUI terminal, you might want to have a look at the article Configuring a pretty and usable terminal emulator for WSL.

Multiple websites, one Grav codebase

If you are like me and have multiple Grav websites deployed for separate projects, you might want to read the documentation on Symbolic Links and on Copying a Project to create a symlinked copy of a single Grav core.

Found errors? Think you can improve this documentation? Simply click the Edit link at the top of the page, and then the icon on Github to make your changes.