Nginx in Docker without Root

This post will walk you through how to run Nginx as a non-privileged (i.e., not root) user. We’ll use an official Nginx image as a starting point, modify the image using a Dockerfile, and provide some tweaks to the configuration files.

Overview

When running Nginx as a non-root user, these are the main things to keep in mind:

  • User needs read access to website files.
  • User needs read and write access to /var/run/nginx.pid.
  • User needs read and write access to /var/cache/nginx.
  • Don’t listen on ports 80 or 443.

User and Directory

Before starting, decide which user you will have run the Nginx process and where you want to store the code for the web application. In my example, I’m using the www-data user and the directory /var/www which is its home directory.

Dockerfile

FROM nginx:stable

COPY ./nginx.conf /etc/nginx/nginx.conf
COPY ./site.conf /etc/nginx/conf.d/default.conf

RUN touch /var/run/nginx.pid && \
  chown -R www-data:www-data /var/run/nginx.pid && \
  chown -R www-data:www-data /var/cache/nginx

USER www-data

VOLUME /var/www

This Dockerfile uses the official nginx:stable image as its starting point. It then copies in a pair of config files, /etc/nginx/nginx.conf and /etc/Nginx/conf.d/default.conf. (See below for these files.)

Next, the Dockerfile makes the www-data user the owner and group for a few paths that Nginx will need to write to. The first is the PID file /var/run/nginx.pid. Since this file doesn’t already exist, the Dockerfile uses the touch command to create an empty file before setting the ownership. The second path is a directory Nginx uses for various caches.

Configuration Files

The Dockerfile copies in two files. /etc/nginx/nginx.conf is the primary config file for Nginx; /etc/nginx/conf.d/default.conf is the default website config file.

You may want to start with the config files provided in the offical image. An easy way to copy the original files from the image to your host is to start a container and use docker cp:

docker run --name nginx -d nginx:stable
docker cp nginx:/etc/nginx/nginx.conf ./nginx.conf
docker cp nginx:/etc/nginx/conf.d/default.conf ./site.conf
docker stop nginx
docker rm nginx

Here’s a sample /etc/nginx/nginx.conf based on the file that comes with the image. Yours may vary a bit, but the only change I needed to make was to remove the user nginx; line to avoid a warning since this directive is only meaningfull when Nginx is running as root.

worker_processes  1;
error_log  /var/log/nginx/error.log warn;
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;
}

Since the Nginx file for the site will vary widely from site to site, I’m including a minimal version. The important part is listen directive.

server {
    listen       8080;
    server_name  localhost;
    location / {
        root   /var/www/htdocs;
        index  index.html index.htm;
    }
}

Only root can listen on ports below 1024, so you will need to use higher-numbered ports for your site. This is pretty much a non-issue since you’ll need to map your host port to your container port anyway, for example:

docker run -d -p 80:8080 mynginx

Complex Comparisons in PHP

I had a project recently where I needed to do some custom array sorting using usort(). Nothing tricky about writing a custom sort function or two, but what do you do when you need several, and you don’t know ahead of time which sort functions you’ll need?

For example, say you have a dataset that you’d like to sort in PHP, and you want to leave it to the user (or configuration file, etc.) to determine the sort order. One configuration may order the data by firstName, then age, then favorite color, while another may order by favorite color, then firstName, etc.

I came up with a solution that allows you to bake an array of compare functions into one single compare function. It looks like this:

Using It

To use this, start by defining some compare functions. If you’re not familiar with how to do this, see the usort() page in the PHP manual. The basic idea is that you provide a function that takes two parameter and returns 1 if the first parameter should sort before the second, -1 if the second should short before the first. 0 indicates they’re the same.

<?php
// From the PHP manual.
function cmp($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

Once you have a few defined, create an array containing references to the functions or strings containing the names of the functions. (PHP considers either to be a “callable”). Pass this array to makeComplexSortFunction(), and use the returned callable in usort().

Here’s an example script:

Happy sorting!

Android Delayed Execution on UI Thread

Ever need to run something on the UI thread after a short delay? Here’s an example. Create a new thread that will block for a set amount of time, then create a Runnable and send it to the Activity’s runOnUiThread() method.

Adapted from this Stack Overflow answer.