Adventures in VPS Land Part I: Seting Up Multiple Flask Apps

Posted on July 21 2014

Note: This is a more technical, spiritual successor to my “origin story” posted previously.

Question: How do I set up a website that runs mainly on Python and the Flask framework and consists of several unrelated Flask “apps” – and for good measure also a few PHP-based pages? Also, I’m using Ubuntu and Apache2. And I want to host all of this on DigitalOcean.

Short answer: Wow, that’s oddly specific. Anyway, have a look here for a very good overview of how to set up multiple Flask apps with Apache and mod_wsgi – and google the rest. 

Long answer (in the form of a series of annotated links with a brief introductory story which you may want to skip if you’re just looking for the actual answer):

When I started working on my personal website, I took over my wife’s Bluehost account. She was working on a 90s nostalgia site; I actually came up with a great name for it: the90scalled.com (I don’t recommend visiting this URL as the project died just before I started using my wife’s account and the domain has been expired for a while – there could be anything on it right now).

Anyway.

My first few projects were mainly done with front end technologies, with occasional PHP code. Well, some of my mini-projects relied on PHP more than others, so eventually I ended up with enough legacy PHP code.

I decided to try Python (with the Flask framework) and Bluehost suddenly didn’t give me enough freedom for that. I wanted to give DigitalOcean a try as it seemed perfect – a VPS (so that I could install and run pretty much anything) and very cheap (I’m currently using their cheapest, \$5/month “droplet” for all my sites – fourtonfish.com, spaceandquotes.com and simplesharingbuttons.com – the last of which can get up to 10,000 views a month, so it seems this is a pretty good setup as I haven’t run into any problems with uptime, bandwidth or anything else.

Originally I followed the “official” way of managing large Flask apps (my actual website being one large app). This worked really well until my code base started to grow and I also started using custom domains for some of the “apps” – things spiraled out of control pretty quickly.

A much better solution, as I learned, is to set up each Flask app to run independently and let the server manage the low-level stuff, like most of the routing.

So what you’ll want to do is to create a configuration file mywebsite.conf inside /etc/apache2/sites-available. Then you can enable your mywebsite site with:

a2ensite mywebsite

Note: I am assuming here that you already have a basic understanding of how Apache works and can look up some of the details yourself; if you need an overview, you can read this tutorial on how to set up Apache virtual hosts – or use Google.

Here is a very simplified example of what your mywebsite.conf file could look like. It assumes you want to have your main Flask app handle your root directory and your projects handled separately in sub-folders.

  <VirtualHost *:80>
    ServerName www.fourtonfish.com
    ServerAlias fourtonfish.com
    ServerAdmin stefan@fourtonfish.com
    DocumentRoot /var/www

    WSGIScriptAlias /sitesummary /var/www/sitesummary/sitesummary.wsgi

    <Directory /var/www/sitesummary>
      WSGIProcessGroup fourtonfish
      WSGIApplicationGroup %{GLOBAL}
      Order deny,allow
      Allow from all
      AllowOverride all
    </Directory>

#   The script handling your root folder has to come last
    WSGIScriptAlias / /var/www/fourtonfish/fourtonfish.wsgi

    Alias /simplesharingbuttons "/var/www/simplesharingbuttons"

    <Directory /var/www/simplesharingbuttons>
      Order deny,allow
      Allow from all
      AllowOverride all
    </Directory>

    Alias /hellosalut "/var/www/hellosalut"

    <Directory /var/www/hellosalut>
      Order deny,allow
      Allow from all
      AllowOverride all
    </Directory>
  </VirtualHost>

And if you want to give one of your Flask apps its own domain, you can simply create a new configuration file called anothersite.conf and write something like this:

  <VirtualHost *:80>
    ServerName www.spaceandquotes.com

    ServerAdmin stefan@spaceandquotes.com
    WSGIDaemonProcess spaceandquotes user=www-data group=www-data threads=5
    WSGIScriptAlias / /var/www/spaceandquotes/spaceandquotes.wsgi

    <Directory /var/www/spaceandquotes>
      WSGIProcessGroup spaceandquotes
      WSGIApplicationGroup %{GLOBAL}
      Order deny,allow
      Allow from all
      AllowOverride all
    </Directory>
  </VirtualHost>

Again, this is pretty simplified with just the most important directives, you might want to add logging, configure mod_expires and other stuff. You can find more examples on the page I mentioned in the beginning.

So this is enough to get your Flask apps and legacy PHP sites going.

In part two, if I ever get around to it, I will show you how to set up git with push-to-deploy web hooks and how to simultaneously push your code to a private Bitbucket repo.

Follow me on this blog or on Twitter to see when the second part comes out.