Nginx and uwsgi

Nginx is great for serving static pages and acting as a reverse-proxy. When a dynamic page is needed then a second process is used to generate the page.

Introduction

When setting up a web site it’s common to use nginx as the front-end. Nginx is great for serving static pages and acting as a reverse-proxy. When a dynamic page is needed then a second process is used to generate the page.

uWSGI was originally designed as a process manager for Python scripts that would generate dynamic pages. Later it has been enhanced to do the same for a number of scripting languages including Perl, Php, Ruby and Go. It even supports the old CGI interface.

It can be frustrating to get nginx and uWSGI to communicate. The problems almost always come down to permission problems of some kind, though at least initially this may not be indicated by the symptoms.

Sockets Vs TCP/IP

From here on I will be describing the Unix Domain Socket interface between nginx and uWSGI. The alternative, communication over TCP/IP, is simpler. However it involves communication via the TCP/IP networking stack and does not perform as well although, to be fair, that is only an issue when handling high network traffic. Unix Domain Sockets can have between 50% – 66% better latency and 7x better throughput.

In all the configurations that I have set up it is uWSGI that has been responsible for creating the socket. Therefore uWSGI also sets the owner and permissions. The first check, therefore, is that uWSGI has the correct permissions to write to the file system at the location you want the socket to be created.

Under which user will you run uWSGI?

For security reasons you should not run uWSGI (or nginx) as root. Create a user specifically for these two services. I normally create www-data since it was also the user traditionally used to run the Apache web server. I also create a group called www-data and add my userid to the group so that I can read files owned by the group. Create www-data as follows

useradd -U -m -s /bin/bash www-data

Emperor mode

You can run uWSGI serving a single application. This is fine for simple and small scale applications. The problem is that if there is a failure then uWSGI will stop and not restart.

Alternatively, run uWSGI in emperor mode. A single emperor process starts and it starts multiple vassals. These vassals then serve the application.

[uwsgi] 
# If Tyrant mode is wanted
# emperor-tyrant = true
# try to autoload appropriate plugin if "unknown" option has been specified
autoload = true
# enable master process manager
master = true
# spawn 2 uWSGI emperor worker processes
workers = 1
# automatically kill workers on master's death
no-orphans = true
# place timestamps into log
log-date = true
# Emperors userid - default is root
# uid = www-data
uid = root
# Emperors group id - default is root
#gid = www-data
gid = root
# vassals directory
emperor = /etc/uwsgi-emperor/vassals

If you wish to run the emperor as an unprivileged user (with uid and gid below) then become a tyrant. In Tyrant mode the Emperor will run the vassal using the UID/GID of the vassal configuration file. If Tyrant mode is used, the vassal configuration files must have UID/GID > 0. An error will occur if the UID or GID is zero, or if the UID or GID of the configuration of an already running vassal changes. The problem is creating sockets – the emperor needs write permission to create sockets for the vassals. If the socket directory is a tempfs then the sockets have to be created at each startup. But places like /run are only accessable to root.

Where should the socket be created?

The traditional location for sockets is under the /var/run directory. Often this is a symbolic link to /run which is mounted on a tempfs filesystem. Note that no data is actually written to the filesystem.

There are normally a number of other sockets created on the system so /var/run or /run are a little cluttered. Also I have had problems setting the correct permissions if the socket was created in /var so my practice has been to create a directory simply for the uWSGI socket.

mkdir -p /var/run/uwsgi
chown www-data:www-data /var/run/uwsgi

However this causes its own problems if the filesystem is mounted on tempfs. When the server is rebooted your carefully created directory will have gone!

If you are running on a server or virtual machine the way to solve this problem is to use a cron job to create the directory. Most implementations of crontab now support a time specification of @reboot. Therefore you can use the two lines above (concatenated with a ‘ ; ‘) in the crontab for your chosen userid.

If you are running uWSGI in a container (e.g. lxc or docker) then create the socket directly in /run. You probably only have nginx and uWSGI running in the container and so it will not be too cluttered with other sockets.

uWSGI configuration

It is then important to configure uWSGI to create the socket and set the correct permissions. The following five lines achieve this.

uid = www-data
gid = www-data
#= Either create a sub-directory /var/run/uwsgi and chown & chmod or put it in /tmp.
socket = /var/run/uwsgi/app_name.sock
chmod-socket = 664
chown-socket = www-data
buffer-size = 6553

The first two lines set the user and group under which uWSGI will run.

The next three lines configure where uWSGI will create the socket, the name of the socket, its owner and its permissions.

The directory (/var/run/uwsgi/ in the example above) should be created before uwsgi is started. uWSGI will not create the directory and so cannot not create the socket if the directory does not exist.