Nginx Cookbook

A recipe to install, configure and package a containerized nginx.

Installation

You could download the sources and build the libraries yourself. This might take you an hour if you want SSL and various useful modules. Yikes, so 2008! I use the containerized version. The docker team has an official build, with lots of variants. My favorite is the alpine Linux version, e.g. 1.12.2-alpine, which is 15.5 MB in size according to my local engine (docker hub claims it's half that size). Set up the docker engine if you haven't already. You'll be downloading the official nginx repo in the docker run command later.

Configuration

I recommend the following locations for your stuff (in line with Unix/Linux standards):

  • Main configuration file in /etc/nginx/nginx.conf
  • Included configuration files in /etc/nginx/conf.d
  • Logs in /var/log/nginx
  • Content in /var/www

This article will only use a main conf file, but I recommend using include files for any non-trival configuration.

Here's a simple example that serves static content on 443 and writes out access and error logs.

events {
    worker_connections 512;
}

http {
    server {
        listen 443 ssl; 
        ssl_certificate /etc/nginx/cert/certificate.pem;
        ssl_certificate_key /etc/nginx/cert/key.pem;
        
        root /var/www;
    }

    access_log /var/log/nginx/access.log combined;
    error_log /var/log/nginx/error.log info;
}

This doesn't have any reverse proxies yet and merely serves static content from /var/www, e.g. http://host/product/overview.html from /var/www/product/overview.html.

Check out intro on reverse proxies and the reference on the proxy module.

Log Rotation

To productionize it, you'll want to set up log archiving. I generally set up logrotate to run in cron.daily and create a script in /etc/logrotate.d/nginx like this to keep two day's worth of logs:

/var/log/nginx/*.log {
    daily
    compress
    delaycompress
    rotate 2
    missingok
    nocreate
    sharedscripts
    postrotate
	    docker kill --signal USR1 nginx 
    endscript
}

Note: The kill tells nginx to reset to the new log post rotation. If you don't do this, no records will persist post-rotation.

Startup

To start it up as a daemon that is always on even if it exits or the host or docker engine restarts:

docker run -d --restart=always -p 80:80 -p 443:443 -v /var/log/nginx:/var/log/nginx -v /etc/nginx:/etc/nginx --name nginx nginx:1.12.2-alpine

Bundle it

You'll eventually want to roll up nginx into your own image so you can don't have to manage scripts and conf files, and can easily deploy to a container orchestrator like AWS ECS or Kubernetes.

Suppose you kept a repo in your source code control system with conf files and content. Here's a simple Dockerfile to bundle that up:

FROM nginx:1.12.2-alpine
COPY etc/nginx /etc/nginx
COPY var /var

You could also add EXPOSE and VOLUME statements, but that's merely documentation. Build it like this:

docker build --tag my-nginx .

And in your docker run command use your image name, my-nginx, instead of the official nginx:1.12.2-alpine.

Runtime Tweaks

If you need to change something quickly in situ, you can shell into the container and vi the conf file, or copy it out/edit and copy it back or remount it on your host. To copy out:

docker cp my-nginx:/etc/nginx/nginx.conf .

Now edit the file. Copy it back:

docker cp ./nginx.conf my-nginx:/etc/nginx/

Finally instruct nginx to reload the conf:

docker kill --signal HUP my-nginx

Published Jan 29, 2018

NGINX icon used with permission from NGINX, Inc.

Comments? email me - mark at sawers dot com