#Deploy NTHUOJ with Nginx, Gunicorn, virtualenv, supervisor and MySQL Adapted from http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/
##Prerequisites ###1. Have a clean clone of NTHUOJ inside deploy folder
mkdir deploy
cd deploy
git clone https://github.com/bruce3557/NTHUOJ_web.git
###2. Install NTHUOJ dependencies
sudo apt-get update
sudo apt-get install mysql-server python-mysqldb libmysqlclient-dev
sudo apt-get install python-pip
sudo apt-get install python-dev
sudo apt-get install python-virtualenv
sudo apt-get install supervisor
sudo apt-get install libjpeg-dev
sudo apt-get install dos2unix
sudo apt-get install nginx
sudo apt-get install npm nodejs
sudo npm install -g bower
sudo ln -s /usr/bin/nodejs /usr/bin/node
###3. Create a virtual Python environment in the application directory
virtualenv .
source bin/activate
pip install -r requirements.txt
###4. Setup mysql
mysql -uroot -p
mysql> create database nthuoj character set utf8;
###5. Finally, let's try to run it
cd NTHUOJ_web/
python install.py
python manage.py runserver
Now, you should be able to access the website from http://127.0.0.1:8000/
.
Please don't be scared if it looks ugly, static files (CSS, JS, ...) will not be served under DEBUG = False
. We will manage it using Nginx
in the next step.
##Setup Nginx for serving static files
We have installed Nginx
in prerequisites. Let's test if it has been installed correctly.
Type sudo service nginx start
, you should see Welcome to nginx!
from http://127.0.0.1
If the result is correct, you can create a file /etc/nginx/sites-available/nthuoj
like below. Please note that all /home/henrryyang42/deploy
should be replaced to your path to deploy
upstream nthuoj_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response (in case the Unicorn master nukes a
# single worker for timing out).
server unix:/home/henrryyang42/deploy/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name nthuoj;
client_max_body_size 4G;
access_log /home/henrryyang42/deploy/logs/nginx-access.log;
error_log /home/henrryyang42/deploy/logs/nginx-error.log;
location /static/ {
alias /home/henrryyang42/deploy/NTHUOJ_web/static/;
}
location /media/ {
alias /home/henrryyang42/deploy/NTHUOJ_web/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;
# set "proxy_buffering off" *only* for Rainbows! when doing
# Comet/long-poll stuff. It's also safe to set if you're
# using only serving fast clients with Unicorn + nginx.
# Otherwise you _want_ nginx to buffer responses to slow
# clients, really.
# proxy_buffering off;
# Try to serve static files from nginx, no point in making an
# *application* server like Unicorn/Rainbows! serve static files.
if (!-f $request_filename) {
proxy_pass http://nthuoj_server;
break;
}
}
# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /home/henrryyang42/deploy/NTHUOJ_web/static/;
}
}
Create a symbolic link in the sites-enabled
folder and restart Nginx
midir ../logs
sudo ln -s /etc/nginx/sites-available/nthuoj /etc/nginx/sites-enabled/nthuoj
python manage.py collectstatic
sudo service nginx restart
Now, you should be able to access static files! You can test if you can see http://127.0.0.1/static/js/base.js
correctly from that url.
At this stage you may find that instead of that static file, you encounter file not found page. This may be caused by the default
configuration file, which is installed with Nginx and masks your new site's configuration. If you don't plan to use it, delete the symbolic link to this file /etc/nginx/sites-enabled/default
.
##Setup Gunicorn In production we won’t be using Django’s single-threaded development server, but a dedicated application server called gunicorn.
We have installed Gunicorn
in prerequisites. Let's test if it has been installed correctly.
gunicorn nthuoj.wsgi:application --bind 127.0.0.1:8000
The site is still ugly, since our static files are served from port 80.
Gunicorn is installed and ready to serve our app. Let's set some configuration options to make it more useful. I like to set a number of parameters, so let's put them all into a small BASH script, which I save as bin/gunicorn_start
#!/bin/bash
NAME="nthuoj" # Name of the application
DJANGODIR=/home/henrryyang42/deploy/NTHUOJ_web # Django project directory
SOCKFILE=/home/henrryyang42/deploy/run/gunicorn.sock # we will communicte using this unix socket
USER=henrryyang42 # the user to run as
GROUP=henrryyang42 # the group to run as
NUM_WORKERS=5 # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=nthuoj.settings # which settings file should Django use
DJANGO_WSGI_MODULE=nthuoj.wsgi # WSGI module name
echo "Starting $NAME as `whoami`"
# Activate the virtual environment
cd $DJANGODIR
source ../bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR
# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec ../bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $NUM_WORKERS \
--user=$USER --group=$GROUP \
--bind=unix:$SOCKFILE \
--log-level=debug \
--log-file=-
Please change all the paths, name, group, etc to yours. We also make the script executable.
sudo chmod u+x ../bin/gunicorn_start
./../bin/gunicorn_start
Now, you can access NTHUOJ from 127.0.0.1
and is supposed to be nice looking because we have the static files served.
##Starting and monitoring with Supervisor
Our gunicorn_start
script should now be ready and working. We need to make sure that it starts automatically with the system and that it can automatically restart if for some reason it exits unexpectedly. These tasks can easily be handled by a service called supervisord
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 application we'll create a file named /etc/supervisor/conf.d/nthuoj.conf
with this content:
[program:nthuoj]
command = /home/henrryyang42/deploy/bin/gunicorn_start ; Command to start app
user = henrryyang42 ; User to run as
stdout_logfile = /home/henrryyang42/deploy/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
After you save the configuration file for our program you can ask supervisor to reread configuration files and update (which will start your the newly registered app).
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status nthuoj
NTHUOJ should now be automatically started after a system reboot and automatically restarted if it ever crashed for some reason now.