WittCode💻

Docker and Nginx

By

Learn how to dockerize and configure Nginx, serve static content, and more using Docker and Docker volumes.

Table of Contents 📖

Creating a Nginx Docker Container

To begin, lets create an Nginx container from the latest version of Nginx using docker run.

docker run --name nginx-c -p 6464:80 nginx
  • Call the container nginx-c using the --name flag.
  • Map port 6464 on our local computer to port 80 in the container.

We map to port 80 in the Nginx container because, by default, Nginx shares static content from the location /usr/share/nginx/html on port 80. We can check this by sending a cURL request to our mapped port.

curl localhost:6464
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

We can see the presence of this HTML file by navigating into the Nginx container and checking the /usr/share/nginx/html directory.

docker exec -it nginx-c sh
ls /usr/share/nginx/html
50x.html  index.html

There is also an HTML file present called 50x.html. This is the default error page that Nginx serves up. We can see the contents of this through a cURL request as well.

curl localhost:6464/50x.html
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>An error occurred.</h1>
<p>Sorry, the page you are looking for is currently unavailable.<br/>
Please try again later.</p>
<p>If you are the system administrator of this resource then you should check
the error log for details.</p>
<p><em>Faithfully yours, nginx.</em></p>
</body>
</html>

Serving Custom Static Content

If we want to serve up our own static content, we just need to copy it into the /usr/share/nginx/html directory. We can do this with volumes. First, lets place the HTML file we want to serve up in a directory called my-static-content.

<h1>Download WittCepter</h1>
<h2>The best chrome extension!</h2>

WittCepter is the name of my Chrome extension, go check it out in the Chrome web store! Now, lets create a volume to place this HTML file in the /usr/share/nginx/html directory.

docker run --name nginx-c -p 6464:80 \ 
-v ./my-static-content:/usr/share/nginx/html/:ro \
nginx

Now lets cURL to get the wittcepter.html file.

curl localhost:6464/wittcepter.html
<h1>Download WittCepter</h1>
<h2>The best chrome extension!</h2>

As this is a volume, we can get live code updates as we make changes. To demonstrate, add another line to the wittcepter.html file and then cURL again.

<h1>Download WittCepter</h1>
<h2>The best chrome extension!</h2>
<h2>It's great at analyzing browser network traffic!</h2>
curl localhost:6464/wittcepter.html
<h1>Download WittCepter</h1>
<h2>The best chrome extension!</h2>
<h2>It's great at analyzing browser network traffic!</h2>

Nginx Configuration

The main configuration file for nginx is called nginx.conf. The location of this file in the Docker container is /etc/nginx/nginx.conf.

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;
}

An important line in the http context is the include declaration. This declaration imports any .conf file inside the conf.d directory into the http context. If we check the conf.d folder, we can see one file inside called default.conf.

server {
  listen       80;
  listen  [::]:80;
  server_name  localhost;

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

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
      root   /usr/share/nginx/html;
  }
}

It is this server context that is responsible for serving up the static content from the /usr/share/nginx/html directory on localhost port 80.

Nginx Custom Configuration

We can add our own custom configuration in a few ways. The easiest would be to import our own nginx.conf file using volumes. However, we can also focus on just adding our own server context by adding our own .conf file to the conf.d directory. For example, lets create a Nginx server context that listens on port 1234.

server {
  listen       1234;
  listen  [::]:1234;
  server_name  localhost;

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

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
      root   /usr/share/nginx/html;
  }
}

Now lets create a volume to bring this file into the Nginx container. Don't forget to change the mapped container port to 1234.

docker run --name nginx-c -p 6464:1234 \ 
-v ./my-static-content:/usr/share/nginx/html/:ro \
-v ./default.conf:/etc/nginx/conf.d/default.conf:ro \ 
nginx

Now sending a cURL to localhost:6464 should map to localhost:1234 in the container but give the same result.

curl localhost:6464/wittcepter.html
<h1>Download WittCepter</h1>
<h2>The best chrome extension!</h2>
<h2>It's great at analyzing browser network traffic!</h2>

As this is a volume, we will get live updates as well. So if we change the default.conf server context port to be 80, it will be reflected in the container as well. However, if we change this port and then cURL inside the container we will get a connection failed.

docker exec -it nginx-c sh
curl localhost:80/wittcepter.html
curl: (7) Failed to connect to localhost port 80 after 0 ms: Couldn't connect to server

This is of course because Nginx needs to be reloaded with this new configuration. We can reload the new configuration inside the container or by running docker exec with the following command.

nginx -s reload
  • -s - Signal to the master process.
  • reload - Keep the Nginx server running while re-reading any configuration file updates.

Now if we cURL inside Nginx localhost:80 it will be successful.

curl localhost/wittcepter.html
<h1>Download WittCepter</h1>
<h2>The best chrome extension!</h2>
<h2>It's great at analyzing browser network traffic!</h2>