Man sitting on top of container with green circle with a power up icon

Using the NGINX Docker image

Matthew Casperson

Docker is a compelling platform to package and run web applications, especially when paired with one of the many Platform as a Service (PaaS) offerings provided by cloud platforms. NGINX has long provided DevOps teams with the ability to host web applications on Linux, and also provides an official Docker image to use as the base for custom web applications.

In this post, I explain how DevOps teams can use the NGINX Docker image to build and run web applications on Docker.

Getting started with the base image

NGINX is a versatile tool with many uses, including a load balancer, reverse proxy, and network cache. However, when running NGINX in a Docker container, most of these high level functions are delegated to other specialized platforms or other instances of NGINX. Typically, NGINX fulfils the function of a web server when running in a Docker container.

To create an NGINX container with the default web site, run the following command:

docker run -p 8080:80 nginx

This command will download the nginx image (if it hasn't already been downloaded) and create a container exposing port 80 in the container to port 8080 on the host machine. You can then open http://localhost:8080/index.html to view the default "Welcome to nginx!" web site.

To allow the NGINX container to expose custom web assets, you can mount a local directory inside the Docker container.

Save the following HTML code to a file called index.html:

<html>
    <body>
        Hello from Octopus!
    </body>
</html>

Next, run the following command to mount the current directory under /usr/share/nginx/html inside the NGINX container with read only access:

docker run -v $(pwd):/usr/share/nginx/html:ro -p 8080:80 nginx

Open http://localhost:8080/index.html again and you see the custom HTML page displayed.

One of the benefits of Docker images is the ability to bundle all related files into a single distributable artifact. To realize this benefit, you must create a new Docker image based on the NGINX image.

Creating custom images based on NGINX

To create your own Docker image, save the following text to a file called Dockerfile:

FROM nginx
COPY index.html /usr/share/nginx/html/index.html

Dockerfile contains instructions for building a custom Docker image. Here you use the FROM command to base your image on the NGINX one, and then use the COPY command to copy your index.html file into the new image under the /usr/share/nginx/html directory.

Build the new image with the command:

docker build . -t mynginx

This builds a new image called mynginx. Run the new image with the command:

docker run -p 8080:80 mynginx

Note that you didn't mount any directories this time. However, when you open http://localhost:8080/index.html your custom HTML page is displayed because it was embedded in your custom image.

NGINX is capable of much more than hosting static files. To unlock this functionality, you must use custom NGINX configuration files.

Advanced NGINX configuration

NGINX exposes its functionality via configuration files. The default NGINX image comes with a simple default configuration file designed to host static web content. This file is located at /etc/nginx/nginx.conf in the default image, and has the following contents:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

There's no need to understand this configuration file in detail, but there is one line of interest that instructs NGINX to load additional configuration files from the /etc/nginx/conf.d directory:

include /etc/nginx/conf.d/*.conf;

The default /etc/nginx/conf.d file configures NGINX to function as a web server. Specifically the location / block loading files from /usr/share/nginx/html is why you mounted your HTML files to that directory previously:

server {
    listen       80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

You can take advantage of the instruction to load any *.conf configuration files in /etc/nginx to customize NGINX. In this example you add a health check via a custom location listening on port 90 that responds to requests to the /nginx-health path with a HTTP 200 OK.

Save the following text to a file called health-check.conf:

server {
    listen       90;
    server_name  localhost;

    location /nginx-health {
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
}

Modify the Dockerfile to copy the configuration file to /etc/nginx/conf.d:

FROM nginx
COPY index.html /usr/share/nginx/html/index.html
COPY health-check.conf /etc/nginx/conf.d/health-check.conf

Build the image with the command:

docker build . -t mynginx

Run the new image with the command. Note the new port exposed on 9090:

docker run -p 8080:80 -p 9090:90 mynginx

Now open http://localhost:9090/nginx-health. The health check response is returned to indicate that the web server is up and running.

The examples above base your custom images on the default nginx image. But there are other variants that provide much smaller image sizes without sacrificing any functionality.

Choosing NGINX variants

The default nginx image is based on Debian. However, NGINX also provides images based on Alpine.

Alpine is frequently used as a lightweight base for Docker images. To view the sizes of Docker images, they must first be pulled down to your local workstation:

docker pull nginx
docker pull nginx:stable-alpine

You can then find the image sizes with the command:

docker image ls

From this you can see the Debian image weighs around 140 MB while the Alpine image weighs around 24 MB. This is quite a saving in image sizes.

To base your images on the Alpine variant, you need to update the Dockerfile:

FROM nginx:stable-alpine
COPY index.html /usr/share/nginx/html/index.html
COPY health-check.conf /etc/nginx/conf.d/health-check.conf

Build and run the image with the commands:

docker build . -t mynginx
docker run -p 8080:80 -p 9090:90 mynginx

Once again open http://localhost:9090/nginx-health or http://localhost:8080/index.html to view the web pages. Everything continues to work as it did previously, but your custom image is now much smaller.

Conclusion

NGINX is a powerful web server, and the official NGINX Docker image allows DevOps teams to host custom web applications in Docker. NGINX also supports advanced scenarios thanks to its ability to read configuration files copied into a custom Docker image.

In this post, you learned how to create a custom Docker image hosting a static web application, added advanced NGINX configuration files to provide a health check endpoint, and compared the sizes of Debian and Alpine NGINX images.

Learn how to use other popular container images:

Resources

Learn more

If you want to build and deploy containerized applications to AWS platforms such as EKS and ECS, try the Octopus Workflow Builder. The Builder populates a GitHub repository with a sample application built with GitHub Actions workflows and configures a hosted Octopus instance with sample deployment projects demonstrating best practices such as vulnerability scanning and Infrastructure as Code (IaC).

Happy deployments!

Loading...