Deploying a Flask web application on FreeBSD • 20 Feb 2013
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.

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.

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.

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.

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
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!
Dude • 30 Mar 2017
svn checkout and update makes a fully functional workcopy including files in .svn dir, you don't need it on production so use svn export instead to get only project files without any unnecessary things
JoongSeob vito kim • 11 Jul 2013
Nice post. It helps much! Thank you.