[Guide] Developing on Windows 10 using WSL

With the release of the Creators update, WSL now has proper networking, 60%+ better support for Linux system calls, and the best feature of all: the ability to execute Windows native executables. You can read more about this here.

Here’s a couple tips on settings this up for web development, including Trellis.


First of all, I recommend using mintty as a terminal. You can install it using the instructions on the wsltty repo.

You can check out various other terminals such as cmder and Hyper which both support tabs, but for now, wsltty provides a nice drop-in replacement to the default.


Most people prefer zsh over bash. If you’re interested, let’s set that up real quick before we get started.

sudo apt-get install zsh

While there are alternatives, I’ve never had any issues with oh-my-zsh and the plugin support is great. Let’s grab that real quick too…

sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

While normally we’d be able to simply use chsh zsh to change our shell to zsh, /etc/passwd appears to be ignored at the moment for the default shell and I’m sure will be addressed in the future.

For now, we will add the following lines to ~/.bashrc to exec zsh on start:

nano ~/.bashrc

# Launch Zsh
if [ -t 1 ]; then
    exec zsh

Once we do that, restart Bash and we should be on our way. After setting up the below, make sure to check out the massive amount of Plugins and Themes for oh-my-zsh.


An important part of keeping your workflow native and sane is getting a proper installation of PHP 7.1 running locally to allow usage of wp-cli and Composer.

Let’s set that up.

PHP 7.1

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.1 php7.1-mbstring php7.1-xml


curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer


cd ~ && curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp


The next step will be a proper installation of node.js and yarn. We will do this using nvm.

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash

After installing nvm, you will need to source it in your ~/.bashrc or ~/.zshrc.

if [ -r ~/.nvm ]; then
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

After doing that, if it’s setup properly, we should get a version response from nvm.


Let’s go ahead and install the latest version of node and set it as our default version.

nvm install node
nvm use node
nvm alias default node

Now we can go ahead install yarn globally.

npm install --global yarn


This can sometimes be preference vs using rvm, but I opted for rbenv due to the reasons listed here as well as it working as I need it too without any overhead.

To prepare for building Ruby, let’s start with a couple packages to make our life easier.

sudo apt-get install build-essential gcc zlib1g-dev zip

Now let’s get rbenv cloned to our home directory along with the ruby-build plugin:

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

and at this point, we should be able to compile rbenv’s dynamic bash extension to speed things up a bit:

cd ~/.rbenv && src/configure && make -C src

Like we did with nvm, we need to source rbenv in our ~/.bashrc or ~/.zshrc file.

if [ -r ~/.rbenv/bin ]; then
  export PATH=$HOME/.rbenv/bin:$PATH
  eval "$(rbenv init -)"


Now that we have rbenv installed, we can install Ruby.

At the point of writing this, 2.3.3 is the latest so lets go with that.

rbenv install 2.2.3

This can sometimes take a few. If it errors out complaining about dependencies, it usually has a convenient apt-get that you can copy and paste to grab them.

Once it is installed, let’s set it as our default version globally.

rbenv global 2.3.3

and we should be set. Let’s check ruby -v just to make sure.

Looks good.


As much as I’d love for it to be, using the Ubuntu package for Vagrant is just not sane yet. While there are numerous, albeit tedious ways to get it working, it is still no where near as functional as the native Windows version and to avoid the issue all together, we’re going to simply make an alias so vagrant actually points to vagrant.exe which if you added Vagrant to your PATH during installation like you should have, will work quite well.


Also added in the Windows 10 Creators update is the ability to create proper Symlinks.

While these are personal preference, I suggest making a few handy symlinks in your WSL users home directory.

Here are some examples of doing this:

ln -s /mnt/c/Users/YOURUSERNAME/Desktop ~/desktop
ln -s /mnt/d/Development ~/dev
ln -s /mnt/d ~/storage
ln -s /mnt/d/Downloads ~/downloads

Now, assuming you have some type of organization with all of your projects, we can simply cd ~/dev and off we go.

Additional Packages

Here are some packages I recommend grabbing with sudo apt-get install.


Or for those who just want to take my word for it and blindly install them all:

sudo apt-get install screen subversion htop dos2unix


I realize some of the things above are personal preference, but I thought this would be a decent starter point for those who are interested in getting up and going with WSL and ditching our old ways of relying on Cygwin/Babun.

I plan on updating this post with additional information as I find the time for it and as I stumble upon things. I’m only about a day and a half into switching to Windows 10 but I’m quite happy with it now that WSL is usable.

I will work on cleaning up my dotfiles and pushing my new configuration to GitHub. Please, if you lurk on me, do not use the dotfiles currently on my GitHub. They are not “WSL-ready” and may cause some annoyances.


  • Added a guide for rbenv.
  • Added a guide to install zsh and oh-my-zsh

This is very nice, thanks for posting it! I agree, the Creators update has gotten WSL so close to being perfect.

Being able to run Windows apps was one of the main deterrents I had experienced with it previously and kept me using Cmder (personal preference, but it’s awesome, and I am actually using WSL via Cmder so I can still have multiple windows, etc).

Only gotcha I’ve ran into now is vagrant ssh, I’m experiencing the same issue as Jeff Geerling: https://www.jeffgeerling.com/blog/2017/using-ubuntu-bash-windows-creators-update-vagrant

I’m betting that there will be a solution for that soon enough as well.


I think I ran into another small issue which I’m surprised I can’t find anyone talking about on Google.

I was unable to use BrowserSync due to /etc/hosts not being in sync with Windows’ host file so when it goes to proxy my internal host for my Trellis box, it’s unable to resolve it.

cat /mnt/c/Windows/System32/drivers/etc/hosts | grep 192.* | sudo tee -a /etc/hosts

I wrote that just now which is a dirty workaround for this. I’m sure it could be made into a script or something to be included in a ~/.bashrc or ~/.zshrc – but I’m more so curious on any of your guys’ take on a more sane solution?

1 thing to consider is by default, WSL’s /etc/hosts resets it’s self to default when a new instance is made. See Issue #398 on the BashOnWindows repo.

This can be rectified by removing:

# This file was automatically generated by WSL. To stop automatic generation of this file, remove this line.

at the top of the /etc/hosts file.

Another thing to note is this has been brought up as an Issue, but doesn’t seem to of been escalated or pushed in any way. See: Issue #149.

Another small thing to watch for is:

Couldn't open browser (if you are using BrowserSync in a headless environment, you might want to set the open option to false)

I was able to fix this by adding, in my case, Firefox to Windows PATH and then setting:

browser: 'firefox.exe'

in BrowserSync’s options.

Edit: Looks like this is being worked on internally.


Added a few more simple guides for installing zsh and rbenv.

If anyone has any other suggestions, let me know.

Thanks a bunch for this guide!

It looks like Vagrant recently merged full support for running vagrant native inside WSL. :slight_smile:

Thanks for this, was just trying to get Browsersync working and this is a quick fix. Hopefully WSL will sync or at least update from the Windows hosts file eventually.

I’m working on a rewrite of this guide including setting up Valet for seamless development on Windows using Acrylic DNS to manage wildcard hosts (i.e. *.dev automatically pointing to localhost and resolving with no extra setup). It’s a breath of fresh air in the Windows world.

Stay tuned.


just curious but why is the only way to install php 7.1 via some random git repository??

Ondřej just happens to run the official unofficial repository for PHP and has for years. Ubuntu is not a bleeding edge distro thus its packages are usually out of date to maintain “stability”.

An alternative would be to use a distro like Arch Linux for your subsystem instead.


hm… but windows automatically installed ubuntu -.- i did manage to get php 7 via sudo apt-get install php

Yes, Ubuntu is the default. It’s a sensible default…

the process was automatically handled by windows, though. how could have i installed a different distro?

how come linux files aren’t updated after creating a symbolic link to a windows folder and updating files on windows? how can i achieve this?

We really appreciate when someone takes time to create a guide for Roots users here. However, this forum isn’t for general debugging or general questions, we do want to keep it Roots focused. Questions about how to use WSL separate from WordPress and web development would be much better asked and answered on WSL support forums.

Can you point me in the right direction? Where can I find those forums? It’s been so incredibly difficult finding any relevant information via Google.




thanks!! i will be bookmarking your post. i figured out what the issue was. for some reason i could not include a dash in the filename of a CSS file which was referenced by a PHP file, otherwise modifications to the CSS file would not show up in the browser :confused:

Thank you so much for this. It helped me install composer and php. But when I was using composer install, it was working really slowly, saying it couldn’t find zip extension or unzip, so I added php-zip and unzip for it to run MUCH more smoothly!

sudo apt-get install php7.2 php7.2-mbstring php7.2-xml php7.2-zip
sudo apt-get install unzip

I had another issue with node, when I used ‘npm start’ it couldn’t find the node-sass library. I think it wasn’t in /usr/bin and that was causing an issue. Using these commands (in this github comment) helped me resolve it.

Thank you again for providing this because it got me the furthest of anything I have found up to now. I’m running!

I am running Docker (Toolbox) now on WSL, so I don’t need any Virtual Machine for development right now (well, technically the Docker Toolbox uses a VM internally (boot2docker)).


Further notes: