Quotation

20 February 2015

Configuring Flask, uWSGI, and Nginx (Updated!)

This is an updated version of a previous post, which is preserved here.



In a departure from what I often write about, I'm going to talk a little bit about something that is tangentially related to what I actually do for a living: running a web server. So I'm going to give a brief tutorial on setting up uWSGI (in Emperor mode) and Nginx so that you can run one or more Python Flask instances on a server.

Installation
Flask
uWSGI
Nginx
Port Forwarding
Sources

Why? Well, I'm far from a pro at anything related to networking or web development, but I have been writing a few web tools lately just for fun. Initially, I had several different Flask/Werkzeug instances running in what was essentially a dev mode on different ports on my server, and I had each of these ports forwarded. But...


...this was ungainly, running multiple Werkzeug instances was inefficient, I didn't want to have to forward all of those ports, and damn it, I wanted to do things right. But, as this isn't my area of expertise, it took me a while to put all of these pieces together, because many of the examples that I was able to find were light on the details. I'm putting this here in the hope that someone else in my situation might find it useful.

Installation

So here are the relevant details. I'm running Ubuntu 14.04 and I'm using Python 3.4 (and 2.7.9), Flask 0.10, uWSGI 2.0.9, and Nginx 1.1.19. If you are missing any of these, you'll want to install them with your package manager of choice. For example:

$ sudo apt-get install python
$ sudo apt-get install uwsgi
$ sudo apt-get install nginx
$ pip3 install flask

Some caveats: First, if you're running Python 2.x, you'll want to ensure that Flask is available for it, as well. (You can try pip install flask, depending on your configuration.) Second, if you're planning to run multiple Flask applications using multiple versions of Python, you may have to build uWSGI core from source and specify which Python plugin to use for each application. Building uWSGI from source isn't the worst thing in the world; instructions for building the application and the necessary plugins are available here.

The goal here is to run multiple Flask servers on one machine without having to worry about port numbers and the like. We'll start with just one, and I'm sure that you can figure the rest out from there.

Flask

First you need a Flask application to run. How about this one? I wrote it a few months ago because I wanted to translate GET requests to POST requests. (At the time that I'm writing this, that particular application hasn't been updated to use Python 3.)

Navigate to the directory you'd like to install it to (probably /opt/ or /var/www/), then clone it. You'll want to verify that it runs locally on its own first.

$ cd /opt
$ git clone https://github.com/spurll/post.git
$ post/run.py

In a web browser on the same server, navigate to http://localhost:9999 and verify that the application is accessible. If you're running headless (as I am) you can always spawn the process to the background with post/run.py & and then curl localhost:9999 and verify that you don't get an error back. You can now kill the Python process.

Flask is now set up!

uWSGI

First, test that uWSGI will run your application correctly on its own:

$ cd /opt/post
$ uwsgi --socket 127.0.0.1:9999 --protocol=http -w run:app

In this case, run is the name of the Python source file that contains our application (/opt/post/run.py) and app is the name of the Werkzeug/Flask application object contained in that file. Verify that the application is accessible again from http://localhost:9999 as above.

If everything is working correctly, kill the uWSGI instance. It's now time to configure uWSGI's Emperor mode. This allows us to essentially have one master process that oversees all of our web applications, starting (and restarting) them when needed and logging as appropriate. You will probably have to install a few plugins, too, using your package manager of choice. (Note that if you want to support multiple Python versions, you may need to build these plugins from source, as mentioned above.) Assuming you want to use the standard plugins:

$ sudo apt-get install uwsgi-plugin-python
$ sudo apt-get install uwsgi-plugin-http

By default, your uWSGI master configuration file will probably be located at /etc/init/uwsgi.conf. Edit it with your editor of choice (I'm a Vim guy, myself):

$ sudo vim /etc/init/uwsgi.conf

It should look something like this:

description "uWSGI"
start on runlevel [2345]
stop on runlevel [06]
respawn

env UWSGI=/usr/bin/uwsgi
env LOGTO=/var/log/uwsgi/emperor.log

exec $UWSGI --master --emperor /etc/uwsgi/apps-enabled --die-on-term --uid www-data --gid www-data --logto $LOGTO

You can change the location of the Emperor's log file by changing the LOGTO environment variable. You can also modify which user (--uid) and group (--gid) the Emperor will run as.

Now it's time to configure the applications. Your application-specific configuration files (in this case, for the POST program that we installed to /opt/post/) will probably be found at /etc/uwsgi/apps-available/. Create a new file there and call it post.ini. It should like something like this:

[uwsgi]

# Variables
url_mount = /%n
base = /opt/%n
app = run
callable = app

# Plugins
plugins-dir = /usr/lib/uwsgi/plugins
plugins = python,http

# URL Script Mounting
mount = %(url_mount)=%(base)/%(app).py
manage-script-name = true

# Generic Config
pythonpath = %(base)
socket = /opt/run/%n.sock
module = %(app)
logto = /var/log/uwsgi/%n.log

Here, url_mount is the mount-point for the application (for example, if you're running the application at http://www.yourserver.com/post, the value would be /post), base is the base directory of our application (the directory that contains the module we want to run), app contains the name of the module to run (in this case run, for run.py), callable is the name of the Werkzeug/Flask callable application object (if you don't supply this, uWSGI will assume that it's called application), and socket defines the location of the socket you'd like Nginx to use when communicating with your uWSGI server. The %n references the name of our file (sans extension) to maintain consistency.

You'll need to ensure that the location of your sockets (in this case, /opt/run/) exists and that the appropriate user (in this case, www-data) has write permissions.

This configuration assumes that you want to run your program using the modules installed on your system's Python. Plugins might prove to be an issue. You'll want to point plugins-dir to the appropriate path, and make sure that you have the appropriate plugin. If you're running Python 3.x (or you want to specify a specific Python plugin for uWSGI for some other reason), you can point plugins at something like python34 (which you may have to build) instead.

To run the application in a virtual environment, you can add a line defining home:

home = %(base)/virtualenv

Where virtualenv is the directory containing the Python virtual environment you'd like to use. (In our case, that would be at /opt/post/virtualenv/, if we were using a virtual environment.)

Once you're ready, create a symbolic link to place the post.ini file you've created in the apps-enabled directory:

$ sudo ln -s /etc/uwsgi/apps-available/post.ini /etc/uwsgi/apps-enabled/post.ini

You can start the uWSGI process (if you haven't already) like this:

$ sudo service uwsgi start

As soon as your Emperor process sees an application configuration file in apps-enabled it will start up a uWSGI instance to serve requests for that application. If you'd like to set up additional Flask applications at this time, simply install them and create uWSGI configuration files for each (and don't forget to link them to apps-enabled!). If you're having trouble, take a look at the logs (which are probably in /var/log/uwsgi/).

The uWSGI Emperor is now set up!

Nginx

We're almost there!

The default configuration file for Nginx should be located at /etc/nginx/sites-available/default. Feel free to edit this one, or create your own. By default, Nginx will point requests on port 80 (the default HTTP port) to /usr/share/nginx/www. If you'd like to point them somewhere else (such as /var/www/) you can change that here. Here's a brief Nginx configuration file that you can use to run connect your uWSGI server to the outside world:

# server unix:///path/to/your/site.sock; # For a file socket.
# server 127.0.0.1:9999;                 # For a port.

upstream post {
    server unix:///opt/run/post.sock;
}

server {
    listen 80;
    server_name your.server.url;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    root /var/www;
    index index.html index.htm;

    # GET to POST
    location /post {
        include uwsgi_params;
        uwsgi_pass post;
    }
}

Replace your.server.url with the URL for your server (you can use localhost for testing purposes). This configuration assumes that you'd like your application to be accessible at http://your.server.url/post. If you'd like it to take the place of the main page at http://your.server.url/, modify the location appropriately.

Note that current versions of uWSGI no longer support the (long-deprecated) uwsgi_modifier1 30; to pass this mount information on to uWSGI, so if you're running multiple applications (or don't want to host your application on /) you will probably want to pay attention to the script mounting information for uWSGI above.

Once you're done, create a soft link to /etc/nginx/sites-enabled/ for each of the entries in /etc/nginx/sites-available/. Now you can start your Nginx service.

$ sudo service nginx start

Every time you modify the Nginx configuration file, you'll have to restart the it.

Port Forwarding

If you're running this server from your home or office and you need external access, don't forgot to forward port 80 so that Nginx is accessible. Instructions for your router are probably available here.

Sources

I used several sites while putting this all together. If you're stuck, they may contain additional information that I neglected to include here. Here are the most helpful of the bunch:

Deploying Flask on uWSGI
Multiple Django and Flask Sites with Nginx and uWSGI Emperor
How to Setup Nginx
uWSGI Example Configuration

I also had some help from my friends and colleagues BCJ and Curtis when I was initially setting up Nginx. Thanks, gents!

03 February 2015

Ideological Boundaries

I'm writing a book. Maybe you'll read it someday. If you're at all interested, I hope that you'll have that opportunity, and I hope even more that you'll enjoy it. The process of writing it is difficult, and it's rewarding, and it's exhausting, and occasionally it's even fun.

It's a novel. And there are people in this novel—characters, I mean—with whom I don't agree. It's hard to be fair. I was never really tempted to throw up a bunch of straw soldiers that I could easily knock down, but it's still difficult to be fair when discussing philosophical or ideological positions that I don't share, especially when these elements aren't the focus of the narrative.

But it's important to be fair. There's a group of people in this book who started off as the enemies, the "big bads", the primary antagonists of the story. It was easy to outline. But as I wrote it, I realised that these people weren't people: they were one character—one guy—just repeated over and over, copied ad nauseam. No nuance, no disagreement, only a clone army, dressed differently but marching in ideological lockstep. That's dangerous, and it's boring, and it doesn't make for much of a good story.

It's not all fixed now (I haven't even completed a first draft: nothing's fixed!), but at least I'm aware of the problem. And when and if the book is published, I look forward to hearing from everyone how unfairly I have portrayed those who disagree with me.

I was thinking about all of this last night as I was polishing up a chapter that I was especially proud of, and over lunch today I happened to stumble upon this really excellent video from Hank Green, in which he discusses polarizing ideological monoculture, and the important diversity that thrives in boundary zones.

21 January 2015

WiFi and Cell Phones: Should You Really Be Worried?

Until recently, several of the talks presented at SkeptiCamp Winnipeg 2013 were missing from the SkeptiCamp Winnipeg archives. Although I have previously posted a transcript of my 2013 talk, which discussed electromagnetic hypersensitivity and other fears linked to WiFi and mobile phones, audio of the talk is now available on the Winnipeg Skeptics site. It's also available right here!

SkeptiCamp Winnipeg 2013: WiFi and Cell Phones: Should You Really Be Worried?

SkeptiCamp Winnipeg is a conference for the sharing of ideas. It is free and open to the public: anyone can attend and participate! Presentations and discussions focus on science and free inquiry, and the audience is encouraged to challenge presenters to defend their ideas. You can visit the Winnipeg Skeptics' SkeptiCamp page for information about upcoming events and links to past SkeptiCamp talks.

12 January 2015

LUEE Episode 92: New Year's Resolutions and Behaviour Change

In this episode of Life, the Universe & Everything Else, Laura, Gem, Ashlyn, and Ian discuss New Year's Resolutions, how difficult it can be to change habits and behaviours, and some evidence-based ways to maximize your chances of succeeding in your goals.

Life, the Universe & Everything Else is a program promoting secular humanism and scientific skepticism that is produced by the Winnipeg Skeptics and the Humanists, Atheists & Agnostics of Manitoba.

Note: Although Gem mentioned that the month of January is named for the Roman god Janus (Ianus), some sources dispute this, attributing the name of the month to the goddess Juno (Iuno).

Links: New Year's resolution (Wikipedia) | Ianuarius (Wikipedia) | New Years Resolution Statistics (Statistic Brain) | Experiment: Resolutions (Quirkology) | Stanford marshmallow experiment (Wikipedia) | The Odds Of Actually Keeping Your New Year's Resolution (Louise Firth Campbell) | Why willpower matters and how to get it (The Guardian) | Willpower: How You Can Get More of It and Why It Runs Out (WebMD) | A prospective study of holiday weight gain (PubMed) | Auld lang syne: success predictors, change processes, and self-reported outcomes of New Year's resolvers and nonresolvers (PubMed) | Why Do Some Turtles 'Breathe' Out of Their Butts? (Discovery News) | SparkPeople | HabitRPG (Gamify Your Life)

Contact Us: Facebook | Twitter | Email

Listen: Direct Link | iTunes | Stitcher | RSS Feed