Published on

nginx configuration for uwsgi for Flask

Authors

/etc/nginx/conf.d/site.conf :

lua
server {
 server_name example.com www.example.com;
 root home/example/flask/static;

 location ~ ^/(img|js|css)/ {  # |pi||ext|theme
  root                    /home/example/flask/static;
  add_header              Cache-Control public;
  #expires                 30d;
  #access_log              off;
 }

 location / { try_files $uri @yourapplication; }

 location @yourapplication {
    include uwsgi_params;
    uwsgi_pass unix:/tmp/uwsgi_example.sock;
 }
}

This must be married with a uwsgi service started by a script in /etc/init.d/ :

bash
#!/bin/bash

# uwsgi - Use uwsgi to run python and wsgi web apps.
#
# chkconfig: - 85 15
# description: Use uwsgi to run python and wsgi web apps.
# processname: uwsgi

PATH=/opt/uwsgi:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/uwsgi

PYTHONENV=/usr

OWNER=uwsgi

NAME=uwsgi
DESC=uwsgi

test -x $DAEMON || exit 0

# Include uwsgi defaults if available
if [ -f /etc/sysconfig/uwsgi ] ; then
	. /etc/sysconfig/uwsgi
fi

set -e

get_pid() {
    if [ -f /var/run/$NAME.pid ]; then
        echo `cat /var/run/$NAME.pid`
    fi
}

#DAEMON_OPTS="-s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 4 -d /var/log/uwsgi.log --pidfile /var/run/$NAME.pid --plugins python --pythonpath $PYTHONPATH --module $MODULE"

DAEMON_OPTS="-s /tmp/uwsgi_cohortion.sock -M 4 -t 30 -A 4 -p 4 -d /var/log/uwsgi.log --pidfile /var/run/$NAME.pid --plugins python --pythonpath $PYTHONPATH --module $MODULE --callable $CALLABLE -H $PYTHONENV"

case "$1" in
  start)
	echo -n "Starting $DESC: "
        PID=$(get_pid)
        if [ -z "$PID" ]; then
            [ -f /var/run/$NAME.pid ] && rm -f /var/run/$NAME.pid

            touch /var/run/$NAME.pid
            chown $OWNER /var/run/$NAME.pid
	    su - $OWNER -pc "$DAEMON $DAEMON_OPTS"
	    echo "$NAME."
        fi

	;;
  stop)
	echo -n "Stopping $DESC: "
        PID=$(get_pid)
        [ ! -z "$PID" ] && kill -s 3 $PID &> /dev/null
        if [ $? -gt 0 ]; then
            echo "was not running"
            exit 1
        else
	    echo "$NAME."
            rm -f /var/run/$NAME.pid &> /dev/null
        fi
	;;
  reload)
        echo "Reloading $NAME"
        PID=$(get_pid)
        [ ! -z "$PID" ] && kill -s 1 $PID &> /dev/null
        if [ $? -gt 0 ]; then
            echo "was not running"
            exit 1
        else
	    echo "$NAME."
            rm -f /var/run/$NAME.pid &> /dev/null
        fi
	;;
  force-reload)
        echo "Reloading $NAME"
        PID=$(get_pid)
        [ ! -z "$PID" ] && kill -s 15 $PID &> /dev/null
        if [ $? -gt 0 ]; then
            echo "was not running"
            exit 1
        else
	    echo "$NAME."
            rm -f /var/run/$NAME.pid &> /dev/null
        fi
        ;;
  restart)
        $0 stop
        sleep 2
        $0 start
	;;
  status)
	killall -10 $DAEMON
	;;
      *)
	    N=/etc/init.d/$NAME
	    echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2
	    exit 1
	    ;;
esac
exit 0

And this has configuration information in /etc/sysconfig/uwsgi . The following works for (i) a core flask file at /home/example/flask/example.py, and (ii) for a flask module (rather than a single file executable), /etc/sysconfig/uwsgi (for a flask module starting at /home/example/flask/example/init.py) :

ini
PYTHONPATH=/home/example/flask
MODULE=example
CALLABLE=app
PYTHONENV=/home/example/env

Note that (under /home/example/env) there's a python virtualenv created with :

bash
# As root :
yum install python-virtualenv

# As user :
cd ~
virtualenv env

Also note that there needs to be a python stub to actually declare the flask 'app' :

CASE1 : there's a python file 'example.py' in /home/example/flask/example.py that defines the flask application 'app'. This file can also define a main, so that it can be used as a dev-machine launcher too. The standard flask minimal intro file will work fine : The body of the file defines 'app' which will be picked up by uwsgi (for production), or run via the " if name == 'main': " pattern for development.

CASE2 : there's a python file 'init.py' in /home/example/flask/example/ that defines the flask application 'app'. To make this setup function as a dev machine, you'll also need to create something that runs this setup locally. The simplest seems to be to create 'run.py' (in the same directory from which the example module branches off) :

python
from example import app

HOST = 'localhost'   # This restricts incoming calls to the local machine
HOST = '0.0.0.0'     # This allows incoming calls from outside the machine (Windows will ask for Firewall permission)
PORT = 7891          # Arbitrary port

app.run(host=HOST, port=PORT, debug=True, )