Flask Web Apps in OS X Server

So, you want to run your Python Flask web applications the native OS X Apache web server? Well that’s awesome, because so did I! This probably won’t work on 10.7.x and earlier without using Apache from brew/ports or using MAMP (which I used); I’m running OS X Yosemite 10.10.5 with the latest server application for this version of OS X.

vonavi:~ jamie$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.10.5
BuildVersion: 14F27

vonavi:~ jamie$ sudo serveradmin -v
Version 15S2259

Step 1: Choose where your app will live.
I personally chose “/Users/jamie/Sites/home” simply for ease of access but I’m not using the userdir functionality.

Here is how my app is laid out:
home\
|-- _venv\
|-- app\
|-- static\
|-- templates\
|-- __init__.py
|-- forms.py
|-- models.py
|-- serializers.py
|-- views.py
|-- Vonavi.py
|-- migration\
|-- app.db
|-- config.py
|-- setup.py
|-- vonavi.wsgi

Step 2: Create a virtual environment
With a terminal open, go to your application directory and run:

virtualenv --always-copy --relocatable --no-site-packages _venv

NOTE: The options I chose were to ensure the virtual environment was more portable. By default, symlinks are made but these will copy files and make any symlinks relative instead of static.
NOTE: “–no-site-packages” is the default and this option is deprecated but I used it to ensure 100% that I know what I’m getting into.
NOTE: “_venv” is the directory for my virtual environment, you’re more than welcome to choose a different name.

From there, you can enter your virtual environment via:
source _venv/bin/activate

Now you’re free to install any modules you need in your web application. I would recommend using the path to the copy of “pip” within the virtual environment to make sure the modules aren’t being installed globally. I also generated a requirements.txt file with all of the packages I need for my app so I ran:
(_venv)vonavi:home jamie$ _venv/bin/pip install -r requirements.txt

Step 3: Create your WSGI file
This is going to be one of the important files that will determine whether you can use the goodies within your virtual environment or not. I decided to use static paths and this is what I came up with:

# -*- coding: utf-8 -*-
import os
import site
import sys

# Add the site-packages of the chosen virtual env to work with
site.addsitedir('/Users/jamie/Sites/home/_venv/lib/python2.7/site-packages')

# Add the app's directory to the PYTHONPATH
sys.path.append('/Users/jamie/Sites/home/_venv')
sys.path.append('/Users/jamie/Sites/home')

# Activate the virtual env
activate_this = '/Users/jamie/Sites/home/_venv/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

from app import app as application

NOTE: WSGI requires “application” which is why you see my import alias.

Step 4: Create an Apache configuration for your web application
In “/Library/Server/Web/Config/apache2”, I created a file called “httpd_vonavi_wsgi.conf” that will house the Apache directives for my web application.

ServerName vonavi.org
WSGIScriptAlias / /Users/jamie/Sites/home/vonavi.wsgi


WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Require all granted

NOTE: I want my web app to run as the web server root so my WSGIScriptAlias is set to “/” but feel free to change it to whatever you would like.

Step 5: Create a property list file for your web application
Now things really get Apple-centric when it comes to the web server configuration… In “/Library/Server/Web/Config/apache2/webapps”, I created a file called “com.vonavi.wsgi.plist” to go with the naming convention of the files with a hint of my own web application.



name
com.vonavi.wsgi
displayName
Vonavi
launchKeys

proxies

installationIndicatorFilePath
/Users/jamie/Sites/home/vonavi.wsgi
includeFiles

/Library/Server/Web/Config/apache2/httpd_vonavi_wsgi.conf

requiredModuleNames

wsgi_module

There are 4 important things and those are going to be the display name (which I will get to later), feel free to give it a name that will be meaningful in the string elements for “displayName” but keep “name” the name of the property list file you’re creating. Put the full path to your .wsgi file in-between the string elements for “installationIndicatorFilePath” and the full path of the just-created Apache directives file for “includeFiles”.

Step 6: Setup your web server
Don’t worry, we’re almost done! Now you just need to setup your web server which consists of creating a site, if you want (like I did for my specific domain: vonavi.org), and enabling Python support then turning on your web app.

6a: Open Server.app
6b: Under Services, click on Websites
6c: Put a check mark next to “Enable Python” if it isn’t already enabled.
6d: Create a new website and configure it appropriately or edit the default. Once in the Edit area, click on “Edit Advanced Settings”.
6e: You should see your web application using the displayName name from the property list file. Place a check mark next to your web app and click Ok. Click Ok again to get out of the edit site window which should leave you at the Websites services screen.
6f: Restart the web server if it is currently running or start it if it was already off. If the web server is currently running, move the slider to the “Off” position and wait until the status says that the service has stopped (and not still in stopping — this could take a minute). Once the web server is stopped, move the slider back to the on position.

You should be able to open your web browser and go to your server’s address to find your Flask web app up and running! This is what worked for me and I welcome feedback if you have better ideas.

For more information, please read the modwsgi configuration directives page.

One comment to Flask Web Apps in OS X Server

  • Seb  says:

    This worked for me on OS X 10.11 Server. Thanks a bunch! I know it’s unnecessary and uncustomary to use Server.app to serve production Flask sites, but I just really like being able to activate them in the UI as needed.

    PS: Your plist listing got mangled, it doesn’t show any of the XML tags.

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>