Earlier this year Microsoft, with support from Canonical, released the Linux subsystem for Windows 10, which allows a user to install an Ubuntu image.
This is said not to be a container, nor a full VM, but the Ubuntu user-mode image running on the Windows kernel. How you ask? Read the How It Works section of this article on Linux.com. There are countless articles out there about this, so any explanation I can give will be vastly inferior to any already out there. Essentially however this is Ubuntu running on the Windows kernel natively.
The outcome of that is an environment where a lot of your common development tools work across Ubuntu to Windows. Your Windows drives are mounted into your Ubuntu environment under /mnt/. So you can navigate around your file system from Bash, giving you most of the power of Ubuntu nativley on Windows.
If you also want to access your Ubuntu file system from Windows you can, and that’s located by default in C:\Users\\AppData\Local\lxss. However, not everything is available there, for example you won’t find a folder called etc, but things like home exist.
Installation & Setup
There are detailed instructions on how to install and setup Bash for Windows here, and in numerous other articles out there in the wild, however what it essentially boils down to is:
- Ensure you have the Windows 10 Anniversary update
- Ensure you have Use developer features: Developer mode on
- Enable the Windows Subsystem for Linux (Beta) in your Windows Features
- Run bash.exe, answer questions, wait for download/install
- Run Bash on Ubuntu on Windows
Useful Tools & Programs
Installing packages in Bash for Windows is very straight forward, because it’s running the full Ubuntu image you can use apt-get to install many things, and dpkg to install other packages you’ve manually downloaded.
If you’re managing servers from Windows, as either a sysadmin or dev ops, you’ll most likely have at least one or two servers running Linux, or perhaps a nest of Raspberry Pi’s, that have to be accessed via SSH. In the days before Bash for Windows you’d most likely be using PuTTY or similar. Now you can SSH natively from one Linux system to another, with no special configurations to be made.
What’s really good about this is how easy it is to set up private/public SSH keys. Although PuTTY does support SSH agents, they never seemed to play well with other software using SSH keys, see next section about git. Because Bash for Windows is running a full Ubuntu environment you can generate or import an existing private key and use that when attempting to make connections.
If you’re importing a private key from putty you’ll need to convert it to the openssh format, which can be done fairly easily by importing it back into PuTTYgen and re-exporting it for openssh. Then place the openssh private key file at ~/.ssh/id_rsa with the public key at ~/.ssh/id_rsa.pub within your Ubuntu environment.
As most private keys are encrypted you’ll need to decrypt your key every time you wish to use it, although you can make this easier by adding the decrypted key to your agent as you log in to Bash. This can be acheived by adding the following script to the end of your ~/.bashrc file:
if [ -z "$SSH_AUTH_LOCK" ] ; then eval `ssh-agent -s` ssh-add fi
This script is executed every time you log into Ubuntu, so for as long as you keep the Bash window open in Windows your key will remain decrypted for you use inside your SSH agent.
Although there are many GUI tools for Windows that allow users to work very well with git, I opted to use the terminal version. This was mostly because it made me have to understand the processes behind git: the two stage approach to source control, branching models, merge conflicts, etc. I also found when I used to use SVN I had to use command line to effectively resolve tree conflicts. Using git in terminal also helped when having to build things on the Raspberry Pi themselves.
One of the major benefits of using git within Bash for Windows though is the seamless integration with SSH keys. Previously I had managed to get Windows to accept my SSH agent using plink and pageant, however I only got it working once and it was a real quest to do it.
In Bash for Windows you generate or import your private key as described in the previous section, ensure you git repository is using the SSH URL and not the HTTP/HTTPS URL, then git pull. This may ask you to confirm the address, and add it to a known hosts file, and it may ask you to decrypt your private key. No more password authentication against the repository, and if you decrypt your key on login for Bash then you eliminate even more password entries.
Personally I find this process allows me to develop a lot easier, particularly on a project that’s moving very quickly with a large number of people where you’re required to pull, push and branch frequently.
nodejs, et al.
Finally NodeJS, which is more a nod towards the kind of programs you can run via Bash on Windows rather than just NodeJS. I’ve used node a little bit on Windows, and every time it’s been via git bash, which is just a way around not having Bash on Windows. With that in mind I decided to cut out the middle-man and install node in Ubuntu and use it via Bash for Windows.
The program I was running was a web server using Express, and surprisingly there were no firewall issues running it in Ubuntu and accessing it via a browser in Windows on the same machine.
Other packages, such as NPM, gulp, etc., seem to work within seamlessly Ubuntu. Perhaps these worked just as well in Windows, but from my experience I’ve always had to work around things a little bit to get them running on Windows. I’ve found myself moving more and more of my development pipeline into Bash for Windows, and it’s made my development process so much easier.
For details on how to install NodeJS for Linux, check out my previous post about installing it on the Raspbian: it’s exactly the same process.
So far there have been a few issues found, most of which are covered in Microsoft’s FAQ. The biggest issue I’ve found so far was a task that wouldn’t stop running, and wouldn’t let me log back in, even after I restarted the physical machine. I addressed this by reinstalling Bash for Windows.
lxrun /uninstall lxrun /install
Running the above commands in Windows command prompt should sort out your issues, this also left the file system and configuration intact.