Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Set up Django, nginx and uwsgi

This document has now been incorporated into the uWSGI documentation:

Set up Django, nginx and uwsgi

Steps with explanations to set up a server using:

  • virtualenv
  • Django
  • nginx
  • uwsgi


nginx will face the outside world. It will serve media files (images, CSS, etc) directly from the file system. However, it can't talk directly to Django applications; it needs something that will run the application, feed it requests from the web, and return responses.

That's uwsgi's job. uwsgi will create a Unix socket, and serve responses to nginx via the uwsgi protocol - the socket passes data in both directions:

the outside world <-> nginx <-> the socket <-> uwsgi

Before you start


Make sure you are in a virtualenv - you will install a system-wide uwsgi later.


I am assuming Django 1.4. It automatically creates a wsgi module when you create a project. If you're using an earlier version, you will have to find a Django wsgi module for your project.

Note that I'm also assuming a Django 1.4 project structure, in which you see paths like:


(i.e. it creates nested directories with the name of your project). Adjust the examples if you using an earlier Django.

It will also be helpful if you are in your Django project's directory. If you don't have one ready, just create a directory for now.

About the domain and port

I'll call your domain Substitute your own FQDN or IP address.

Throughout, I'm using port 8000. You can use whatever port you want of course, but I have chosen this one so it doesn't conflict with anything a web server might be doing already.

Basic uwsgi intallation and configuration

Install uwsgi

pip install uwsgi

Basic test

Create a file called

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return "Hello World"


uwsgi --http :8000 --wsgi-file

The options mean:

http :8000
use protocol http, port 8000
load the specified file

This should serve a hello world message directly to the browser on port 8000. Visit:

to check.

Test your Django project

Now we want uwsgi to do the same thing, but to run a Django site instead of the module.

But first, make sure that your project actually works! Now you need to be in your Django project directory.

python runserver

Now run it using uwsgi:

uwsgi --http :8000 --chdir /path/to/your/project --module project.wsgi --virtualenv /path/to/virtualenv

The options mean:

chdir /path/to/your/project
use your Django project directory as a base
module project.wsgi
i.e. the Python wsgi module in your project
virtualenv /path/to/virtualenv
the virtualenv

There is an alternative to using the --module option, by referring instead to the wsgi file:

wsgi-file /path/to/your/project/project/
i.e. the system file path to the file

Point your browser at the server; if the site appears, it means uwsgi can serve your Django application from your virtualenv. Media/static files may not be served properly, but don't worry about that.

Now normally we won't have the browser speaking directly to uwsgi: nginx will be the go-between.

Basic nginx

Install nginx

The version of Nginx from Debian stable is rather old. We'll install from backports.

sudo pico /etc/apt/sources.list     # edit the sources list


# backports
deb squeeze-backports main


sudo apt-get -t squeeze-backports install nginx # install nginx
sudo /etc/init.d/nginx start    # start nginx

And now check that the server is serving by visiting it in a web browser on port 80 - you should get a message from nginx: "Welcome to nginx!"

Configure nginx for your site

Check that your nginx has installed a file at /etc/nginx/uwsgi_params. If not, copy to your directory, because nginx will need it. Easiest way to get it:


Create a file called nginx.conf, and put this in it:

# nginx.conf
upstream django {
    # connect to this socket
    # server unix:///tmp/uwsgi.sock;    # for a file socket
    server;      # for a web port socket

server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name;   # substitute your machine's IP address or FQDN
    charset     utf-8;

    #Max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /media  {
                alias /path/to/your/project/project/media;      # your Django project's media files

        location /static {
                alias /path/to/your/project/project/static;     # your Django project's static files

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /etc/nginx/uwsgi_params; # or the uwsgi_params you installed manually

Symlink to this file from /etc/nginx/sites-enabled so nginx can see it:

sudo ln -s ~/path/to/your/project/nginx.conf /etc/nginx/sites-enabled/

Basic nginx test

Restart nginx:

sudo /etc/init.d/nginx restart

Check that media files are being served correctly:

Add an image called media.png to the /path/to/your/project/project/media directory


If this works, you'll know at least that nginx is serving files correctly.

nginx and uwsgi and

Let's get nginx to speak to the hello world application.

uwsgi --socket :8001 --wsgi-file

This is nearly the same as before, except now we are not using http between uwsgi and nginx, but the (much more efficient) uwsgi protocol, and we're doing it on port 8001. nginx meanwhile will pass what it finds on that port to port 8000. Visit:

to check.

Meanwhile, you can try to have a look at the uswgi output at:

but quite probably, it won't work because your browser speaks http, not uwsgi.

Using sockets instead of ports

It's better to use Unix sockets than ports - there's less overhead.

Edit nginx.conf.

server unix:///tmp/uwsgi.sock;
comment out

and restart nginx.

Runs uwsgi again:

uwsgi --socket /tmp/uwsgi.sock --wsgi-file

Try in the browser.

If that doesn't work

Check your nginx error log(/var/log/nginx/error.log). If you see something like:

connect() to unix:///path/to/your/project/uwsgi.sock failed (13: Permission denied)

then probably you need to manage the permissions on the socket (especially if you are using a file not in /tmp as suggested).


uwsgi --socket /tmp/uwsgi.sock --wsgi-file --chmod-socket=644 # 666 permissions (very permissive)


uwsgi --socket /tmp/uwsgi.sock --wsgi-file --chmod-socket=664 # 664 permissions (more sensible)

You may also have to add your user to nginx's group (probably www-data), or vice-versa, so that nginx can read and write to your socket properly.

Running the Django application with uswgi and nginx

Let's run our Django application:

uwsgi --socket /tmp/uwsgi.sock --chdir /path/to/your/project --module project.wsgi --virtualenv /path/to/virtualenv --chmod-socket=664

Now uwsgi and nginx should be serving up your Django application.

a uwsgi .ini file for our Django application

Deactivate your virtualenv:


and install uwsgi system-wide:

sudo pip install uwsgi

We can put the same options that we used with uwsgi into a file, and then ask uwsgi to run with that file:

# django.ini file

# master
master                  = true

# maximum number of processes
processes               = 10

# the socket (use the full path to be safe)
socket          = /tmp/uwsgi.sock

# with appropriate permissions - *may* be needed
# chmod-socket    = 664

# the base directory
chdir           = /path/to/your/project

# Django's wsgi file
module          = project.wsgi

# the virtualenv
home            = /path/to/virtualenv

# clear environment on exit
vacuum          = true

And run uswgi using the file:

uwsgi --ini django.ini


--ini django.ini
use the specified .ini file

Test emperor mode

uwsgi can run in 'emperor' mode. In this mode it keeps an eye on a directory of uwsgi config files, and spawns instances ('vassals') for each one it finds.

Whenever a config file is amended, the emperor will automatically restart the vassal.

# symlink from the default config directory to your config file
sudo ln -s /path/to/your/project/django.ini /etc/uwsgi/vassals/

# run the emperor as root
sudo uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --master

The options mean:

emperor /etc/uwsgi/vassals
look there for vassals (config files)
uid www-data
run as www-data once we've started
gid www-data
run as www-data once we've started

Check the site; it should be running.

Make uwsgi startup when the system boots

The last step is to make it all happen automatically at system startup time.

Edit /etc/rc.local and add:

/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --master

before the line "exit 0".

And that should be it!


This comment has been minimized.

Copy link
Owner Author

@evildmp evildmp commented Jul 12, 2012

in Test your Django project when you explain module project.wsgi it is not a path but a python module in python-import style, so it should be .wsgi

for someone PYTHONPATH is not a clear concept so you may want to use files using --wsgi-file /path/to/your/project/project/

then in "Configure nginx for your site" i suppose the nginx package already includes the uwsgi_params file


This comment has been minimized.

Copy link

@mjtamlyn mjtamlyn commented Jul 12, 2012

Any reason why you used uwsgi rather than gunicorn? The description of how the stack works is very useful though!


This comment has been minimized.

Copy link
Owner Author

@evildmp evildmp commented Jul 12, 2012

@mjtamlyn I can't even remember why! Probably, someone advised me too...


This comment has been minimized.

Copy link

@orokusaki orokusaki commented Nov 27, 2012

@mjtamlyn - why not? Every benchmark out there shows uWSGI being faster and better by nearly every measure (e.g., ), and Gunicorn is shown to have a higher error rate (e.g., ), whereas uWSGI is just about 100% error free. Good servers, hipster Unicorn logos do not necessarily make. Also worth noting is that uWSGI uses the uwsgi protocol which has less overhead than HTTP for reverse proxying.


This comment has been minimized.

Copy link

@brainless brainless commented Jan 8, 2013

Worked absolutely like a charm for me. Made some changes for Django 1.3 paths.


This comment has been minimized.

Copy link

@ashwin31 ashwin31 commented Jan 9, 2013

can you write about how to host multiple django sites on a single server in production environment.


This comment has been minimized.

Copy link

@jesiah-hackinglife jesiah-hackinglife commented Feb 7, 2013

Some Centos users might need to replace /usr/local/bin/uwsgi with /your-virtual-python-path/bin/uwsgi when running the last part of this tutorial


This comment has been minimized.

Copy link

@clime clime commented Feb 24, 2013

/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --master
For me this command creates two emperor copies. If I remove --master, then only one emperor is spawned. Is it correct to run it with --master?


This comment has been minimized.

Copy link

@alvinli1991 alvinli1991 commented Mar 9, 2013

Nice gist ,It helps me a lot to set up my first app with nignx and uwsgi.
Next I will read more about Django , nginx and uwsgi.
Just say thank you !


This comment has been minimized.

Copy link

@markinhos9 markinhos9 commented Mar 13, 2013

First, thanks for this tutorial, it works perfect.
Now, I have two django projects and I want each one is displayed in a different path, for example: / one for one django project / two for the other project
any idea? THANKS!!!!!


This comment has been minimized.

Copy link

@RichardBruskiewich RichardBruskiewich commented Mar 20, 2013

In your section "If that doesn't work" for the socket uwsgi connection, using the --uid directive (pointing to your nginx user, e.g. www-data) seems to resolve permission issues for the socket.


This comment has been minimized.

Copy link

@stliang stliang commented Apr 14, 2013

I am using nginx version: nginx/1.2.8

The correct way to sym link for me was:

cd /etc/nginx/conf.d/
ln -s /path/to/project/nginx.conf /etc/nginx/conf.d/
mv default.conf default.conf_original

The default.conf file also contains server config


This comment has been minimized.

Copy link

@stliang stliang commented Apr 15, 2013

I am using debian 6.0.5

The last step did not work well for me. I turned to a startup script deployed in /etc/init.d/ instead:


This comment has been minimized.

Copy link

@softinio softinio commented Oct 7, 2013

For this to work for me I had to change:

server unix:///tmp/uwsgi.sock;


server unix:/tmp/uwsgi.sock;


This comment has been minimized.

Copy link

@Niklas9 Niklas9 commented Dec 27, 2013

Had the same issue as incitonetworks; using Ubuntu 12.04.3 LTS with nginx installed through apt-get (ver 1.1.19)


This comment has been minimized.

Copy link

@Varnan Varnan commented Apr 7, 2015

I Have a doubt in the line "Create a file called nginx.conf" , where can I create the nginx.conf ? if it is inside the /etc/nginx/ there already exist a file named "nginx.conf".
Please help me i'm stuck in that line and I want to deploy one of my project. Using Ubuntu 12.04, nginx and uwsgi


This comment has been minimized.

Copy link

@laike9m laike9m commented Oct 1, 2015

@Varnan You could just modify nginx.conf.


This comment has been minimized.

Copy link

@derekriemer derekriemer commented Dec 29, 2015

Wow, that worked great. I had some trouble with other tutorials botching my conf file for nginx, and that really helped. I am now using uwsgitop and the convenient stats module to optimize how many workers I need.
Now I need to buy a domain and my web server will finally be working.


This comment has been minimized.

Copy link

@swills1 swills1 commented Jan 23, 2016

You tell us to make a uwsgi.ini file but you don't tell us where to put it or explain it in any detail. Do we put it somewhere and refer to it in another config? I ask because the note says --ini django.ini So I assume that goes somewhere to call the file. Also, in your example uwsgi.ini you have a path to virtualenv but we don't really need thta option do we since we are no longer working in virtualenv at that point?


This comment has been minimized.

Copy link

@h3ct0rjs h3ct0rjs commented Sep 2, 2016

@stevenmw Did you find that ?


This comment has been minimized.

Copy link

@h3ct0rjs h3ct0rjs commented Sep 2, 2016

I have a two questions. First my nginx is serving me the files correctly, and the uwsgi process is running. When I enter to it just simple not show me the django part, but I know that nginx is serving me the file because it just show me a image in the browser, and offcourse the uwsgi is serving the static files. What should I do to see the proper django app ?


This comment has been minimized.

Copy link

@kgarnett29 kgarnett29 commented Mar 15, 2018

i encountered an issue when "uwsgi --socket /tmp/uwsgi.sock --wsgi-file", and neither 666 nor 664 could solve that.
finally i added user: www-data in .ini file and chown of nginx.conf file from my account/root to www-data, and the 502 bad gateway disappeared!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment