Before modern web frameworks like Flask and Django simplified web development, the Python Web Server Gateway Interface (WSGI / PEP 3333) established the standard interface connecting web servers (like Nginx) with Python web applications. Understanding raw WSGI mechanics gives you deep insight into how Python web requests are processed under the hood.

Step 1: Write a Pure Python WSGI Application (PEP 3333)

A valid WSGI application is a callable object (a function or class instance) that accepts two arguments: environ (a dictionary of HTTP request headers) and start_response (a callback function setting status codes and response headers):

wsgi_app.pypython
def application(environ, start_response):
    # Extract HTTP Request Details
    request_method = environ.get('REQUEST_METHOD', 'GET')
    path_info = environ.get('PATH_INFO', '/')
 
    # Define HTTP Response Status and Headers
    status = '200 OK'
    headers = [
        ('Content-Type', 'text/html; charset=utf-8'),
        ('X-Powered-By', 'Python WSGI')
    ]
 
    # Invoke start_response callback before returning body
    start_response(status, headers)
 
    # Return iterable byte payload
    response_body = f"<h1>Hello from Pure Python WSGI!</h1><p>Method: {request_method} | Path: {path_info}</p>"
    return [response_body.encode('utf-8')];

WSGI Callable Contract Breakdown:

  • `environ`: Dictionary containing CGI-style environment variables (HTTP headers, query strings, body input stream).

  • `start_response(status, headers)`: Function that sends the HTTP response line and headers to the web server.

  • Byte Return Value: Must return an iterable of byte strings (encode("utf-8")), not plain Python unicode strings.

Step 2: Configure uWSGI Application Server

Create a uwsgi.ini configuration file to manage uWSGI worker processes and Unix socket communications:

uwsgi.iniini
[uwsgi]
# Point to Python module (wsgi_app.py) and callable (application)
module = wsgi_app:application
 
# Master process management
master = true
processes = 4
threads = 2
 
# Unix Socket for Nginx reverse proxy
socket = /tmp/uwsgi_app.sock
chmod-socket = 660
vacuum = true
 
die-on-term = true

Step 3: Connect Nginx to uWSGI via uwsgi_pass

In your Nginx server block, use the native uwsgi_pass directive to route web traffic to your uWSGI socket:

/etc/nginx/sites-available/wsgi_appnginx
server {
    listen 80;
    server_name wsgi.example.com;
 
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/tmp/uwsgi_app.sock;
    }
}

Deploying with uWSGI and Nginx combines raw Python performance with Nginx’s high-concurrency static file serving and SSL termination.