How to setup a LEMP server inside a Docker.IO Container

updated August 7th, 2013 incorporating fixes by Mr. Chizzlebear.

Docker is awesome. There are great explanations of what it is and how it works in this awesome collection of quotes.

In this tutorial, we will setup a self-contained LEMP (GNU/Linux, Nginx, MariaDB, PHP-FPM) stack inside a minimalist Ubuntu 12.04 container.

Note: I’m new to Docker too, so if you have any tips or links to other tutorials, leave them in a comment!

If you do not already have installed, go ahead and set it up. It’s cool, I’ll give you 5 minutes..

Ready? Ok let’s get this show on the road!

The Container

Start a minimal Ubuntu 12.04 (aka “Precise”, an LTS release) image that docker automatically fetches for you:

The Repositories

Great, now we are running a shell inside a container! It has it’s own filesystem, process space, and apps. The minimalist image is pretty bare, so..

Setup repositories with latest nginx (Engine-X, the ‘E’ in LEMP), PHP5 (using FPM), and MariaDB (the trending MySQL fork these days) using signed PPAs. Note: I’m using Ondrej’s builds to get the latest PHP5 support (thanks Ondrej!)

A small patch

The stock image is really bare, so lets install a few utils, and make a tiny fix.

* whiptail – for displaying dialogs in the CLI via perl
* mlocate – to make locate/updatedb work (to quickly find files)
* nano – for simple file edits
* /etc/mtab – a mounted file systems table to make MySQL happy


All together this will add ~170MB to your GNU/Linux container.

Before we do anything else, let’s save the current state of the container.. while it’s running!

Open up another terminal, find the ID of the container, and commit it to a new image!

Well look at that, you just created a container image! This image can be shared with others, and can be extended safely knowing you can always fallback to its original state.

We could continue working in this container, but let’s try something else: shut down the container by exiting its shell.

No containers are running. Yep, it down, including all the processes inside.
We could restart the container and continue where we left off. But instead, lets spawn a new shell (inside a new container) using the new snapshot you just created and finish configuring that way!

Notice how the newly spawned container has a new hostname (representing a new ID).

In git/svn terms, this is like cloning a repository and then working on it, eventually committing your changeset!

Stacking the database

MySQL needs a little loving before it will work inside our container. The default config’s flush-method for InnoDB tables doesn’t like O_DIRECT access to tmpfs, so let’s change it:

After commenting out that line, MySQL should start cleanly.

Now, create a new user and a database catalog for testing.

Great, we have a live running database with some data in it. Let’s get PHP-FPM running and create a site to host using Nginx.

Stacking Nginx

Create the site’s location:

Make the landing page:

With some php that accesses the database:

Then replace nginx’s default config:

with this:

And start your engine!

Stacking PHP-FPM

This is the one component that will work straight out of the box:


Bam! Our self-contained web-server should be up and running. Let’s test it using the lynx command-line browser: (Ah the good old days!)

You should see something like this:
lynx lemp test

16 thoughts on “How to setup a LEMP server inside a Docker.IO Container

  1. Thanks for the post. I found 2 typos in here:

    root@b3f5e7de5ad4:/# echo “deb deb precise main” >> /etc/apt/sources.list
    There you have ‘deb’ twice, resulting in an apt-get error

    And in the PHP file, you’re missing the last semicolumn

  2. Great catches! Thanks Mr. Chizzlebear!

  3. But how do you get the data in mysql to persist? It’s in tmpfs so every time your container goes down you lose the database. What is the ideal way to handle that? nfs mounts to a nas? Thanks!

  4. Pingback: Docker | MÓDOLO

  5. How did you get upstart to work?

    Following your instructions produces these errors:

    initctl: Unable to connect to Upstart: Failed to connect to socket /com/ubuntu/upstart: Connection refused

    I’m running docker 0.6.5 so not sure if there were major changes between then.


  6. I’ve followed your tutorial but wasn’t able to reach the nginx inside the container from the outside, how do you do it?

  7. Pingback: What I’m Reading December 12 | inthecloud247

  8. For those considering Docker, here are three arguments for Docker that are clear benefits and cannot be argued against:

    A) Ability to easily diff containers. It improves debugging, allows faster sharing of the environment, and quicker deployments. This is a big plus and there aren’t any competing solutions.

    B) Ability to debug DevOps (like chef recipes) locally without having to pay the penalty of the slow boot of a VM or AWS instance.

  9. One of our developers is using I am very interested in using docker to set up a nginx fastcgi server with modsecurity and SPDY enabled and a few other optional plugins enabled. I want to run at least version 1.4.7 of nginx. I take it I will have to use wget to get source code into the container’s
    /usr/src and then build from there? Any gotchas to look out for?

  10. Pingback: Docker gebruiken om een testomgeving te creëren - Michael Boumann

  11. Considering this post is a year old and the Docker codebase and community have grown quite a bit, you probably already realize or have discovered this bit I’m about to share. It would be considered bad practice to stack all of these programs into one container because Docker containers operate with a single process. The L in LEMP can be considered your host machine, however, nginx, mysql (mariadb) and PHP should all be managed within their own containers. Its also very possible to host docker within docker so that you could create a container of containers, so-to-speak.

  12. Pingback: Docker gebruiken om een testomgeving te creëren - Michael Boumann Tech

Leave a Reply

Your email address will not be published. Required fields are marked *