Run Python WSGI Web App with Waitress

Advertisement

Advertisement

Introduction

WSGI is the standard for running Python web applications. Gunicorn and uWSGI are great options for running WSGI apps, but they only have limited support in Windows or no support at all. Waitress is another option for running WSGI applications and it really shines in Windows because it is written purely in Python with no other dependencies. I will show you how to use Waitress to serve web application using Python WSGI.

Selling points for Waitress:

  • Production quality
  • Well documented
  • Easy to install
  • Portable, with no dependencies except Python standard library so it runs in Windows
  • Part of the trusted Pylons project
  • Licensed for Freedom with Zope Public License

Setup

You will need Python installed. I recommend using a virtual environment. If you don't know how to create and use Python virtual environments, check out my tutorial Python Virtual Environments Tutorial.

You will need to install the Waitress package for Python which is easily done with pip:

python -m pip install waitress

If you want to install manually, get the source code from https://github.com/Pylons/waitress and run setup.py from the root directory:

python setup.py install

Running

You have two primary options for running Waitress. You can use the command-line tool waitress-serve or you can import Waitress in to a Python script and run it from there. They are essentially the same and you can pick the option that works best for your project.

Full usage information can be found in the official documentation but I will demonstrate the most common example from my experience.

Waitress supports using a UNIX sockets, although the examples here use TCP.

Command line

After installing the Waitress package, it will create a command-line sript named waitress-serve. The full options for running can be reviewed if you run waitress-serve with no options.

# Print usage
waitress-serve

Waitress is packaged well and also has a __main__.py in the source code, so you can also execute the same CLI tool using python3 -m waitress like this:

# Equivalent to `waitress-serve`
python3 -m waitress
# Or from a specific virtual environment
/path/to/venv/bin/python -m waitress

In this next example, it pretends there is a file named my_wsgi_project.py with an object named app like a typical Flask web application. The URL prefix is optional, but is useful when you are serving the application on a sub-directory like behind a reverse-proxy. It will listen on localhost port 8001.

waitress-serve --url-prefix=/my-app --listen=127.0.0.1:8001 my_wsgi_project:app 

In Python

This example will change the current working directory to the directory that the Python script resides in. In this example, it pretends there is a file named my_wsgi_project.py with an object named app like a typical Flask web application.

It will serve on IPv4 for localhost only on port 8001.

# run.py
import os
from waitress import serve
from my_wsgi_project import app  # Import your app

# Run from the same directory as this script
this_files_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(this_files_dir)

# `url_prefix` is optional, but useful if you are serving app on a sub-dir
# behind a reverse-proxy.
serve(app, host='127.0.0.1', port=8001, url_prefix='/my-app')

As a Service

If you want to run your application so it runs when the computer restarts and always stays up, you need to create a service.

Linux Service

For Linux users, check out my tutorial Creating Systemd Service Files.

Here is a simple example:

# /etc/systemd/system/my_app.service
[Unit]
Description=My WSGI app
After=network.target

[Service]
Type=simple
User=nanodano
WorkingDirectory=/home/nanodano
ExecStart=/path/to/venv/bin/waitress-serve --listen=127.0.0.1:8001 app.wsgi:application
Restart=always

[Install]
WantedBy=multi-user.target

Windows Service

For Windows users, check out my tutorial Run Python Script as Windows Service.

Here is a simple example of registering your app as a Windows service using nssm.

nssm.exe install "MyCustomService" "C:\opt\venv\Scripts\python.exe" "C:\opt\run.py"

Behind Nginx reverse-proxy

Frequently you need to serve multiple web applications on a single server using the same port. The solution is to use a reverse-proxy like Nginx. This allows you to create virtual hosts, serve static files, and serve multiple WSGI applications at once.

To learn how to setup Nginx as a reverse-proxy to serve WSGI applications and handle other things like redirection, SSL, authentication, and more, check out my Nginx Tutorial.

Here is a simple example of a reverse proxy with Nginx using SSL:

http {
    server {
        listen 443 ssl;

        ssl_certificate /path/to/cert.pem
        ssl_certificate_key /path/to/private-key.pem
        ssl_ciphers  HIGH:!aNULL:!MD5;

        server_name example.com;

        location /static/ {
            alias /var/www/static-content/;
        }

        location / {
            proxy_pass http://localhost:9999/;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

Conclusion

After reading this you should understand how to run a Python WSGI application using Waitress and when Waitress would be a good option over Gunicorn or uWSGI. You should understand how to do it from within Python and from the command-line.

References

Advertisement

Advertisement