Skip to content

Instantly share code, notes, and snippets.

@henryyang42
Last active January 22, 2016 16:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save henryyang42/e70c7f444788e674c4da to your computer and use it in GitHub Desktop.
Save henryyang42/e70c7f444788e674c4da to your computer and use it in GitHub Desktop.

#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.

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