Tips for Deploying NGINX (Official Image) with Docker

In the past year alone, the Docker community has created 100,000+ images and over 300+ million images have been pulled from Docker Hub to date. Over 20 million of these pulls came from the 70+ Official Images that Docker develops in conjunction with upstream partners, like Oracle, CentOS, and NGINX.

NGINX is used by over 40% of the world’s busiest websites and is an open-source reverse proxy server, load balancer, HTTP cache, and web server. The official image on Docker Hub has been pulled over 3.4 million times and is maintained by the NGINX team. This post from NGINX provides a walkthrough on using the Docker Image to deploy the open-source version of NGINX.

Attend the webinar titled “Building Applications with Microservices and Docker”

To create an instance of NGINX in a Docker container, search for and pull the NGINX official image from Docker Hub. Use the following command to launch an instance of NGINX running in a container and using the default configuration.

This command creates a container named mynginx1 based on the NGINX image and runs it in detached mode, meaning the container is started and stays running until stopped but does not listen to the command line. We will discuss later how to interact with the container.

The NGINX image exposes ports 80 and 443 in the container and the -P option tells Docker to map those ports to ports on the Docker host that are randomly selected from the range between 49153 and 65535. We do this because if we create multiple NGINX containers on the same Docker host, we create a conflict on ports 80 and 443. The port mappings are dynamic and are set each time the container is started or restarted. If you want the port mappings to be static, set them manually with the -p option. The long form of the Container Id will be returned.

We can run docker ps to verify that the container was created and is running, and to see the port mappings:

We can also verify that NGINX is running by making an HTTP request to port 49167 (reported in the output from the preceding command as the port on the Docker host that is mapped to port 80 in the container); the default NGINX welcome page appears:

Now that we have a working NGINX Docker container, how do we manage the content and the NGINX configuration? And what about logging? It is common to have SSH access to NGINX instances, but Docker containers are generally intended to be for a single purpose (in this case running NGINX) so the NGINX image does not have OpenSSH installed and for normal operations there is no need to get shell access directly to the NGINX container. We will use other methods supported by Docker. For a detailed discussion of alternatives to SSH access, see Why you don’t need to run SSHd in your Docker Containers.

Managing Content and Configuration Files

There are multiple ways you can manage the NGINX content and configuration files and we will cover a few options:

Maintain the Content and Configuration on the Docker Host

When the container is created we can tell Docker to mount a local directory on the Docker host to a directory in the container. The NGINX image uses the default NGINX configuration, so the root directory for the container is/usr/share/nginx/html and the configuration files are in /etc/nginx. If the content on the Docker host is in the local directory /var/www and the configuration files are in /var/nginx/conf, we run the command:

Now any change made to the files in the local directories /var/www and /var/nginx/conf on the Docker host are reflected in the directories /usr/share/nginx/html and /etc/nginx in the container. The :ro option causes these directors to be read only inside the container.

Copy the Files from the Docker Host

Another option is to have Docker copy the content and configuration files from a local directory on the Docker host when a container is created. Once a container is created, the files are maintained by creating a new container when the files change or by modifying the files in the container. A simple way to copy the files is to create a Dockerfile to generate a new Docker image, based on the NGINX image from Docker Hub. When copying files in the Dockerfile, the path to the local directory is relative to the build context where the Dockerfile is located. For this example, the content is in the content directory and the configuration files are in the conf directory, both in the same directory as theDockerfile. The NGINX image has the default NGINX configuration files, including default.conf and example_ssl.conf in/etc/nginx/conf.d. Since we want to use the configuration files from the host, we include commands in the followingDockerfile to delete the default files:

We can then create our own NGINX image by running the following command from the directory where the Dockerfileis located:

# docker build -t mynginximage1.

Note the period (“.”) at the end of the command. This tells Docker that the build context is the current directory. The build context contains the Dockerfile and the directories to be copied. Now we can create a container using the image by running the command:

# docker run --name mynginx3 -P -d mynginximage1

If we want to make changes to the files in the container, we use a helper container as described below.

Maintain Files in the Container

As mentioned previously, we are not able to get SSH access to the NGINX container, so if we want to edit the content or configuration files directly we can use a helper container that has shell access. In order for the helper container to have access to the files, we must create a new image that has the proper volumes specified for the image. Assuming we want to copy the files as in the example above, while also specifying volumes for the content and configuration files, we use the following Dockerfile:

This creates an interactive container named mynginx4_files that runs in the foreground with a persistent standard input (-i) and a tty (-t) and mounts all the volumes defined in the container mynginx4 as local directories in the newmynginx4_files container. This container uses the Debian image from Docker Hub, which is the same operating system used by the NGINX image. Since all of the examples shown so far use the NGINX image and therefore Debian, it is more efficient to use Debian for the helper container rather then having Docker load another operating system. After the container is created, it runs the bash shell, which presents a shell prompt for the container that you can use to modify the files as needed. You can also install other tools, such as Puppet or Chef, in the container to manage these files. If you exit the shell by running the exit command, the container terminates. If you want to exit while leaving the container running, use Control-p followed by Control-q. The container can be started and stopped with the following commands:

# docker start mynginx4files

and

# docker stop mynginx4files

Shell access can be regained to a running container with the command:

# docker attach mynginx4files

Managing Logging

Default Logging

The NGINX image is configured to send the main NGINX access and error logs to the Docker log collector by default. This is done by linking them to stdout and stderr, which causes all messages from both logs to be stored in the file/var/lib/docker/containers/\<container id\>/\<container id\>-json.log on the Docker Host. \<container id\> is the long-form Container Id returned when you create a container. You can display the long-form Id for a container with the command:

# docker inspect --format '{{ .Id }}' <container name>

You can use both the Docker command line and the Docker Remote API to extract the log messages. From the command line run the command:

# docker logs <container name>

To enable the Docker Remote API, add the following line to the file /etc/default/docker:

DOCKEROPTS='-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock'

When Docker is restarted, it listens for HTTP API requests on port 4243 (you can specify a different port) and also on a socket. To get all the messages, you can issue the GET request:

To include only access log messages in the output, include only stdout=1; to limit the output to error log messages, include only stderr=1. To learn about other available options, see the Docker documentation.

Customized Logging

If you want to implement another method of log collection, or if you want to configure logging differently at various levels in the NGINX configuration (such as servers and locations), you can use a volume for the directory or directories in which to store the log files in the container. You can then use a helper container to access the log files and use whatever logging tools you like. To implement this, create a new image that contains the volume or volumes for the logging files. For example, to configure NGINX to store log files in /var/log/nginx/log, we start with the Dockerfile shown in the earlier example of copying files from the Docker host to the container and simply add a volume declaration for this directory:

We can then create an image as described above and using this image create an NGINX container and a helper container that have access to the log directory. This helper container can have any desired logging tools installed.

Controlling NGINX

Since we do not have access to the command line of the NGINX container directly, we cannot use the nginx command to control NGINX. Fortunately NGINX can be controlled by signals and Docker provides kill command for sending signals to a container. For example, to reload the NGINX configuration run the command:

docker kill -s HUP <container name>

If you want to restart the NGINX process, restart the container by running the command:

docker restart <container name>

Summary

NGINX and Docker are tools that work extremely well together. By using the NGINX open-source image from the Docker Hub repository, you can easily spin up new instances of NGINX in Docker containers. You can also take these images and easily create new Docker images from them to give you even more control of your containers and how you manage them.

Tips for Deploying NGINX (Official Image) with Docker

Our web site code is open on GitHub and provides an example of building a new container from the nginx base image & deployment on CoreOS. If you’re interested, here is the github repo: https://github.com/mailsquad/website

This tutorial is indeed a big help for me personally. Glad to know everything about it now after spending time researching about it. I know a lot better now because of the step by step tutorial you’ve shared. And thanks for giving some input and tips as well for deploying images with docker.

Amandeep

Hi,
I have query regarding helper container.
I have created a nginx container from custom docker image exposing port 80 and 443 and few volumes also and one helper container named nginx4files where nginx.conf is mounted automatically.
Problem statement -: from nginx4files container, i have modified the port of nginx from 80 to 8085 and reload the nginx configuration using nginx -s reload command. I checked the nginx.conf file in nginx container which is getting updated as well but when i am running docker ps the changed port (80 to 8085)is not getting mapped to host dynamic port. Therefore, even container is running, i am not able to access nginx landing page from host system. Please advise, do i need to stop the nginx container to reflect the configuration of i am missing something here.

This tutorial is very a big help. Through this we can then create an image as described in this page and using this image create an NGINX container and a helper container that have access to the log directory.

jeremy rutman

I followed this blog's instructions but wind up with a server that shows only the 'wecome to nginx ' splash page – no changes to /var/www seem to get seen . I used docker run –name mynginx2 -v /data/www:/usr/share/nginx/html:ro -v /var/nginx/conf:/etc/nginx:ro -p8090:80 -d nginx and also without -d flag to no avail ( my web content is in /data/www)

restarting the container is not advisable when you initialize Docker Swarm because it may remove the nginx service. So if you need an alternative aside docker restart; You can go inside the container and just run nginx -s reload