Documente Academic
Documente Profesional
Documente Cultură
Nginx, Gunicorn,
virtualenv, supervisor and
PostgreSQL
JUN 9TH, 2013
Django is an efficient, versatile and dynamically evolving web application
development framework. When Django initially gained popularity, the recommended
setup for running Django applications was based around Apache with mod_wsgi. The
art of running Django advanced and these days the recommended configuration is
more efficient and resilient, but also more complex and includes such tools as: Nginx,
Gunicorn, virtualenv, supervisord and PostgreSQL.
In this text I will explain how to combine all of these components into a Django
server running on Linux.
Prerequisites
I assume you have a server available on which you have root privileges. I am using a
server running Debian 7, so everything here should also work on an Ubuntu server or
other Debian-based distribution. If youre using an RPM-based distro (such as
CentOS), you will need to replace the aptitude commands by their yum counterparts
and if youre using FreeBSD you can install the components from ports.
If you dont have a server to play with, I would recommend the inexpensive VPS
servers offered by Digital Ocean. If you click through this link when signing up, youll
pay a bit of my server bill :)
Im also assuming you configured your DNS to point a domain at the servers IP. In
this text, I pretend your domain is example.com
PostgreSQL
To install PostgreSQL on a Debian-based system run this command:
Create a database user and a new database for the app. Grab a perfect password
from GRC.
$ sudo su - postgres
postgres@django:~$ createuser --interactive -P
Enter name of role to add: hello_django
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
postgres@django:~$
Application user
Even though Django has a pretty good security track record, web applications can
become compromised. If the application has limited access to resources on your
server, potential damage can also be limited. Your web applications should run as
system users with limited privileges.
Create a user for your app, named hello and assigned to a system group
called webapps.
$ sudo groupadd --system webapps
$ sudo useradd --system --gid webapps --shell /bin/bash --home /webapps/hello_django hello
$ sudo su - hello
hello@django:~$ cd /webapps/hello_django/
hello@django:~$ virtualenv .
Your environment is now activated and you can proceed to install Django inside it.
Downloading/unpacking django
(...)
Installing collected packages: django
(...)
Successfully installed django
Cleaning up...
Your environment with Django should be ready to use. Go ahead and create an
empty Django project.
(hello_django)hello@django:~$ cd hello
0 errors found
June 09, 2013 - 06:12:00
Django version 1.5.1, using settings 'hello.settings'
Development server is running at http://example.com:8000/
Quit the server with CONTROL-C.
You can check what groups youre a member of by issuing the groups command or id.
$ id
uid=1000(michal) gid=1000(michal) groups=1000(michal),27(sudo),100(users)
If youre not a member of users, you can add yourself to the group with this
command:
$ sudo usermod -a -G users `whoami`
Group memberships are assigned during login, so you may need to log out and back
in again for the system to recognize your new group.
Gunicorn
In production we wont be using Djangos single-threaded development server, but a
dedicated application server called gunicorn.
Install gunicorn in your applications virtual environment:
Cleaning up...
Now that you have gunicorn, you can test whether it can serve your Django
application by running the following command:
DJANGODIR=/webapps/hello_django/hello
GROUP=webapps
NUM_WORKERS=3
DJANGO_SETTINGS_MODULE=hello.settings
DJANGO_WSGI_MODULE=hello.wsgi
view rawgunicorn_start.bashhosted
with by GitHub
You can test your gunicorn_start script by running it as the user hello.
$ sudo su - hello
hello@django:~$ bin/gunicorn_start
Starting hello_app as hello
2013-06-09 14:21:45 [10724] [INFO] Starting gunicorn 18.0
2013-06-09 14:21:45 [10724] [DEBUG] Arbiter booted
2013-06-09 14:21:45 [10724] [INFO] Listening at: unix:/webapps/hello_django/run/gunicorn.sock (10724)
2013-06-09 14:21:45 [10724] [INFO] Using worker: sync
2013-06-09 14:21:45 [10735] [INFO] Booting worker with pid: 10735
2013-06-09 14:21:45 [10736] [INFO] Booting worker with pid: 10736
2013-06-09 14:21:45 [10737] [INFO] Booting worker with pid: 10737
Note the parameters set in gunicorn_start. Youll need to set the paths and filenames to
match your setup.
As a rule-of-thumb set the --workers (NUM_WORKERS) according to the following formula:
2 * CPUs + 1. The idea being, that at any given time half of your workers will be busy
doing I/O. For a single CPU machine it would give you 3.
The --name (NAME) argument specifies how your application will identify itself in
programs such as top or ps. It defaults to gunicorn, which might make it harder to
distinguish from other apps if you have multiple Gunicorn-powered applications
running on the same server.
In order for the --name argument to have an effect you need to install a Python
module called setproctitle. To build this native extension pip needs to have access to C
header files for Python. You can add them to your system with the python-dev package
and then install setproctitle.
$ sudo aptitude install python-dev
(hello_django)hello@django:~$ pip install setproctitle
Now when you list processes, you should see which gunicorn belongs to which
application.
$ ps aux
USER
(...)
hello
hello
hello
hello
When Supervisor is installed you can give it programs to start and watch by creating
configuration files in the /etc/supervisor/conf.d directory. For our hello application well
create a file named /etc/supervisor/conf.d/hello.conf with this content:
[program:hello]
command = /webapps/hello_django/bin/gunicorn_start
; Command to start
app
user = hello
; User to run as
stdout_logfile = /webapps/hello_django/logs/gunicorn_supervisor.log ; Where to write
log messages
redirect_stderr = true
; Save stderr in the same log
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8
; Set UTF-8 as
default encoding
view rawhello.confhosted
with by GitHub
You can set many other options, but this basic configuration should suffice.
Create the file to store your applications log messages:
After you save the configuration file for your program you can ask supervisor to
reread configuration files and update (which will start your the newly registered app).
You can also check the status of your app or start, stop or restart it using supervisor.
RUNNING
Your application should now be automatically started after a system reboot and
automatically restarted if it ever crashed for some reason.
Nginx
Time to set up Nginx as a server for out application and its static files. Install and
start Nginx:
You can navigate to your server (http://example.com) with your browser and Nginx
should greet you with the words Welcome to nginx!.
Create an Nginx virtual server configuration for Django
Each Nginx virtual server should be described by a file in the /etc/nginx/sitesavailabledirectory.
You select which sites you want to enable by making symbolic links
client_max_body_size 4G;
access_log /webapps/hello_django/logs/nginx-access.log;
error_log /webapps/hello_django/logs/nginx-error.log;
location /static/ {
alias /webapps/hello_django/static/;
}
location /media/ {
alias /webapps/hello_django/media/;
}
location / {
# an HTTP header important enough to have its own Wikipedia entry:
# http://en.wikipedia.org/wiki/X-Forwarded-For
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# enable this if and only if you use HTTPS, this helps Rack
# set the proper protocol for doing redirects:
# proxy_set_header X-Forwarded-Proto https;
# pass the Host: header from the client right along so redirects
# can be set properly within the Rack application
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
#
#
#
#
#
#
with by GitHub
Restart Nginx:
If you navigate to your site, you should now see your Django welcome-page powered
by Nginx and Gunicorn. Go ahead and develop to your hearts content.
At this stage you may find that instead of the Django welcome-page, you encounter
the default Welcome to nginx! page. This may be caused by
the default configuration file, which is installed with Nginx and masks your new sites
configuration. If you dont plan to use it, delete the symbolic link to this file
from /etc/nginx/sites-enabled.
If you run into any problems with the above setup, please drop me a line.
/webapps/hello_django/
bin
activate
django-admin.py
gunicorn
gunicorn_django
gunicorn_start
python
hello
manage.py
project_application_1
project_application_2
hello
__init__.py
settings.py
urls.py
wsgi.py
include
python2.7 -> /usr/include/python2.7
lib
python2.7
lib64 -> /webapps/hello_django/lib
logs
gunicorn_supervisor.log
nginx-access.log
nginx-error.log
media
run
gunicorn.sock
static
Restart Nginx:
If you never plan to use this application again, you can remove its config file also
from the sites-available directory
$ sudo rm /etc/nginx/sites-available/hello_django
$ sudo rm /etc/supervisor/conf.d/hello.conf
If you never plan to use this application again, you can now remove its entire
directory from webapps:
$ sudo rm -r /webapps/hello_django