michielovertoom.com

Deploying a Flask web application on FreeBSD • 20 Feb 2013

Flask logo Go web scale with Flask! Flask is a small framework which can be used to build web applications. It also has good documentation. Flask's built-in webserver is only usable for development, so for production purposes I use gunicorn as the webserver. It will run a few instances of the web application in a few worker threads. Nginx as a reverse-proxy is used to free the worker threads from requests by slow clients (like mobile phones). And lastly, supervisor is used to monitor the web application and restart it, should it terminate for some reason. It also starts the web application when the server reboots.

Typographical ornament

Flask and the web application

Install FreeBSD on a machine. Become root and install Python if it's not already installed. Then install pip and Flask (via pip). Alternatively, you could install the port /usr/ports/www/py-flask.

# cd /usr/ports/devel/py-pip # make install clean # pip install flask

This is the source code of the example web application (in this article, it lives in /usr/home/user/prj/python/flask-examples/example2.py):

import flask app = flask.Flask(__name__) from werkzeug.contrib.fixers import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app) @app.route("/") def index(): return "Hello, " + flask.request.remote_addr if __name__ == "__main__": app.run(host="0.0.0.0")

Start the web application: # python example2.py * Running on http://0.0.0.0:5000/

...point a webbrowser, preferably on another machine, to http://SERVER:5000/, where SERVER is the IP address of the machine you run the web application on, and the app should respond with something like this:

Hello, 192.168.5.30

Ok, the webapp works. But it still uses the built-in development webserver which is not suitable for production environments.

Typographical ornament

Gunicorn

Let's start a real webserver and create 4 worker-threads for the web application. First, install gunicorn, either by installing the port www/py-gunicorn or via pip:

# pip install gunicorn # rehash # gunicorn -w 4 -b 0.0.0.0:8005 example2:app

Point your browser to http://SERVER:8005 to verify it still works. Then, type Control-C to stop the web application.

Typographical ornament

Nginx

The next step is to put nginx in front of it, to make the application resilient to many concurrent requests from slow clients:

# cd /usr/ports/www/nginx # make install clean

This is a simple /usr/local/etc/nginx/nginx.conf which serves static content from the /www directory:

events { worker_connections 1024; } http { server { location / { root /www; index index.html; } } }

To proxy our web application, we need the following server entry in /usr/local/etc/nginx/nginx.conf:

server { listen 81; server_name _; location / { proxy_pass http://127.0.0.1:8005/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }

Add this to /etc/rc.conf:

nginx_enable="yes"

Now start nginx:

# /usr/local/etc/rc.d/nginx start

If you now point your webbrowser to http://SERVER:81, you'll get a 'Bad Gateway' error from nginx, because the web application is not running.

Typographical ornament

Supervisor

We have to make our web application controllable by a monitoring program. Should the web application crash for some reason, it has to be restarted. Also in the case of a server reboot, it must be started. Supervisor does the job.

# cd /usr/ports/sysutils/py-supervisord # make install clean

And put this in /etc/rc.conf:

supervisord_enable="yes"

Add the web application to /usr/local/etc/supervisord.conf as 'flaskexample':

[unix_http_server] file=/var/run/supervisor/supervisor.sock [supervisord] logfile=/var/log/supervisor/supervisord.log pidfile=/var/run/supervisor/supervisord.pid user=root [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///var/run/supervisor/supervisor.sock [program:flaskexample] command=/usr/local/bin/gunicorn -w 4 -b 127.0.0.1:8005 example2:app directory=/home/user/prj/python/flask-examples user=root autostart=true autorestart=true stdout_logfile=NONE stderr_logfile=NONE ; Handy for debugging: ; stdout_logfile=/var/log/supervisor/webapp.stdout ; stderr_logfile=/var/log/supervisor/webapp.stderr

...and then start the supervisord daemon. It should start the web application.

# /usr/local/etc/rc.d/supervisord start Starting supervisord. # supervisorctl status flaskexample RUNNING pid 5778, uptime 0:00:06

Point your browser to http://SERVER:81 and see if it responds with something like "Hello, 192.168.5.30".

Deploy via Subversion

When I use subversion to deploy updates to a webserver, I often use this script, 'updatesite':

svn update sudo supervisorctl restart webapp

That's it! If you have any questions or remarks, please email me.

Comments

JoongSeob vito kim • 11 Jul 2013

Nice post. It helps much! Thank you.

Jordan • 19 Jul 2014

Thanks for the guide!

Gerald • 8 Dec 2014

Thank you very much. It is extreme helpful.

Dani • 1 Oct 2015

Awesome man!

Leave a comment

name (required)



content last edited on March 17, 2013, 14:51 - rendered in 3.22 msec