Template

Python Production Stack

Python, Nginx, Gunicorn and a hardened systemd service for one FastAPI, Django or Flask app.

Options

As they appear on the run form, with their defaults.

Application name

Text

Lowercase letters, digits and hyphens, such as api. Names the folder, account and service.

Default: Required

Application module

Text

What Gunicorn loads, such as config.wsgi:application for Django or app.main:app for FastAPI.

Default: Required

Application interface

One choice

  • ASGI: FastAPI, Starlette, Django over ASGI
  • WSGI: Django, Flask

Default: ASGI: FastAPI, Starlette, Django over ASGI

Python

One choice

On Ubuntu and Debian, both choices install the release's one Python 3.

  • Newest Python 3 in the distribution's repositories
  • The distribution's default python3

Default: Newest Python 3 in the distribution's repositories

Port on 127.0.0.1

Text

Gunicorn listens here, on this server only.

Default: 8000

Python tools

Any of the choices

  • uv
  • Poetry
  • Pipenv

Default: uv

Client headers

Any of the choices

For database drivers and libraries that compile against them.

  • PostgreSQL (psycopg)
  • MySQL and MariaDB (mysqlclient)
  • libxml2 and libxslt (lxml)
  • JPEG and zlib (Pillow)

Default: None

What you get

Everything one Python web application needs on the server except its code: Python with venv and pip, Nginx, Gunicorn in the application's own virtual environment (with Uvicorn workers for ASGI), the Python tools you choose with a compiler and build headers, a service account, Gunicorn settings and a hardened systemd service on 127.0.0.1. The service is installed but not started until you deploy.

Choosing the options

Application name — lowercase letters, digits and hyphens, such as api. It names /srv/api, the api account and the api service.

Application module — what Gunicorn loads: app.main:app for a FastAPI app in app/main.py; config.asgi:application or config.wsgi:application for Django, where config holds settings.py; app:app for Flask in app.py.

Application interfaceASGI for FastAPI, Starlette and Django over ASGI; WSGI for Django and Flask.

PythonNewest Python 3 on the RHEL family installs the newest Python packaged beside the system one, such as 3.12; on Ubuntu and Debian both choices install the release's Python 3.

Port on 127.0.0.1 — where Gunicorn listens, on this server only. 8000 unless something else uses it.

Python tools — uv, Poetry or Pipenv, installed with pipx and available to every account.

Client headers — for dependencies that compile against them: PostgreSQL for psycopg, MySQL and MariaDB for mysqlclient, libxml2 for lxml, JPEG and zlib for Pillow.

What happens

  1. Update Packages.
  2. Install Python.
  3. Install Nginx.
  4. Install Gunicorn into the application's own virtual environment, /srv/api/venv for api.
  5. Install Python Tools, with a compiler and build headers.
  6. Configure Python App: the account, the Gunicorn settings (/etc/api/gunicorn.conf.py for api) and the service.

After the run

For an application named api on port 8000:

  1. Deploy the code to /srv/api/current.
  2. Install its requirements: /srv/api/venv/bin/pip install -r /srv/api/current/requirements.txt, or with the tool you chose, for uv uv pip install --python /srv/api/venv/bin/python -r requirements.txt.
  3. Put its settings in /etc/api/environment, owned by root, mode 0640, group api.
  4. Start it: systemctl enable --now api, and check curl http://127.0.0.1:8000/.
  5. Put HTTPS in front with Configure Reverse Proxy or the Nginx Reverse Proxy + Auto-Renewing SSL template, forwarding to http://127.0.0.1:8000.

Common problems

  • The port is already in use, or the name is taken by an existing account or service — see Configure Python App.
  • The Uvicorn worker does not import — see Install Gunicorn.
  • A header package is not available on the RHEL family — enable CodeReady Builder; see Install Python Tools.
  • The service starts and stops once you enable it — read journalctl -u api -n 50; the module path and missing settings are the usual causes.