Using LXD Containers Instead of VMs For Web Development

I’ve been dabbling with Canonical’s LXD containers ever since 1.0, but found it more difficult to use than Virtual Box. With the 2.0 release, a lot of the pain-points have been ironed out, so I decided to give it another try. Before you say, “What about Docker?” I would say you’re right, that does exist, but I have not spent enough time working with Docker, and wouldn’t feel comfortable putting it into production. With LXD, you can treat the container much like you would a virtual machine. So if you plan on deploying on Virtual Private Server or Virtual Machine, you can replicate the production environment pretty well.

Use Case

I have a few Django apps in production right now, and have also built some test APIs using MongoDB. When ever I do web development work, I try to replicate a real server as much as possible. The problem is that I am kind of a neat freak when it comes to my filesytem services. I don’t like having database and web services running while I’m just anwsering emails. In the past, I have used a Raspberry Pi for this, but the performance is not as great as my laptop. This is why I sought out containerization. I can spin up a server on my powerful laptop, play around, then destroy it and all the data and services go kaboom.

How I did it

The first thing to do is just install lxd from the repo. I’m using Ubuntu 17.04, so everything is just works out of the box. I followed the prompts to enable a network bridge so that I could access the container IP addresses in my web browser. I pretty much followed the instructions in this blog and the official docs. I decided to create two containers, one to be used for a postgres server and another to be used as a web server for my Django app.

First, I created a 16.04 container for postgres with:

lxc launch ubuntu:16.04 xenial-postgres

This caused LXD to go get the official Ubuntu 16.04 image from, then create a container with the alias of xenial-postgres. I then ran:

lxc exec xenial-postgres bash

This allowed me to start a bash session as root inside of the container. I then went through my regular processes to install postgres. I created the database and database user, then updated the configuration to allow all hosts on the container’s subnet to access the database (use ip addr on the host and look for lxdbr0). Not the most secure way to do it, but good enough for my local machine. After exiting the container’s shell, I ran:

lxc launch ubuntu:16.04 xenial-web

This time, the container was created in under a minute, since the template image is already cached. I lxc exec ... bash into this container and install git, nginx, etc. Then I ran into an issue. I already have the the git project on the host, so why would I want to download them again? From here, I started DuckDuckGo searching away and found you can share directories from the host to the containers, but there are permission issues (directory in the container not writable, owned by nobody user). From what I researched, I found this gist and it worked like a charm. It’s probably not a production-ready solution, but it makes using LXD for development a good experience.

From there, I ran lxc image list, which lists all installed containers as well as their IP addresses. If I’ve set up Nginx correctly, I should be able enter the web server’s IP adress in my browser and test my installation.


I recommend trying out LXD for development projects. They are lighter weight than virtual machines, but easy to use if you are familiar with the Linux shell. There are even Ansible hooks to automate LXD container deployments for production.