As a part of the Udacity Full Stack Web Developer Nanodegree, they got us to deploy our Flask app to an Ubuntu server running Apache. This was relatively simple (find out more with my full server setup document).

However, on my own server I use the Nginx web server and you have to use uWSGI to serve the Flask app. Here I will document what I did to my Ubuntu server, both for myself and anybody that’s interested. I found the following tutorial very helpful: How To Serve Flask Applications with uWSGI and Nginx on Ubuntu 14.04.

Install and configure PostgreSQL

This is a repeated step from the Nanodegree, but needs to be done on my server all the same.

Install PostgreSQL with the following command:

sudo apt-get install postgresql postgresql-contrib

Create a PostgreSQL user called catalog with:

sudo -u postgres createuser -P catalog

You are prompted for a password. This creates a normal user that can’t create databases, roles (users).

Create an empty database called catalog with:

sudo -u postgres createdb -O catalog catalog

That’s it for the PostgreSQL setup.

Clone the catalog app

Clone the repository containing the catalog app to the home directory of a normal user.

git clone https://github.com/SteveWooding/fullstack-nanodegree-vm.git

Setup virtual Python environment and install software

To prevent the system from being clogged up with various Python packages, it is recommended to use a Python virtual environment when deploying apps. This also means that if another requires specific versions of Python packages, it is easy just to create another virtual environment for that app with those packages.

Install Python Pip and Virtualenv:

sudo apt-get install python-pip
sudo pip install virtualenv

One other system-wide package to install is libpq-dev. This is required to build the psycopg2 package within the virtual environment.

sudo apt-get install libpq-dev

Create the environment inside the app directory:

cd ~/fullstack-nanodegree-vm/vagrant/catalog
virtualenv catalogenv

Go into the environment:

source catalogenv/bin/activate

The command prompt will now start with (catalogenv).

Install uWSGI and Flask and the other prerequisites the app needs:

pip install uwsgi
pip install flask
pip install oauth2client
pip install psycopg2
pip install sqlalchemy
pip install flask-seasurf
pip install requests

To make sure the catalog is working within the virtual environment, run the following command to run the app in debug mode using a local SQLite file:

python application.py

Check for any errors and use a browser to check http://localhost:8000. If you only have terminal access to a remote service, install a text-only browser for local testing. elinks is one I recommend.

When finished, use Ctrl-C to exit the Python program. And remove the database file:

rm itemcatalog.db

Configure and test uWSGI

The file catalog.wsgi is the entry point for uWSGI. Update file paths and the password to the PostgreSQL database in this file. Then test with the following command:

uwsgi --socket 0.0.0.0:8000 --protocol=http --wsgi-file catalog.wsgi

uWSGI needs a configuration file that does a similar job to the manually entered line above. Here is the file for this project (catalog.ini):

[uwsgi]
wsgi-file = catalog.wsgi

master = true
processes = 5

socket = catalog.sock
chmod-socket = 660
vacuum = true

die-on-term = true

You can find this file in the root directory of the project repository.

The web app should be available again at http://localhost:8000, except this time using the PostgreSQL database.

Come out of the virtual environment, now everything is set-up and working.

deactivate

Copy catalog app to /srv directory

To keep the system clean and tidy, copy just the catalog app to the /srv/ directory, from where the app will be served from.

sudo cp -R ~/fullstack-nanodegree-vm/vagrant/catalog /srv

Then change the ownership to the web server user for all files in the catalog app.

sudo chown -R www-data:www-data /srv/catalog

Now that the catalog app has been moved, update paths in /srv/catalog/catalog.wsgi and choose a good secret for the value of application.secret_key.

sudo -u www-data nano /srv/catalog/catalog.wsgi

Create an Upstart script

To make sure the catalog app is served at boot time and to make it a service that can be started and stopped, let’s make an Upstart script (assuming Ubuntu is the OS).

Open a file for editing:

sudo nano /etc/init/catalog.conf

This should contain the following in my case (see this for a more detailed explanation):

description "uWSGI server instance configured to serve catalog app"

start on runlevel [2345]
stop on runlevel [!2345]

setuid www-data
setgid www-data

env PATH=/srv/catalog/catalogenv/bin
chdir /srv/catalog       
exec uwsgi --ini catalog.ini

Start the uWSGI process now with:

sudo start catalog

Configuring Nginx to pass on requests to the app

Nginx now needs to be configured to act as a proxy and pass on requests to the uWSGI app.

Create a new virtual server in the sites-available directory:

sudo nano /etc/nginx/sites-available/catalog

This file contains the following in my case:

server {
    listen 80;
    server_name zooma.stevenwooding.com;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/srv/catalog/catalog.sock;
    }
}

If you are using a server name other than localhost, make sure the DNS settings are updated to point at your server’s IP address.

Enable the new site with:

sudo ln -s /etc/nginx/sites-available/catalog /etc/nginx/sites-enabled

Check the Nginx configuration in valid with:

sudo nginx -t

Correct any errors. Once successful, restart Nginx with:

sudo service nginx reload

The app should now be successfully served.

Updating OAuth secrets files

My catalog app allows visitors to login via Google+ and Facebook using OAuth. I now have to tell Google and Facebook the new location of my app and fill in the secrets in the following two files:

/srv/catalog/g_client_secrets.json
/srv/catalog/fb_client_secrets.json

For Google, go to the Google Developers Console and for Facebook, go to Facebook Login. For extra security, I refreshed the client secrets, just in case previous secrets are now compromised.

Login to the app via Google and Facebook should now work. If not, double check the client IDs and secrets and the javascript_origins variable in the g_client_secrets.json file.

Double check on Facebook for the app that on:

Settings > Advanced > Client OAuth Settings > Valid OAuth redirect URIs

the correct URL for the app is present.

For Google this is in API Manager > Credentials, select the web client and check the value of Authorized JavaScript origins has the correct URL in it for the app. Don’t forget to save settings if any changes need to be made.

Reflections

So that’s how I deployed my Flask app I made during my Udacity Nanodegree to my server running Nginx. You can check it out here zooma.stevenwooding.com.

The next thing I want to do is use a Let’s Encrypt SSL certificate and put the app on HTTPS instead of HTTP. This raises the confidence of users that a website is safe and secure.

Update

My catalog app is now secured with SSL/TLS. All I had to do was follow my own basic guide: Let’s Encrypt All the Things. Then apply these extra settings to increase the SSL security of the site: How to improve HTTPS security.