WittCode💻

Is Docker Breaking Nginx?

By

The official Docker Nginx image is extremely useful in getting an instance of Nginx up and running quickly. However, it does have some issues. Particularly when it comes to environment variable substitution.

Table of Contents 📖

Nginx Variables and Environment Variables

The default Nginx Docker image provides environment variable support out of the box. However, it is not perfect. This is because both Nginx variables and environment variables look very similar. Consider the configuration file below.

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  '[$time_local]: $status $remote_addr "$request"';

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

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;
    gunzip on;
    gzip_types    text/plain application/javascript application/x-javascript text/javascript;

    server {
        listen ${NGINX_PORT};
        server_name ${NGINX_HOST};

        root /usr/share/nginx;

        location / {
            try_files $uri $uri/ $uri.html /images/404.png;
        }

        location /api {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_pass http://${SERVER_HOST}:${SERVER_PORT}/api;
            proxy_http_version 1.1;
        }
    }    
}

In this configuration file, we have environment variables defining the location of our Nginx web server and Node API server. However, we also have variables like $uri to define the path of the request and $host to append to the proxied request.

Docker Nginx Image and Environment Variables

To use environment variables in the Nginx docker image, we need to copy a file with environment variables to the location /etc/nginx/templates in the container. Under the hood, the Nginx image will use envsubst to replace the environment variables in the file. However, it will also replace all instances of Nginx variables. This means that $host and $uri will be replaced. If there is not environment variable for this value it will be blank. This can cause a lot of issues in the Nginx configuration and even break it.

What to do?

To handle this, simply create your own entrypoint script for the Docker image. This allows us to have control over the environment variable substitution process. Specifically, we can set the environment variables that we want to be replaced in the configuration file.

#!/usr/bin/env sh

# Replace the environment variables
envsubst '${NGINX_HOST} ${NGINX_PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf

# Run Nginx in the foreground. 
nginx -g "daemon off;"

INFO: The -g "daemon off;" command tells Nginx to stay in the foreground. This means that the container will not exit when the script exits. This is important because we want to keep the container running. If we exited the script, the container would exit.

Now when the container starts up, this script will make it so envsubst will only target the provided environment variables. This means that the Nginx variables will not be affected.

Is Docker Breaking Nginx?