This article explains how to use NGINX as an application gateway with uWSGI and Django.

Table of Contents

Introduction

NGINX is a high-performance, scalable, secure, and reliable web server and a reverse proxy. NGINX enables all the main web acceleration techniques aimed at HTTP connection and traffic management. For many years, NGINX capabilities such as load balancing, SSL termination, connection and request policing, static content offload, and content caching have helped NGINX users to build reliable and fast websites quickly and efficiently.

NGINX can also act as a secure application gateway, offering a number of specialized built-in interfaces to pass traffic from users to applications. In this regard, not only can NGINX proxy HTTP and HTTPS traffic to an HTTP-enabled application container, it can also directly talk to most of the popular lightweight application servers and web frameworks via optimized app gateway interfaces via modules like uWSGI and FastCGI.

One of the reasons for using NGINX as an application gateway is the following. Even though the most commonly used application containers have embedded external HTTP interfaces with some routing capabilities, NGINX provides an all-in-one solution for HTTP connection management, load balancing, content caching, and traffic security, with the application back end kept securely behind NGINX for better scalability and performance. It is also very easy to cluster application instances behind NGINX to build highly available applications.

An Overview of uWSGI and Django

A few words about “specialized interfaces”. As useful as it is, HTTP hadn’t ever been optimized for modern lightweight application deployment scenarios. In recent years, a number of standardized interfaces evolved for use with various application frameworks and application containers. One of these interfaces is the Web Server Gateway Interface (WSGI), an interface between a web server/proxy and a Python-based application.

One of the most commonly used application servers offering the uwsgi protocol – its own implementation of the WSGI protocol – is the Configuring NGINX for Use with uWSGI and Django

In this document we’ll provide a quick recommendation on how to configure NGINX for use with a official repositories (either binaries or the source), you don’t have to do anything to enable support for the uwsgi protocol – it’s included in NGINX by default.

Configuring the uWSGI application container itself is outside the scope of this document, so please refer to the excellent Quickstart for Python/WSGI applications for more information.

For simplicity’s sake, let’s assume you’re going to use a Django-based setup for your Python app. Django is probably the most commonly used Python web framework, so it makes sense to use it in our example below. For extensive information on how to configure a Django environment, please refer to the Django documentation.

For illustrative purposes only, a quick example on how you might be invoking your uWSGI server with Django:

/usr/local/sbin/uwsgi \
    --chdir=/var/django/projects/myapp \
    --module=myapp.wsgi:application \
    --env DJANGO_SETTINGS_MODULE=myapp.settings \
    --master --pidfile=/usr/local/var/run/uwsgi/project-master.pid \
    --socket=127.0.0.1:29000 \
    --processes=5 \
    --uid=505 --gid=505 \
    --harakiri=20 \
    --max-requests=5000 \
    --vacuum \
    --daemonize=/usr/local/var/log/uwsgi/myapp.log

Assuming the above, an example NGINX configuration for use with a Django project might look like the following:

http {

    ...

    upstream django {
        server 127.0.0.1:29000;
    }

    server {
        listen 80;
        server_name myapp.example.com;

        root /var/www/myapp/html;

        location / {
            index index.html;
        }

        location /static/  {
            alias /var/django/projects/myapp/static/;
        }

        location /main {
            include /etc/nginx/uwsgi_params;
            uwsgi_pass django;

            uwsgi_param Host $host;
            uwsgi_param X-Real-IP $remote_addr;
            uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
            uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
        }
    }
}

Notice that the configuration defines an upstream called django. The port number matches the one the uWSGI server binds to, as specified by the socket argument in the sample uwsgi command. Here the static content is offloaded to NGINX, which serves it directly. Traffic to the “main” application is proxied and bridged from HTTP to the uwsgi protocol and passed to the Django app, running inside uWSGI application container.

Conclusion

Lightweight, heterogeneous application environments are becoming an increasingly popular way of building and deploying modern web applications. Newer, standardized application interface protocols like uwsgi and FastCGI enable faster communication between users and applications.

Using NGINX in front of an application container has become a common way to lift the burden of HTTP traffic management from the application, protecting the application from unexpected spikes of user traffic, malicious behavior, denial-of-service attacks, and more. Unbundling real-world, external HTTP traffic from the actual application allows the developer to fully focus on the application logic, and leave the web acceleration and fundamental HTTP traffic security tasks to NGINX.

For more information on configuring the uwsgi module for NGINX, please see: