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.
Ubuntu | Python |
---|---|
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.
-
Create and activate a new environment:
$ mkdir ~/exampleapp/ && cd ~/exampleapp/
$ python -m venv .venv -
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:
-
Install the Django CLI:
(.venv) $ pip install Django
-
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/
-
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.
-
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.targetThese settings will vary depending on your system and application. We suggest consulting the official documentation for the configuration parameters and best practices.
-
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
.
-
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 -
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.
-
Execute their install script with the following command:
$ curl https://pyenv.run | bash
-
Add the following content to
~/.bashrc
: `bashload 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!
-
Reload your shell:
$ exec "$SHELL"
-
Install the desired Python version:
$ pyenv install -v 3.9.11
$ pyenv global 3.9.11