Instructions on building a server with Docker and Nginx on Ubuntu trusty 14.04. (old & depreciated)

Clone this repo:


  1. c136c96 jfrazelle -> jessfraz by Jess Frazelle · 7 months ago master
  2. 615c006 update by Jessie Frazelle · 2 years, 8 months ago
  3. 09ed556 update readme by Jessie Frazelle · 2 years, 8 months ago
  4. 25c7b6d update because i will reference this in talk by Jessica Frazelle · 2 years, 8 months ago
  5. 0666f91 Merge branch 'master' of by Jessica Frazelle · 2 years, 11 months ago

Docker Presentation

This is a repository holding instructions on building a server like the one used in my presentation at BrooklynJS on March 20th, 2014. You can find my slides here:

When you are all finished reading this and understand the build and rundocker commands, checkout the scripts directory. I sealed all this up in a bow for you.

  • setup-nginx: sets up the main nginx config with the apps-enabled directory
  • build-images: builds the base images
  • run-apps: spins up all the containers for the apps and routes them accordingly with publish

But, I would highly suggest looking these over and seeing how they work, there's some fun things with grep and awk.


I have included a Vagrantfile for a VirtualBox with ubuntu trusty 14.04. It will also provision nginx, & docker for you on the first vagrant up.

You have one of two options for setup:

Using the included Vagrantfile

This is the easiest route. Just make sure you have VirtualBox and Vagrant installed.

# bring the server up
# the first time you run vagrant up it provisions the box
# so it takes about 10 min
$ vagrant up
$ vagrant ssh

Installing VirtualBox

VirtualBox is a general-purpose full virtualizer for x86 hardware, targeted at server, desktop and embedded use.

Installation via homebrew cask:

$ brew tap phinze/homebrew-cask
$ brew install brew-cask
$ brew cask install virtualbox

If you don't use homebrew cask, you can install VirtualBox via the VirtualBox website.

Installing Vagrant

Vagrant is a tool for building complete development environments. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases development/production parity, and makes the “works on my machine” excuse a relic of the past.

Installation via homebrew cask:

$ brew cask install vagrant

If you don't use homebrew cask, you can install Vagrant via the Vagrant website.

Vagrant Completions (optional, but helpful nonetheless): Add autocomplete for Vagrant to bash completion.

$ brew tap homebrew/completions
$ brew install vagrant-completion

Then just add the following to your .bash_profile to source the completions:

[ -f `brew --prefix`/etc/bash_completion.d/vagrant ]; source `brew --prefix`/etc/bash_completion.d/vagrant

If you want to roll your own

I have included, which will install nginx and docker.

$ sudo ./

Installing linux kernel 3.8 on precise

If using ubuntu 12.04 (precise) you will need to upgrade the kernel, if you are on trusty 14.04, skip this.

Don't know your kernel version? Just type uname -a in the command line and it will return it for you.

To quote the docker docs:

Due to a bug in LXC, Docker works best on the 3.8 kernel. Precise comes with a 3.2 kernel, so we need to upgrade it. The kernel you’ll install when following these steps comes with AUFS built in. We also include the generic headers to enable packages that depend on them, like ZFS and the VirtualBox guest additions. If you didn’t install the headers for your “precise” kernel, then you can skip these headers for the “raring” kernel. But it is safer to include them if you’re not sure.

# install the backported kernel
$ sudo apt-get update
$ sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring

# reboot
$ sudo reboot

Build Base Images

A base image is what docker pulls from to start the build. You can find trusted base images in the docker index. Now for this I have already created a slew of dockerfiles that we will create base images from in the apps directory.

If you ssh into the vagrant box with the Vagrantfile provided, the directories are synced and these should be located at /var/presentation/apps in your vagrant box. Included in the directory are extremely minimal Dockerfiles for node, python, ruby, and go.

This is a great reference on caching and best parctices: Docker Best Practices.

NOTE: For the purposes of this I have seperate dockerfiles, but in a perfect world you would have images based off languages. Then in other dockerfiles that use that language you can import FROM lang/base. Like the example in my slides. Since the cache works from the top to the bottom you want all the similar things that most dockerfiles have at the top and then the volatile changes at the bottom.

docker build

To build the base images, we are going to use the docker build command. More info

Options we are using:

  • --rm: Remove intermediate containers after a successful build
  • -t <tag-name>: Repository name (and optionally a tag) to be applied to the resulting image in case of success
$ cd /var/presentation/apps


$ sudo docker build --rm -t node/base node/

with sqlite3

$ sudo docker build --rm -t ghost/base blog/


$ sudo docker build --rm -t python/base python/


$ sudo docker build --rm -t ruby/base ruby/


$ sudo docker build --rm -t golang/base go/

View your images

$ sudo docker images

If you see any images named <none>, run sudo docker rmi $(sudo docker images | grep "^<none>" | awk "{print $3}") to remove untagged images.

Other Helpful commands: To stop all docker containers run sudo docker stop $(sudo docker ps -a -q), and to remove all docker containers run sudo docker rm $(sudo docker ps -a -q).

Setup nginx

We are going to want to create proxy redirects on the fly so we are going to replace the default nginx config files with our own.

$ sudo rm -rf /etc/nginx
$ sudo mkdir /etc/nginx
$ sudo cp -r /var/presentation/nginx/* /etc/nginx/

# restart nginx
$ sudo service nginx restart

Run Apps

docker run

The docker run command first creates a writeable container layer over the specified image, and then starts it using the specified command. More info

Options we are using:

  • -d: Detached mode: Run container in the background, print new container id
  • --name <name>: Assign the specified name to the container. If no name is specific docker will generate a random name
  • -p <port>: Map a network port to the container


hello world example

$ sudo docker run --name node_hello_world -p 3000 -d node/base
$ sudo /var/presentation/scripts/publish node<port>

ghost blog example

$ sudo docker run --name node_ghost -p 3000 -d ghost/base
$ sudo /var/presentation/scripts/publish blog<port>


$ sudo docker run --name python_hello_world -p 5000 -d python/base
$ sudo /var/presentation/scripts/publish python<port>


$ sudo docker run --name ruby_hello_world -p 4567 -d ruby/base
$ sudo /var/presentation/scripts/publish ruby<port>


$ sudo docker run --name go_hello_world -p 8080 -d golang/base
$ sudo /var/presentation/scripts/publish go<port>