Serving Django app with uWSGI and Nginx
This article will show how we can serve a Django app with uWSGI and Nginx.
We're going to configure the uWSGI application container server to interface with our applications by setting up Nginx to reverse proxy to uWSGI.
Nginx provides a HTTP connection management, load balancing, content caching, and traffic security, etc.
uWSGI is an application server container and communicates with the application using the methods defined by the WSGI spec, and with other web servers over a variety of other protocols. The uWSGI translates requests from a conventional web server into a format that the application can process.
In other words, the WSGI spec defines the interface between the web server (uWSGI server) and application. The uWSGI server is responsible for passing client requests to the application using the WSGI spec.
the web client <-> the web server <-> the socket <-> uwsgi <-> Django
"uWSGI operates on a client-server model. Your Web server (e.g., nginx, Apache) communicates with a django-uwsgi "worker" process to serve dynamic content." - How to use Django with uWSGI.
In this section, we will setup a virtualenv for our sample app.
$ mkdir ~/sample-app/ $ cd sample-app $ virtualenv venv $ source venv/bin/activate (venv)k@laptop:~/sample-app$
install the uWSGI server into our environment using pip:
(venv)k@laptop:~/sample-app$ pip install uwsgi
WSGI is an interface between a web server and the application. It ensures a standardized way between various servers and application frameworks.
A wsgi.py provides an application object which is callable to be used by the server.
Let's create an application in a file called wsgi.py in our application directory:
def application(environ, response): response('200 OK', [('Content-Type', 'text/html')]) return ["Hello WSGI Python App!"]
The uWSGI will look for a callable called application which takes two parameters.
The first is an environmental variable-like key-value dictionary. The second is the name the app will use internally to refer to the web server (uWSGI) callable that is sent in.
Our application takea this information and do the following:
- It calls the callable it received with an HTTP status code and any headers it wants to send back. In this case, we are sending a "200 OK" response and setting the Content-Type header to text/html.
- It returns an iterable to use as the response body. Here, we've just used a list containing a single string of HTML. Strings are iterable as well, but inside of a list, uWSGI will be able to process the entire string with one iteration.
In Django projects include a wsgi.py file by default that translates requests from the web server (uWSGI) to the application (Django). The simplified WSGI interface stays the same regardless of how complex the actual application code is. This is one of the strengths of the interface.
Let's start up uWSGI which will tell it to use HTTP for the time being and to listen on port 8888. We will pass it the name of the script (suffix removed):
(venv)k@laptop:~/sample-app$ uwsgi --socket 0.0.0.0:8888 --protocol=http -w wsgi
The uWSGI Config File (~/sample-app/sample-app.ini) looks like this:
[uwsgi] module = wsgi:application master = true processes = 5 socket = sample-app.sock chmod-socket = 664 vacuum = true die-on-term = true
We'll use the init file with an Upstart script that we'll see in the next section.
We can launch a uWSGI instance at boot so that our application is always available (/etc/init/sample-app.conf):
description "uWSGI instance to serve sample-app" start on runlevel [2345] stop on runlevel [!2345] setuid k setgid www-data script cd /home/k/sample-app . venv/bin/activate uwsgi --ini sample-app.ini end script
We start out with the system runlevels of 2 through 5 and stop the service when it's on any runlevel outside of the level.
The configuration file tells Upstart about which user (k) and group (www-data) to run the process as.
Next, we'll run the actual commands to start uWSGI via a script block.
Now that our Upstart script is complete, we can start the service:
(venv)k@laptop:~/sample-app$ sudo start sample-app sample-app start/running, process 7228 (venv)k@laptop:~/sample-app$ ps aux | grep sample-app k 7232 0.5 0.1 50164 7008 ? S 15:06 0:00 uwsgi --ini sample-app.ini k 7233 0.0 0.1 53028 5304 ? S 15:06 0:00 uwsgi --ini sample-app.ini k 7234 0.0 0.1 53028 5304 ? S 15:06 0:00 uwsgi --ini sample-app.ini k 7235 0.0 0.1 53028 5304 ? S 15:06 0:00 uwsgi --ini sample-app.ini k 7236 0.0 0.1 53028 5304 ? S 15:06 0:00 uwsgi --ini sample-app.ini k 7237 0.0 0.1 53028 5304 ? S 15:06 0:00 uwsgi --ini sample-app.ini
We can also see :
(venv)k@laptop:~/sample-app$ ls -la ... -rw-rw-r-- 1 k k 142 May 21 16:37 sample-app.ini srw-rw-r-- 1 k www-data 0 May 21 19:06 sample-app.sock drwxrwxr-x 6 k k 4096 May 21 12:49 venv -rw-rw-r-- 1 k k 142 May 21 12:37 wsgi.py
The app will start automatically on boot. We can stop the service at any time by typing:
(venv)k@laptop:~/sample-app$ sudo stop sample-app
Now we have a WSGI app and have verified that uWSGI can read and serve it.
Also, we have a configuration file and an Upstart script.
Our uWSGI process will listen on a socket and communicate using the uwsgi protocol.
Note that we can use Nginx as a proxy via uwsgi protocol for communicating with uWSGI which is a faster protocol than HTTP and have better performance.
Let's create a new file /etc/nginx/sites-available/sample-app:
server { listen 80; server_name sample-app.com; location / { include uwsgi_params; uwsgi_pass unix:/home/k/sample-app/sample-app.sock; } }
Enable the server configuration we just made by linking it to the sites-enabled directory:
$ sudo ln -s /etc/nginx/sites-available/sample-app /etc/nginx/sites-enabled
Check the configuration file for syntax errors:
$ sudo service nginx configtest * Testing nginx configuration
If it reports back that no problems were detected, restart the server to implement new changes:
$ sudo service nginx restart
Once Nginx restarts, we should be able to go to our server's domain name or IP address (without a port number) and see the application we configured:
Here are two samples:
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization