I’ve spent the morning figuring out how to use Flask through Anaconda with Apache and uWSGI on an Amazon EC2 machine, side-stepping the system’s default Python. I’ll log the main steps in, I found lots of hints on the web but nothing that tied it all together for someone like me who lacks Apache config experience. The reason for deploying using Anaconda is to keep a consistent environment against our dev machines.
First it is worth noting that mod_wsgi and mod_uwsgi (this is what I’m using) are different things, Flask’s Apache instructions talk about mod_wsgi and describes mod_uwsgi for nginx. Continuum’s Anaconda forum had a hint but not a worked solution.
I’ve used mod_wsgi before with a native (non-Anaconda) Python installation (plus a virtualenv of numpy, scipy etc), I wanted to do something similar using an Anaconda install of an internal recommender system for a client. The following summarises my working notes, please add a comment if you can improve any steps.
- Setup an Ubuntu 12.04 AMI on EC2
source activate production # activate the Anaconda environment
(I'm assuming you've setup an environment and
put your src onto this machine)
conda install -c https://conda.binstar.org/travis uwsgi
# install uwsgi 2.0.2 into your Anaconda environment
using binstar (other, newer versions might be available)
uwsgi --http :9090 --uwsgi-socket localhost:56708
# run uwsgi locally on a specified TCP/IP port
curl localhost:9090 # calls localhost:9090/ to test
your Flask app is responding via uwsgi
If you get uwsgi running locally and you can talk to it via curl then you’ve got an installed uwsgi gateway running with Anaconda – that’s the less-discussed-on-the-web part done.
Now setup Apache:
sudo apt-get install lamp-server^
# Install the LAMP stack
sudo a2dissite 000-default
# disable the default Apache app
# I believe the following is sensible but if there's
an easier or better way to talk to uwsgi, please
leave me a comment (should I prefer unix sockets maybe?)
sudo apt-get install libapache2-mod-uwsgi # install mod_uwsgi
sudo a2enmod uwsgi # activate mod_uwsgi in Apache
# create myserver.conf (see below) to configure Apache
sudo a2ensite myserver.conf
# enable your server configuration in Apache
service apache2 reload # somewhere around now you'll have
to reload Apache so it sees the new configurations, you
might have had to do it earlier
My server.wsgi lives in with my source (outside of the Apache folders), as noted in the Flask wsgi page it contains:
from server import app as application
Note that it doesn’t need the virtualenv hack as we’re not using virtualenv, you’ve already got uwsgi running with Anaconda’s Python (rather than the system’s default Python).
The Apache configuration lives in /etc/apache2/sites-available/myserver.conf and it has only the following lines (credit: Django uwsgi doc), note the specified port is the same as we used when running uwsgi:
Once Apache is running, if you stop your uwsgi process then you’ll get 502 Bad Gateway errors, if you restart your uwsgi process then your server will respond again. There’s no need to restart Apache when you restart your uwsgi process.
For debugging note that /etc/apache2/mods-available/ will contain uwsgi.load once mod_uwsgi is installed. The uwsgi binary lives in your Anaconda environment (for me it is ~/anaconda/envs/production/bin/uwsgi), it’ll only be active once you’ve activated this environment. Useful(ish) error messages should appear in /var/log/apache2/error.log. uWSGI has best practices and a FAQ.
Having made this run at the command line it now needs to be automated. I’m using Circus. I’ve installed this via the system Python (not via Anaconda) as I wanted to treat it as being outside of the Anaconda environment (just as Upstart, cron etc would be outside of this environment), this means I needed a bit of tweaking. Specifically PATH must be configured to point at Anaconda and a fully qualified path to uwsgi must be provided:
check_delay = 5
endpoint = tcp://127.0.0.1:5555
pubsub_endpoint = tcp://127.0.0.1:5556
cmd = <path_anaconda>/envs/production/bin/uwsgi
args = --http :9090 --uwsgi-socket localhost:56708
warmup_delay = 0
numprocesses = 1
This can be run with “circusd <config>/circus.ini –log-level debug” which prints out a lot of debug info to the console, remember to run this with a login shell and not in the Anaconda environment if you’ve installed it without using Anaconda.
Once this works it can be configured for control by the system, I’m using systemd on Ubuntu via the Circus Deployment instructions with a /etc/init/circus.conf script, configured to its own directory.
If you know that mod_wsgi would have been a better choice then please let me know (though dev for the project looks very slow [it says "it is resting"]), I’m experimenting with mod_uwsgi (it seems to be more actively developed) but this is a foreign area for me, I’d be happy to learn of better ways to crack this nut. A quick glance suggests that both support Python 3.
Ian applies Data Science as an AI/Data Scientist for companies in ModelInsight
and Mor Consulting
, founded the image and text annotation API Annotate.io
, co-authored SocialTies
, programs Python, authored The Screencasting Handbook
, lives in London and is a consumer of fine coffees.