Nginx Proxy on Docker Cloud

2016/02/21

This weekend, I’ve been playing with nginx-proxy using Docker Cloud, a rebranded container cloud service which was formerly known as Tutum.

I’ve been using Digital Ocean as my cloud provider as Docker Cloud will give you $20 free credit to use with them for signing up. If you sign up to Digital Ocean using the above referral link, you will also receive an additional $10 credit.

nginx-proxy is a Docker container that will transparently proxy any of your Docker containers and publish them under a virtualhost as defined in a VIRTUAL_HOST variable which can be specified on any container you wish to proxy.

As an added bonus, we can use nginx-letsencrypt-proxy which will automatically provision SSL certificates from Lets Encrypt for each of the containers virtual hosts. The SSL certificates are renewed every hour from Lets Encrypt to prevent them from expiring.

So lets get started…

Docker Cloud offer a web-based user interface and a command line tool. The majority of this tutorial will be carried out using the command line tool. To install the tool, run pip install docker-cloud, preferably within a virtualenv.

Once installed, we need to create a Docker Cloud configuration file. Currently, the default filename for this is still tutum.yml. So, create and open this file for editing.

The first thing we need is a volume container to temporarily contain generated Lets Encrypt certificates. This doesn’t have to be persisted or backed up as the certificates are regenerated automatically at regular intervals. As you can see, our volume container is called volume-certs and contains the path /etc/nginx/certs.

volume-certs:
    image: ubuntu
    mem_limit: 64m
    volumes:
        - "/etc/nginx/certs"
    command: "/bin/true"

The next step is to create another volume container to hold some configuration and templates that are required by the nginx-proxy container. As this volume container always needs to contain the same static content, I created a separate container for this which I linked to Docker Cloud. This means that the container is automatically built when the repository is updated.

This new volume container is then added to our tutum.yml configuration file to ensure it is created with the rest of our stack.

volume-nginx-proxy-config:
    image: jinglemansweep/nginx-proxy-configuration
    mem_limit: 64m
    command: "/bin/true"

We now need to setup the nginx-proxy containers. There are two containers, one is just a standard nginx container which performs the reverse proxying. This container use volumes from our next container, docker-gen, as well as our temporary certifcate volume container volume-certs we configured earlier.

The docker-gen container is special in that it has access to the host machines Docker socket so can monitor when containers are started and stopped. When it detects a change, it regenerates the Nginx configuration automatically using the templates specified in our nginx-proxy-configuration container.

nginx-proxy:
    image: nginx
volumes_from:
    - volume-certs
    - volume-nginx-proxy-config
ports:
    - "80:80"
    - "443:443"

nginx-gen:
    image: jwilder/docker-gen
    volumes:
        - "/var/run/docker.sock:/tmp/docker.sock:ro"
    volumes_from:
        - nginx-proxy
        - volume-nginx-proxy-config
    command: "-notify-sighup nginx -watch -only-exposed -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf"

If you want to automatically provide SSL certificates for your containers using Lets Encrypt, we will need to configure one more container. The nginx-letsencrypt-proxy container creates the required domain authorisation material required by Lets Encrypt’s validation system and publishes it to the main nginx-proxy container via a shared volume container.

You will have to specify the container ID of your docker-gen container using the NGINX_DOCKER_GEN_CONTAINER environment variable, which is nginx-gen in this example. This container automatically configures the Lets Encrypt validation material whenever a container is started, hence the need for using the host machines Docker socket again.

nginx-letsencrypt-proxy:
    image: jrcs/letsencrypt-nginx-proxy-companion
    environment:
        - "NGINX_DOCKER_GEN_CONTAINER=nginx-gen"
    volumes:
        - "/var/run/docker.sock:/var/run/docker.sock:ro"
    volumes_from:
        - nginx-proxy

That is most of the configuration done. The only additional steps is to add containers that you want to be reverse-proxied by Nginx to a given domain/sub-domain and secured via SSL. In this example, we are just using another default Nginx container.

Any container you want reverse-proxied requires its ports to be exposed using EXPOSE and not PORTS. It also requires three environment variables. The first (VIRTUAL_HOST) is the domain/sub-domain that Nginx will use to proxy that container. The next two (LETSENCRYPT_HOST and LETSENCRYPT_EMAIL) are used for automatically generating our SSL certificates. Generally, the VIRTUAL_HOST and LETSENCRYPT_HOST variables should contain the same value.

nginx-website: 
    image: nginx
    environment:
        - "VIRTUAL_HOST=cloud.louisking.xyz"
        - "LETSENCRYPT_HOST=cloud.louisking.xyz"
        - "LETSENCRYPT_EMAIL=jinglemansweep@gmail.com"
    expose:
        - "80"
        - "443"

Now we have configured all our containers, we can use the docker-cloud command line too to provision our stack. The first thing to do is to login to Docker Cloud using the standard docker login command. Once you have done this, Docker Cloud will work using your account.

We’ll navigate to where our tutum.yml file is and create our stack:

docker-cloud stack up

Source code for my full Docker hosting setup can be found on GitHub.

That’s it for now. More to follow soon.

Post Directory