Building Websites with Python and Flask
Over the course of my learning I have ended up with a base configuration for serving Python web applications. This configuration utilises the nginx web server together with uwsgi as the Python > web app gateway. As is the norm, it is recommended to utilise a python virtual environment to isolate your software requirements. The full stack is:
- virtualenv
- Python
- Flask
- uwsgi
- Supervisor
- nginx
The standard operating system I go to for web apps such as this is Ubuntu. The steps detailed below are all given for that operating system.
Create users
Create a user and group under which the services will run. You could use your own account but it is safer to use something like www.
$ sudo groupadd www
$ sudo adduser www -g www
Create the application directory
We now create the top level directory under which your web applications will be served. The directory we have specified here is also the default directory for Apache under Ubuntu. If Apache is installed on your system you will have to decide whether you go with this choice or go for a different location.
$ sudo mkdir /var/www
$ sudo chown -R www:www /var/www
Your application will be hosted under /var/www
so if your application is myapp then the direcory will be /var/www/myapp
. We will do this later but let’s take a moment to describe the target layout.
/var/www/myapp
├── venv < Directory created by virtualenv
│ ├── bin
│ │ ├── activate
│ │ ├── python
│ │ └── uwsgi
│ ├── include
│ ├── lib
│ └── local
├── manage.py < Manage script if you use Flask-Scripts
├── myapp < Your application directory
│ ├── static
│ │ ├── css
│ │ └── js
│ ├── templates
│ ├── __init.py__
│ ├── models.py
│ ├── routes.py
│ └── forms.py
├── myapp_nginx.conf < nginx configuraiton file
└── myapp_uwsgi.ini < uwsgi configuration file
Install the software
Install the virtualenv package. Python should already be installed for an Ubuntu distribution.
$ sudo apt-get install python-virtualenv
Create the virtualenv
In this step we create our application directory, create and activate the virtual environment and then install Flask.
$ cd /var/www/myapp
$ virtualenv venv
$ . venv/bin/activate
$ pip install flask
nginx configuration
Create or edit the nginx configuration file.
This nginx configuration file defines virtual hosts.
# /etc/nginx/nginx.conf
user www;
worker_processes 1;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use kqueue | rtsig | epoll | /dev/poll | select | poll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
client_max_body_size 20M;
keepalive_timeout 0;
uwsgi_read_timeout 86400;
uwsgi_send_timeout 86400;
#gzip on;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen 443 ssl;
ssl_certificate /var/www/example.com.pem;
ssl_certificate_key /var/www/newkey.pem;
server_name demo.example.com;
access_log /var/log/demo/access_log;
root /var/www/demo;
location / {
uwsgi_pass 127.0.0.1:28080;
include uwsgi_params;
}
location /static {
alias /var/www/demo/app/static;
}
location = /favicon.ico {
alias /var/www/demo/app/static/images/favicon.ico;
}
}
server {
listen 80;
listen 443 ssl;
ssl_certificate /var/www/example.com.pem;
ssl_certificate_key /var/www/newkey.pem;
server_name test.example.com;
access_log /var/log/test/access_log;
root /var/www/test;
location / {
uwsgi_pass 127.0.0.1:28082;
include uwsgi_params;
}
location /static {
alias /var/www/test/app/static;
}
location = /favicon.ico {
alias /var/www/test/app/static/images/favicon.ico;
}
}
}
A very simple, single app configuration file located in /var/www/myapp-nginx.conf
might look like the below.
server {
listen 80;
server_name mytest.example.com;
charset utf-8;
root /home/alan/python_projects/flask_app/example/static;
location / {
try_files $uri @uwsgi;
}
location @uwsgi {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3031;
}
}
With nginx under Ubuntu, configuration files are held under /etc/nginx
. In this next step we will remove the default confiruation file and then symlink our configuration file to this directory.
$ sudo rm /etc/nginx/sites-enabled/default
$ sudo ln -s /var/www/myapp/myapp_nginx.conf /etc/nginx/sites-aviable
$ sudo service nginx restart
uwsgi configuration
$ sudo apt-get install uwsgi
Create the uwsgi configuration file at /var/www/<app>/<app>-uwsgi.ini
.
[uwsgi]
uid = www
gid = www
socket = :28080
chdir = /var/www/myapp
master = True
venv = /var/www/demoapp/venv
app = hello
module = %(app)
callable = app
wsgi-file = /var/www/prod_demo/manage.py
enable-threads = True
Install and configure Supervisor
Supervisor is a system which will start up a process and continously monitor that process. We will use Supervisor to autostart our uwsgi service layer.
$ sudo apt-get install supervisor
Now create the configuration file at /etc/supervisor/conf.d/demoapp_supervisor.conf
.
[program:example]
command=/usr/local/bin/uwsgi --ini /var/www/myapp/myapp_uwsgi.ini
autostart=true
autorestart=true
stopsignal=INT
Other options here are to use uwsgi emperor mode. Go here for more details.
References
The above has come from experience together with the following very helpful articles and notes:
Bouroumeau-Fuseau, M. (2015). Building websites in Python with Flask The Traveling Coder. [online] Maximebf.com. Available at: http://maximebf.com/blog/2012/10/building-websites-in-python-with-flask/#.VQehJkKZbdk [Accessed 18 Mar. 2015].
Karzyński, M. (2013). Setting up Django with Nginx, Gunicorn, virtualenv, supervisor and PostgreSQL. Available at http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/
Todo
A lot of work still needs to be done on this article. I’ll start documenting this work here but for now some outstanding items are:
- Run through an installation again and check the order of software installation (virtualenv or not)
- Fully validate and include in this reference installation of Node.js and npm