A Django setup using Nginx and Gunicorn
2014-09-28 10:00
621 查看
http://goodcode.io/blog/django-nginx-gunicorn/
This is a howto on setting up Django on a Linux (Ubuntu) system using Nginx as a reverse proxy and Gunicorn as a Django service.
The conventional way to run Django in production these days is using
Apache2 and mod_wsgi. While there’s nothing wrong with that approach,
I prefer Nginx. I also like to be able to control Django server separately from the web server.
There are several production-ready servers for Django. The best seem to be
Gunicorn and uWSGI, and Gunicorn seems the best supported and most active project.
When running Django server separately from the web server, we need a way to start, stop and restart the Django server. A popular way for doing it in Django world is
Supervisor, altough, for Ubuntu users,
Upstart might be less hassle.
You probably already have a Django project you want to deploy, but for completenes’ sake, the steps here will use an empty toy “Hello World” Django project:
virtualenv, right? If not,
you should.
For production, we might want a bit more options, and we want to make sure the server is executing in the correct environment. The easiest way is to create a shell script to set it all up:
The number of workers is number of worker processes that will serve requests. You can set it as low as 1 if you’re on a small VPS. A popular formula is 1 + 2 * number_of_cpus on the machine (the logic being, half of the processess will be waiting for I/O,
such as database). YMMV.
Don’t forget to mark the script as executable (chmod ug+x script.sh). You can run it from the command line for testing. Note that Gunicorn by default uses 127.0.0.1:8000 address (the same as Django debug server), which is fine if Nginx is on the
same machine – you usually don’t want to have it wide open to anyone, and instead let Nginx handle incoming connections.
If you want to run several Django servers on the same machine, just make sure each uses a different port number.
the official docs. The config file for running our server (/etc/supervisor/conf.d/hello.conf on Debian/Ubuntu) should look like this:
Test it with supervisorctl {start,status,stop} hello (as root).
Test it with service hello {start,status,stop} (as root).
Update 2011-11-14:For completeness of the Upstart setup configuration one has to add a soft link in
Update 2011-11-14: Christophe Meessen found and fixed several errors in the procedures and config files, and also provided info about the extra Upstart configuration I missed. Thanks Christophe!
apt-get install nginx, and other Linux distributions usually have equivalent commands.
Nginx is mostly a drop-in replacement for Apache for serving static files, though there are some
things to set up if you need to run PHP code as well.
For our setup, we need Nginx to serve as the reverse proxy for the upstream server(s). To do so, we add a server section to the config file:
Ubuntu and Debian systems keep Nginx config files in same layout as for Apache, so the above cold be added to
/etc/nginx/sites-available/hello (and enabled by symlinking from sites-enabled directory). Use
nginx -t for config test and nginx -s reload to reload the configuration.
same machine.
Have improvements on the above or your own helpful tips, or found an error in the post? Share in the comments.
We’re small, experienced and passionate team of web developers, doing custom app development and web consulting.
Learn more about us
18.06.2011.
Senko Rašić
21.07.2014.Python packages we use
18.07.2014.Ready for EuroPython 2014
lamby
June 18, 2011 at 2:46 pm
gunicorn in Debian has a /etc/gunicorn.d feature (like sites-enabled) so you don’t need to mess about making your own scripts.
Reply
Senko
June 18, 2011 at 6:31 pm
That’s neat, thanks. Althought, that means you have to have gunicorn installed systemwide, whereas, in my example, I installed it in virtualenv. Not that installing it systemwide would neccessarily be a problem for most people, I just like having most of
the stuff neatly tucked in virtualenv.
Reply
Mahdi Yusuf
June 18, 2011 at 2:51 pm
I have been meaning to learn this. Thanks.
Reply
Max Jaderberg
June 18, 2011 at 3:32 pm
Brilliant stuff…was really looking for a clear guide for setting up django
Reply
Jonas B.
June 18, 2011 at 4:26 pm
Why not run Django directly on uwsgi for nginx? I find it to be the far most common and well supported configuration. Performance is at least as good and there’s one less component to troubleshoot.
Reply
Senko
June 18, 2011 at 6:34 pm
I don’t have good arguments for whether gunicorn is better than the uwsgi combination. When I was looking for alternatives to mod_wsgi, I found both, but gunicorn did come up more often and I got the impression that more people are using it.
Reply
Tim
June 18, 2011 at 4:37 pm
you could do similar setup with Cherrypy + ngingx. In fact ngingx+apache2/wsgi would also give a decent performance boost to your python/django deployments (or any other non-python apache “mods”.
Reply
Viktor Petersson
June 18, 2011 at 4:51 pm
We’ve been running a very similar solution for some time on FreeBSD, and it works lika charm. If you’re running it across multiple servers, you probably want to move Nginx off of each node, and run it on a central load balancer and then have separate static
servers (Nginx works great for this too).
If you want to scale it further, you can add Varnish to the equation to get some powerfull caching.
Reply
Dana Woodman
June 18, 2011 at 7:01 pm
First off, great overview. That’s basically the setup I use for most of my Django projects.
If you haven’t had the pleasure of using Fabric yet, you should definitely check it out. It’s an excellent way to manage/deploy you Django projects, including starting/restarting Gunicorn, updating you project code and doing database management; all remotely
via ssh. It’s a great tool in the Django web development toolkit.
http://docs.fabfile.org/en/1.0.1/index.html
Reply
Simon Pantzare
June 18, 2011 at 11:26 pm
During development, it may be preferable to run supervisord inside the virtualenv as well. Here is a small project of mine intended to make this easy:
https://github.com/pilt/pewatch
Reply
Elf M. Sternberg
June 19, 2011 at 5:22 am
Thanks for this. I’ve been shy about using Gunicorn, mostly because I’ve been using an Nginx + Apache/WSGI + Varnish trio for my django & media issues. I may look into it again for my next project. (Then again, my next project may be couchdb as my front-end
server, and node.js as a back-end, so…)
Reply
Rich
June 19, 2011 at 7:42 am
Can you say a bit more about the benefits gained from using this setup over Apache? Numbers would be great, too..
Reply
Senko
June 20, 2011 at 1:34 am
I didn’t want to get into whys, as the choice of the server really depends on the specific use case, so YMMV. I prefer Nginx because it’s really good at what it does (serving static assets, proxying/load balancing slower upstreams for dynamic stuff).
I also host a bunch of apps written on various platforms (Django, Flask, Tornado, Node.js, PHP) on the same system, so I need to use some sort of a reverse proxy anyways. In such a setup, there’s no need to involve Apache too, if it’s just used for passing
control on to the (Django, or PHP, …) app.
Server benchmarks are hard to do right, but here’s a relatively recent one: http://nichol.as/benchmark-of-python-web-servers
Reply
This is a howto on setting up Django on a Linux (Ubuntu) system using Nginx as a reverse proxy and Gunicorn as a Django service.
The conventional way to run Django in production these days is using
Apache2 and mod_wsgi. While there’s nothing wrong with that approach,
I prefer Nginx. I also like to be able to control Django server separately from the web server.
There are several production-ready servers for Django. The best seem to be
Gunicorn and uWSGI, and Gunicorn seems the best supported and most active project.
When running Django server separately from the web server, we need a way to start, stop and restart the Django server. A popular way for doing it in Django world is
Supervisor, altough, for Ubuntu users,
Upstart might be less hassle.
You probably already have a Django project you want to deploy, but for completenes’ sake, the steps here will use an empty toy “Hello World” Django project:
Preparation
First things first – you are usingvirtualenv, right? If not,
you should.
virtualenv --no-site-packages test cd test source bin/activate pip install gunicorn django django-admin.py startproject hello cd hello # to test the base setup works python manage.py runserver 0.0.0.0:8000
Gunicorn
Testing Django with Gunicorn is as simple as:gunicorn_django -b 0.0.0.0:8000
For production, we might want a bit more options, and we want to make sure the server is executing in the correct environment. The easiest way is to create a shell script to set it all up:
#!/bin/bash set -e LOGFILE=/var/log/gunicorn/hello.log LOGDIR=$(dirname $LOGFILE) NUM_WORKERS=3 # user/group to run as USER=your_unix_user GROUP=your_unix_group cd /path/to/test/hello source ../bin/activate test -d $LOGDIR || mkdir -p $LOGDIR exec ../bin/gunicorn_django -w $NUM_WORKERS --user=$USER --group=$GROUP --log-level=debug --log-file=$LOGFILE 2>>$LOGFILE
The number of workers is number of worker processes that will serve requests. You can set it as low as 1 if you’re on a small VPS. A popular formula is 1 + 2 * number_of_cpus on the machine (the logic being, half of the processess will be waiting for I/O,
such as database). YMMV.
Don’t forget to mark the script as executable (chmod ug+x script.sh). You can run it from the command line for testing. Note that Gunicorn by default uses 127.0.0.1:8000 address (the same as Django debug server), which is fine if Nginx is on the
same machine – you usually don’t want to have it wide open to anyone, and instead let Nginx handle incoming connections.
If you want to run several Django servers on the same machine, just make sure each uses a different port number.
Supervisor
Supervisor has extensive documentation, and this blog post is big already, so I’ll just point you tothe official docs. The config file for running our server (/etc/supervisor/conf.d/hello.conf on Debian/Ubuntu) should look like this:
[program:hello] directory = /path/to/test/hello/ user = your_unix_user command = /path/to/test/hello/script.sh stdout_logfile = /path/to/logfile.log stderr_logfile = /path/to/logfile.log
Test it with supervisorctl {start,status,stop} hello (as root).
Upstart
Ubuntu alternative is Upstart, which has a similar config file (/etc/init/hello.conf). An example:description "Test Django instance" start on runlevel [2345] stop on runlevel [06] respawn respawn limit 10 5 exec /path/to/test/hello/script.sh
Test it with service hello {start,status,stop} (as root).
Update 2011-11-14:For completeness of the Upstart setup configuration one has to add a soft link in
/etc/init.dfor a file named
helloto
/lib/init/upstart-job. So the following instruction should be executed after the .conf file has been created in /etc/init:
sudo ln -s /lib/init/upstart-job /etc/init.d/hello
Update 2011-11-14: Christophe Meessen found and fixed several errors in the procedures and config files, and also provided info about the extra Upstart configuration I missed. Thanks Christophe!
Nginx
If you don’t have it set up, you should also install Nginx. The install procedure varies from system to system. On Debian and Ubuntu systems, it’s as simple asapt-get install nginx, and other Linux distributions usually have equivalent commands.
Nginx is mostly a drop-in replacement for Apache for serving static files, though there are some
things to set up if you need to run PHP code as well.
For our setup, we need Nginx to serve as the reverse proxy for the upstream server(s). To do so, we add a server section to the config file:
server { listen 80; server_name example.com; # no security problem here, since / is alway passed to upstream root /path/to/test/hello; # serve directly - analogous for static/staticfiles location /media/ { # if asset versioning is used if ($query_string) { expires max; } } location /admin/media/ { # this changes depending on your python version root /path/to/test/lib/python2.6/site-packages/django/contrib; } location / { proxy_pass_header Server; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_connect_timeout 10; proxy_read_timeout 10; proxy_pass http://localhost:8000/; } # what to serve if upstream is not available or crashes error_page 500 502 503 504 /media/50x.html; }
Ubuntu and Debian systems keep Nginx config files in same layout as for Apache, so the above cold be added to
/etc/nginx/sites-available/hello (and enabled by symlinking from sites-enabled directory). Use
nginx -t for config test and nginx -s reload to reload the configuration.
That’s it
And that’s it. The services are really quite simple to set up once you know what goes where, the setup is flexible and performant, and the server environments are isolated so it’s possible to host many different services with varying requirements on thesame machine.
Have improvements on the above or your own helpful tips, or found an error in the post? Share in the comments.
We’re small, experienced and passionate team of web developers, doing custom app development and web consulting.
Learn more about us
18.06.2011.
Senko Rašić
Archive
22.09.2014.Building memories to last forever21.07.2014.Python packages we use
18.07.2014.Ready for EuroPython 2014
23 comments
lamby
June 18, 2011 at 2:46 pm
gunicorn in Debian has a /etc/gunicorn.d feature (like sites-enabled) so you don’t need to mess about making your own scripts.
Reply
Senko
June 18, 2011 at 6:31 pm
That’s neat, thanks. Althought, that means you have to have gunicorn installed systemwide, whereas, in my example, I installed it in virtualenv. Not that installing it systemwide would neccessarily be a problem for most people, I just like having most of
the stuff neatly tucked in virtualenv.
Reply
Mahdi Yusuf
June 18, 2011 at 2:51 pm
I have been meaning to learn this. Thanks.
Reply
Max Jaderberg
June 18, 2011 at 3:32 pm
Brilliant stuff…was really looking for a clear guide for setting up django
Reply
Jonas B.
June 18, 2011 at 4:26 pm
Why not run Django directly on uwsgi for nginx? I find it to be the far most common and well supported configuration. Performance is at least as good and there’s one less component to troubleshoot.
Reply
Senko
June 18, 2011 at 6:34 pm
I don’t have good arguments for whether gunicorn is better than the uwsgi combination. When I was looking for alternatives to mod_wsgi, I found both, but gunicorn did come up more often and I got the impression that more people are using it.
Reply
Tim
June 18, 2011 at 4:37 pm
you could do similar setup with Cherrypy + ngingx. In fact ngingx+apache2/wsgi would also give a decent performance boost to your python/django deployments (or any other non-python apache “mods”.
Reply
Viktor Petersson
June 18, 2011 at 4:51 pm
We’ve been running a very similar solution for some time on FreeBSD, and it works lika charm. If you’re running it across multiple servers, you probably want to move Nginx off of each node, and run it on a central load balancer and then have separate static
servers (Nginx works great for this too).
If you want to scale it further, you can add Varnish to the equation to get some powerfull caching.
Reply
Dana Woodman
June 18, 2011 at 7:01 pm
First off, great overview. That’s basically the setup I use for most of my Django projects.
If you haven’t had the pleasure of using Fabric yet, you should definitely check it out. It’s an excellent way to manage/deploy you Django projects, including starting/restarting Gunicorn, updating you project code and doing database management; all remotely
via ssh. It’s a great tool in the Django web development toolkit.
http://docs.fabfile.org/en/1.0.1/index.html
Reply
Simon Pantzare
June 18, 2011 at 11:26 pm
During development, it may be preferable to run supervisord inside the virtualenv as well. Here is a small project of mine intended to make this easy:
https://github.com/pilt/pewatch
Reply
Elf M. Sternberg
June 19, 2011 at 5:22 am
Thanks for this. I’ve been shy about using Gunicorn, mostly because I’ve been using an Nginx + Apache/WSGI + Varnish trio for my django & media issues. I may look into it again for my next project. (Then again, my next project may be couchdb as my front-end
server, and node.js as a back-end, so…)
Reply
Rich
June 19, 2011 at 7:42 am
Can you say a bit more about the benefits gained from using this setup over Apache? Numbers would be great, too..
Reply
Senko
June 20, 2011 at 1:34 am
I didn’t want to get into whys, as the choice of the server really depends on the specific use case, so YMMV. I prefer Nginx because it’s really good at what it does (serving static assets, proxying/load balancing slower upstreams for dynamic stuff).
I also host a bunch of apps written on various platforms (Django, Flask, Tornado, Node.js, PHP) on the same system, so I need to use some sort of a reverse proxy anyways. In such a setup, there’s no need to involve Apache too, if it’s just used for passing
control on to the (Django, or PHP, …) app.
Server benchmarks are hard to do right, but here’s a relatively recent one: http://nichol.as/benchmark-of-python-web-servers
Reply
相关文章推荐
- Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 16.04和记录
- Minimal Nginx and Gunicorn configuration for Django projects
- Setting up Django with Nginx, Gunicorn, virtualenv, supervisor and PostgreSQL
- [django] Deploy Django Applications Using uWSGI and Nginx on Ubuntu 14.04
- How to setup Apache and mod_python and django
- nginx+gunicorn运行django
- WSGI using uWSGI and nginx on Ubuntu 12.04 (Precise Pangolin)
- django+gunicorn+nginx部署项目 入门经验
- 给我一台全新的服务器,使用nginx+gunicorn+supervisor部署django
- django部署方式之Gunicorn+Django+nginx+mysql
- nginx+gunicorn+django
- Django+nginx+gunicorn部署流程(二)
- Django部署------在云服务器上用django+nginx+gunicorn进行部署
- 【Python】Centos7下部署Django(nginx+gunicorn)
- apache(nginx)+django+virutalenv(virtualenvwrapper)+gunicorn+supervisor配置高效web环境
- django 学习笔记2: install django and setup first django project
- Setting up Django and your web server with uWSGI and nginx
- Django+gunicorn+Nginx环境的搭建
- ubuntu/linux nginx+Gunicorn+django 部署方法详细教程
- python+django+gunicorn+nginx的配置