Why does running Flask with Nginx require a WSGI wrapper?

Well, WSGI is a specification for interface between Python applications and web servers. uWSGI is (simply put) a realization of this specification written in C/C++. You can run almost any application on a "serious" webserver (like nginx) by just providing an entry point:

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return ["Hello World"]

and then running it like this:

uwsgi --http :9090 --wsgi-file file_with_the_code_above.py

You can return anything you want instead of ["Hello world"], of course. See http://uwsgi-docs.readthedocs.org/en/latest/WSGIquickstart.html for more.


Nginx is a web server and is concerned with web server stuff, not with how to run Python programs. uWSGI is an application server and knows how to speak WSGI with Python (and other languages now). Both Nginx and uWSGI speak the uWSGI protocol, which is an efficient protocol over UNIX sockets.

Nginx deals with http requests from/responses to the outside world (possibly load balancing, caching, etc.). Your Flask application deals with WSGI requests/responses. uWSGI knows how to start your application (possibly with multiprocessing and/or threading) and bridge the gap between HTTP and WSGI.

There are other HTTP servers besides Nginx, and other WSGI servers besides uWSGI, but they all use the same workflow: the HTTP server passes to the WSGI server, which manages your application process and passes back to the HTTP server.

This setup is known as a reverse proxy. It allows each tool to do what it's good at and not be concerned about the other parts of the process. There is nothing particularly inefficient about it, until you get to truly massive scales.