Setting up Green Unicorn, nginx, supervisord and fabric on CentOS 5.5 for Django
Join the DZone community and get the full member experience.
Join For FreeWhen I first started working with Django I deployed my apps using Apache and mod_python. Then after a little while I started playing with nginx and switched my setup so that nginx was serving the static content and reverse proxied requests back to Apache and mod_python. Not too long after that, I switched out mod_python with mod_wsgi and ran mod_wsgi in daemon mode.
This setup worked well for a while, but one thing I never really liked was the fact that I needed to run Apache which is pretty heavy even when you strip out all the unused modules. Apache is great, but all I was really using it for was a router between nginx and mod_wsgi, I wasn't using any of the other features in Apache.
I looked at fastcgi and uswgi and they looked good, but for one reason or another I never made the jump. Recently I have been hearing a lot of good things about green unicorn, so I decided to check it out. When I first looked at it, it was fairly new and because of this a little concerned with stability, so I kept and eye on it and watched it mature.
While I was waiting for green unicorn, I ended up doing a lot of research on the new python hosting services that recently hit the market. Three out of the five services that I looked were using green unicorn, the other two were using uWSGI.
The fact that these three services are basing there new businesses on green unicorn gave it a lot of credibility. Not too long after that I started playing with green unicorn to see what it would take to get my sites up and running.
The first thing that I noticed was that I didn't need to create a wsgi file if I used their gunicorn_django command, which was pretty sweet. The fact that they built it into the service shows you that django is a first class citizen.
The second thing that I noticed was that I needed a way to start up green unicorn and keep it running, something that apache does for you with mod_wsgi. I did a little bit of research and found out that supervisord would work perfectly for what I needed to do with green unicorn.
Because seeing is better then reading, I'll guide you throw the steps
that you will need to do in order to get your system setup in a way
that will make using green unicorn very easy, especially if you want to
run more then one website on your server. I'm going to use a 256MB
rackspace cloud instance running centos 5.5.
Create a Rackspace Cloud Server
Go into the rackspace cloud server management website and allocate
yourself a new 256MB CentOS 5.5 server or if you prefer do the same
thing using their API. Now that you have a server and the root password,
follow along step by step to get you system all setup.
Software and versions
- RackSpace Cloud Server 256MB
- CentOS 5.5
- Python 2.6.6
- nginx 1.0.4
- supervisord 3.0a10
- virtualenv 1.6.1
- pip 1.0.1
- gunicorn 0.12.2
- fabric 1.1.0
Bitbucket project
To make things easier I have created a django bootstrap project directory with all of the file used in the blog post. It is located here, so feel free to clone and fork.
https://bitbucket.org/kencochrane/django-gunicorn-nginx-supervisord-bootstrap/
Login to server
ssh root@<RackSpaceIP>
Update packages
yum -y update
Install packages
You might not need all of these right now, but I normally need these down the line, so doing them all now.
yum -y install emacs readline-devel ncurses-devel libevent-devel glib2-devel libjpeg-devel freetype-devel bzip2 bzip2-devel bzip2-libs openssl-devel pcre pcre-devel gpg make gcc yum-utils unzip
Add a Django User as a System User
useradd -d /opt/django -m -r django
Set Password for Django to What Ever You Want
passwd django
Setup Directories
mkdir -p /opt/django mkdir -p /opt/django/apps mkdir -p /opt/django/logs mkdir -p /opt/django/logs/nginx mkdir -p /opt/django/logs/apps mkdir -p /opt/django/configs mkdir -p /opt/django/scripts mkdir -p /opt/django/htdocs mkdir -p /opt/django/tmp mkdir -p /opt/django/configs/nginx mkdir -p /opt/django/configs/supervisord mkdir -p /opt/django/apps/my_app
Add Blank HTML Page
echo "<html><body>nothing here</body></html> " > /opt/django/htdocs/index.html
Install Zlib
# download from zlib.net mkdir -p /tmp/downloads cd /tmp/downloads wget http://www.zlib.net/zlib-1.2.5.tar.gz tar -xvzf zlib-1.2.5.tar.gz cd zlib-1.2.5 ./configure -s make install
Install Python 2.6.6
CentOS 5.5 doesn't come with python2.6 pre installed so we need to do that on our own.
mkdir -p /tmp/downloads cd /tmp/downloads wget http://www.python.org/ftp/python/2.6.6/Python-2.6.6.tgz tar -xvzf Python-2.6.6.tgz cd Python-2.6.6 ./configure --enable-shared make make altinstall
Add the Following to /etc/profile
We need to add the lib path to the LD_LIBRARY_PATH or else you will get an error saying it can't find libpython2.6.so.1.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/:/usr/local/lib64/
Source the New Profile
source /etc/profile
Install Distribute
mkdir -p /tmp/downloads cd /tmp/downloads curl -O http://python-distribute.org/distribute_setup.py python2.6 distribute_setup.py
Install Pip & virtualenv
mkdir -p /tmp/downloads cd /tmp/downloads curl -O -k https://raw.github.com/pypa/pip/master/contrib/get-pip.py python2.6 get-pip.py pip install virtualenv
Install supervisor
pip install supervisor
Install mercurial
pip install mercurial
Install nginx
mkdir -p /tmp/downloads cd /tmp/downloads wget http://nginx.org/download/nginx-1.0.4.tar.gz tar -xzvf nginx-1.0.4.tar.gz cd nginx-1.0.4 ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module --with-http_stub_status_module make /etc/init.d/nginx stop sleep 2 sudo make install sudo chmod +x /usr/local/sbin/nginx
Install my app
Add first virtualenv
cd /opt/django/apps/my_app/ virtualenv --distribute --no-site-packages v0.1 # make this a post_create hook? touch /opt/django/apps/my_app/v0.1/.venv cd /opt/django/apps/my_app/v0.1/ hg clone https://bitbucket.org/kencochrane/django-gunicorn-nginx-supervisord-bootstrap my_app ln -s /opt/django/apps/my_app/v0.1 /opt/django/apps/my_app/current ln -s /opt/django/apps/my_app/current/my_app/conf/nginx.conf /opt/django/configs/nginx/myapp.conf ln -s /opt/django/apps/my_app/current/my_app/conf/supervisord.conf /opt/django/configs/supervisord/myapp.conf # activate the ve source /opt/django/apps/my_app/current/bin/activate cd /opt/django/apps/my_app/current/my_app/ ./bootstrap.py
Configure nginx
# as root mkdir -p /etc/nginx ln -s /opt/django/apps/my_app/current/my_app/server/etc/nginx.conf /etc/nginx/nginx.conf ln -s /usr/local/nginx/conf/mime.types /etc/nginx/mime.types ln -s /opt/django/apps/my_app/current/my_app/server/init.d/nginx /etc/init.d/nginx chmod 755 /etc/init.d/nginx chkconfig --add nginx chkconfig nginx on
Configure Supervisord
# as root ln -s /opt/django/apps/my_app/current/my_app/server/etc/supervisord.conf /etc/supervisord.conf ln -s /opt/django/apps/my_app/current/my_app/server/init.d/supervisord /etc/init.d/supervisord chmod 755 /etc/init.d/supervisord chkconfig --add supervisord chkconfig supervisord on
Firewall
We need to open up the firewall so that we are allowed connection, if you don't know anything about this, check out these links.
- http://cloudservers.rackspacecloud.com/index.php/Firewalls
- http://cloudservers.rackspacecloud.com/index.php/Introduction_to_iptables
- http://cloudservers.rackspacecloud.com/index.php/Sample_iptables_ruleset
# Open http port 80 iptables -I RH-Firewall-1-INPUT -p tcp --dport 80 -j ACCEPT
.bashrc file changes
I can't remember where I saw this little trick, if you know please let me know so that I can give them credit. If you put a file in your mercurial directory called .venv, when you cd into the directory this little bash hack will automatically activate your virtual environment for you. This allows you to have something similar to virtualenvwrapper in this custom setup.
Add this code to the .bashrc file
emacs /opt/django/.bashrc # # User specific aliases and functions has_virtualenv() { if [ -e .venv ]; then deactivate >/dev/null 2>&1 source bin/activate fi } venv_cd () { cd "$@" && has_virtualenv } alias cd="venv_cd" #end of changes # source the file to get new changes in active shell source /opt/django/.bashrc
Change Permissions of the Django Home Directory to Django
This cleans up and left over root ownership
chown -R django:django /opt/django/*
Switch to Django User
su - django
Start up nginx
service nginx start
Startup supervisord
service supervisord start
Test nginx and supervisord
Check supervisord status
supervisorctl status my_app RUNNING pid 13594, uptime 0:00:05
To check nginx go to the IP or domain name for your rackspace server in your browser and make sure it worked.
Updating the Application Using Fabric
Inside of the bitbucket project directory there is a file called fabfile.py. This file will allow you to update the application from your machine whenever you want just by calling one command.
It will prompt you for your hostname and password for the django
user. Then it will go out to the rackspace server and pull and update
the app and restart the application in supervisord. It is very basic for
right now, but should get you started if you want to do more advanced
stuff.
fab update_server
Now that we have everything setup, if you want to add a new application to our setup all we need to do is:
- create a new directory under apps
- create the virtualenv
- run the bootstrap to install the software
- make sure that the application has a supervisord and nginx configuration file
- symlink those files to the correct locations in the config directory
- run any python management commands you might need to run (syncdb, migrate, etc)
- reload supervisord and nginx
- you should be good to go.
I hope this was helpful to someone besides myself, if it was helpful for you please let me know in the comments.
Source: http://kencochrane.net/blog/2011/06/django-gunicorn-nginx-supervisord-fabric-centos55/
Opinions expressed by DZone contributors are their own.
Comments