March 18, 2015

847 words 4 mins read

Building Websites with Python and Flask

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
comments powered by Disqus