Skip to main content

Run Python applications with uWSGI

This tutorial explains how to run a basic Python application with uWSGI in userspace.

For the example below, we assume that your application supports wsgi. If you use Django or Flask, this is already the case.

1. Install Python

Your managed server already comes with Python pre-installed, but the available version is fixed based on the Ubuntu version.

UbuntuPython
18.04 (Bionic)3.6.*
20.04 (Focal)3.8.*
22.04 (Jammy)3.10.*

If you require a different version, you can find instructions in the section "Install an alternative Python Version".

2. Setup Virtual Environment (venv)

To separate your Python applications from each other, it's best practice to use virtual environments or short, venv.

  1. Create and activate a new environment:

    $ mkdir ~/exampleapp/ && cd ~/exampleapp/
    $ python -m venv .venv
  2. Install uWSGI inside the virtual environment:

    $ source .venv/bin/activate
    (.venv) $ pip install uwsgi

In case the installation of uWSGI fails, the problem may be missing packages/libraries. Please contact our support so we can install these for you.

3. Application Deployment

The steps to deploy your application depends on your application. With Django, for example, you'll need to install the Django package, then upload all files to the server and install the dependencies:

  1. Install the Django CLI:

    (.venv) $ pip install Django
  2. Copy the application files to your server:

    rsync -Hav --delete --exclude='node_modules/*' --exclude='logs/*' --exclude='.git/*' --exclude='.venv/*' ./local_project www-data@server.nine.ch:exampleapp/
  3. Install your dependencies:

    (.venv) $ pip install -r requirements.txt

4. Run Application as a Service

To ensure a service keeps running after an application crash or system reboot, we highly recommend using a Systemd user service. The configuration for such a Systemd unit depends on your application. The above example assumes that you’re running a Django app.

  1. Create the service file in ~/.config/systemd/user/exampleapp.service:

    [Unit]
    Description=exampleapp

    [Service]
    WorkingDirectory=%h/exampleapp
    Restart=always
    KillSignal=SIGQUIT
    Type=notify
    NotifyAccess=all

    Environment=PYTHON_VERSION=3.9.11
    Environment=PATH=%h/.pyenv/versions/$PYTHON_VERSION/bin:$PATH
    EnvironmentFile=%h/exampleapp/.env

    ExecStart=%h/exampleapp/.venv/bin/uwsgi \
    --module=exampleapp.wsgi:application \
    --master \
    --http=127.0.0.1:3000 \
    --enable-threads \
    --threads=2 \
    --processes=4 \
    --harakiri=20 \
    --max-requests=5000 \
    --vacuum \
    --home=%h/exampleapp/.venv

    [Install]
    WantedBy=default.target

    These settings will vary depending on your system and application. We suggest consulting the official documentation for the configuration parameters and best practices.

  2. Start the service:

    touch ~/exampleapp/.env # ensure environment file exists
    systemctl --user daemon-reload
    systemctl --user enable exampleapp.service
    systemctl --user start exampleapp.service
    systemctl --user status exampleapp.service

5. Configure Webserver

The application is now running on a local port. To reach the application via Port 80/443, the webserver needs to proxy these HTTP requests to the uWSGI service. There are already two nine-manage-vhost templates for this use case pre-installed on your managed server: proxy and proxy_letsencrypt.

  1. Create a new vHost and set the local port of the applications via template variable:

    $ sudo nine-manage-vhosts virtual-host create example.com --template proxy --template-variable PROXYPORT=3000 --webroot ~/exampleapp/static

    Virtual Host created: example.com
    example.com
    ===========
    DOMAIN: example.com
    USER: www-data
    WEBROOT: /home/www-data/exampleapp/static
    TEMPLATE: proxy
    TEMPLATE VARIABLES: PROXYPORT
    3000
    ALIASES: www.example.com
    example.com.server.nine.ch
  2. Create and use a Let's Encrypt certificate for HTTPS:

    $ sudo nine-manage-vhosts certificate register-client --contact-email=mymail@example.com
    $ sudo nine-manage-vhosts certificate create --virtual-host example.com
    $ sudo nine-manage-vhosts virtual-host update example.com --template=proxy_letsencrypt_https --template-variable PROXYPORT=3000

That's it! Your application should be accessible via ports 80 and 443.

Install an alternative Python Version

To be more flexible with different Python versions, we recommend the usage of pyenv.

  1. Execute their install script with the following command:

    $ curl https://pyenv.run | bash
  2. Add the following content to ~/.bashrc: `bash

    load pyenv at bash initialization

    export PATH="$HOME/.pyenv/bin:$PATH" eval "$(pyenv init --path)" eval "$(pyenv virtualenv-init -)" ` Please note, depending on your shell, these settings may vary!

  3. Reload your shell:

    $ exec "$SHELL"
  4. Install the desired Python version:

    $ pyenv install -v 3.9.11
    $ pyenv global 3.9.11