Friday, October 4, 2013

Python framework Flask+Nginx+UWSGI on virtualenv

This post includes how to install nginx, uwsgi, flask and python environment. 


Some Tools Installation 

  • yum -y groupinstall "Development tools"
  • yum -y install gcc ncurses-devel zlib-devel bzip2-devel openssl-devel make

Python Installation

  • cd /var/tmp
  • wget http://www.python.org/ftp/python/2.7.5/Python-2.7.5.tgz
  • tar zxvf Python-2.7.5taz
  • cd Python-2.7.5
  • ./configure --with-threads --enable-shared
  • make && make altinstall

Python check (check your python installation)

  • cd /var/tmp
  • python2.7 (after this command if you enter the python console that means your python installation is successful, otherwise maybe you will encounter "python2.7: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory")
  • vi /etc/ld.so.conf (add /usr/local/lib into this document)
  • /sbin/ldconfig
  • /sbin/ldconfig -v
  • python2.7 (double check again, this time you can enter the python console)

Pip Installation

  • cd /var/tmp
  • wget http://python-distribute.org/distribute_setup.py
  • python2.7 distribute_setup.py
  • wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py
  • python2.7 get-pip.py

Virtualenvwrapper Installation

  • pip-2.7 install virtualenvwrapper

Create User for nginx

  • groupadd nginx
  • useradd -g nginx nginx
  • passwd nginx
  • su nginx
  • vi ~/.bashrc (change to nginx user and add the following two lines)
export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python2.7
source /usr/local/bin/virtualenvwrapper.sh 2 >/dev/null
  • source ~/.bashrc #reload this file

Create Virtualenv and uwsgi installation

  • su nginx
  • mkvirtualenv -p /usr/local/bin/python2.7 env27
  • workon env27 ##change to env27
  • pip-2.7 install uwsgi # install uwsgi

Nginx Installation

  • su root
  • yum -y install pcre-devel
  • cd /var/tmp
  • wget http://nginx.org/download/nginx-1.2.3.tar.gz
  • su nginx  # change to nginx
  • tar xvfz nginx-1.2.3.tar.gz
  • cd nginx-1.2.3
  • ./configure --user=nginx --group=nginx --prefix=/home/nginx/SAgent --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module
  • make && make install

Create some folders for webapps: 

  • mkdir /home/nginx/SAgent/sites-available
  • mkdir /home/nginx/SAgent/sites-enabled
  • mkdir /home/nginx/SAgent/webapps
  • mkdir /home/nginx/SAgent/uwsgi
  • mkdir /home/nginx/SAgent/uwsgi/conf
  • mkdir /home/nginx/SAgent/uwsgi/logs
  • mkdir /home/nginx/SAgent/uwsgi/run/

Create nginx as service:

  • sudo vi /etc/init.d/nginx (put the following content in this new file)
#!/bin/sh
#
# nginx - this script starts and stops the nginx daemin
#
# chkconfig: 2345 80 25
# description: Startup script for nginx webserver. Place in /etc/init.d and
# For CentOS/Redhat run: 'chkconfig --add nginx'
# processname: nginx
# config:      /home/nginx/SAgent/conf/nginx.conf
# pidfile:     /home/nginx/SAgent/logs/nginx.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

nginx="/home/nginx/SAgent/sbin/nginx"
prog=$(basename $nginx)

NGINX_CONF_FILE="/home/nginx/SAgent/conf/nginx.conf"
lockfile=/var/lock/subsys/nginx

start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    configtest || return $?
    stop
    sleep 1
    start
}

reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}
force_reload() {
    restart
}

configtest() {
  $nginx -t -c $NGINX_CONF_FILE
}

rh_status() {
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac

  • sudo chmod +x /etc/init.d/nginx 
  • sudo /sbin/chkconfig nginx on
  • sudo /sbin/chkconfig --list nginx  # check

Create uwsgi as service: 

  • sudo vi /etc/init.d/uwsgi # put the following content in this new file
#!/bin/sh
#
# uwsgi - This script starts and stops all configured uwsgi applications
#
# chkconfig:   2345 80 25
# description: uWSGI is a program to run applications adhering to the
#              Web Server Gateway Interface.
# processname: uwsgi
# config:      /etc/sysconfig/uwsgi

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

# initialize python virtualenv
VIRT_ENV=env27 #env33 #env27 #env3.21
PY_VER=2.7 #3.3 #2.7     #3.2
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
WORKON_HOME=/home/nginx/.virtualenvs
VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python$PY_VER
. /usr/local/bin/virtualenvwrapper.sh 2> /dev/null
workon $VIRT_ENV

uwsgi=`which uwsgi`
prog=$(basename "$uwsgi")
UWSGI_ROOT="/home/nginx/SAgent/uwsgi"
UWSGI_CONF_DIR="$UWSGI_ROOT/conf"
UWSGI_LOG_FILE="$UWSGI_ROOT/uwsgi.log"
UWSGI_PID_FILE="/var/run/uwsgi.pid"
# force to all vassals
export UWSGI_VASSAL_HOME="$WORKON_HOME/$VIRT_ENV"
UWSGI_ARGS="--emperor $UWSGI_CONF_DIR --binary-path $uwsgi"

start() {
    [ -x $uwsgi ] || exit 5
    [ -d $UWSGI_CONF_DIR ] || exit 6
    echo -n $"Starting $prog: "
    daemon --pidfile="$UWSGI_PID_FILE" $uwsgi $UWSGI_ARGS --pidfile $UWSGI_PID_FILE --daemonize $UWSGI_LOG_FILE
    retval=$?
    echo
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc -p "$UWSGI_PID_FILE" $prog
    retval=$?
    echo
    return $retval
}

restart() {
    stop
    sleep 1
    start
}
reload() {
    echo -n $"Reloading $prog: "
    killproc -p "$UWSGI_PID_FILE" "$prog" -HUP
    retval=$?
    echo
    return $retval
}
force_reload() {
    restart
}

rh_status() {
    status -p "$UWSGI_PID_FILE" "$prog"
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|reload|force-reload}"
        exit 2
esac
  • sudo chmod +x /etc/init.d/uwsgi
  • sudo /sbin/chkconfig uwsgi on
  • sudo /sbin/chkconfig --list uwsgi  # check

Flask webframework installation

  • cd /var/tmp
  • wget http://pypi.python.org/packages/source/F/Flask/Flask-0.10.tar.gz
  • tar zxvf Flask-0.10.tar.gz
  • cd Flask-0.10
  • python2.7 setup.py install

Create demo application

  • mkdir /home/nginx/DemoAgent/sites-available/demo
  • mkdir /home/nginx/DemoAgent/webapps/demo
  • vim /home/nginx/DemoAgent/webapps/demo/demo.py # add the following python code in demo.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

if __name__ == "__main__":
app.run()
  • python2.7 demo.py # check 127.0.0.1:5000, you can see the hello world. 

Some configurations for nginx and uwsgi

  • ln -s /home/nginx/DemoAgent/sites-available/demo /home/nginx/DemoAgent/sites-enabled/demo # create symbolic link
  • vi /home/nginx/DemoAgent/uwsgi/conf/demo.ini # the ini file must has the same name as webapps folder. e.g., demo, add the following content into demo.ini

[uwsgi]
processes = 1
master = true
limit-as = 1024
reload-on-as = 512
reload-on-rss = 256
memory-report = true
socket = /home/nginx/DemoAgent/uwsgi/run/%n.sock
logto = /home/nginx/DemoAgent/uwsgi/logs/%n.log
manage-script-name = 1
auto-procname = true
enable-threads = 5
procanme-prefix-spaced = %n
chdir = /home/nginx/DemoAgent/webapps/%n
mount = /%n=/home/nginx/DemoAgent/webapps/%n/demo.py
callable = app



  • vim /home/nginx/DemoAgent/conf/nginx.conf # in {http{server}} section, modify location section content

  location /demo {
    set   $app   demo;
    include uwsgi_params;
    uwsgi_param SCRIPT_NAME "/${app}";
    uwsgi_param UWSGI_SCRIPT index;
    uwsgi_param UWSGI_MODULE index;
    uwsgi_param UWSGI_PYHOME "${document_root}/${app}";
    uwsgi_param UWSGI_CHDIR "${document_root}/${app}";
    uwsgi_pass unix:/home/nginx/DemoAgent/uwsgi/run/${app}.sock;
 }


  • service nginx start
  • service uwsgi start
URL: 127.0.0.1/demo # you can see the Hello World responded from demo.py