Playbook
Configure Python App
A service account, Gunicorn settings and a hardened systemd service for one Python web app.
Category
Runtimes
Time limit per server
5 minutes
Temporary failures
Not retried: run it again
Version
1.0
Supported systems
Ubuntu 22.04+, Debian 12+, RHEL-compatible 8+ (AlmaLinux, Rocky Linux, RHEL, CentOS Stream, Oracle Linux), Amazon Linux 2023+
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
- WSGI: Django, Flask
- ASGI: FastAPI, Starlette, Django over ASGI
Default: WSGI: Django, Flask
Port on 127.0.0.1
Text
Gunicorn listens here, on this server only.
Default: 8000
When to use it
After Install Gunicorn, to give a Python web application everything it needs on the server except its code: an account to run as, Gunicorn's settings and a systemd service. The service is installed but not started until you deploy.
Choosing the options
Application name — the same name you gave Install Gunicorn, such as api. For api it creates the api account, /srv/api, /etc/api and the api service.
Application module — what Gunicorn loads, in module:variable form:
- Django over WSGI:
config.wsgi:application, whereconfigis the folder holdingsettings.py. - Django over ASGI:
config.asgi:application. - FastAPI:
app.main:appwhen the file isapp/main.pyand the application object isapp. - Flask:
app:appwhen the file isapp.py.
Application interface — the same choice as in Install Gunicorn: WSGI for Django and Flask, ASGI for FastAPI and Starlette.
Port on 127.0.0.1 — the port Gunicorn listens on, on this server only, between 1024 and 65535. 8000 unless something else uses it.
What it does on the server
The examples below use an application named api on port 8000.
- Creates a system account and group named after the application. The account cannot sign in, and
/srv/apiis readable only by root and that account. - Writes
/etc/api/gunicorn.conf.py: listening on127.0.0.1:8000,syncworkers sized as twice the CPU count plus one for WSGI, or Uvicorn workers sized as the CPU count plus one for ASGI, a 30-second request timeout, worker recycling after about 1,000 requests, forwarded headers trusted from this server only, and logs to the journal. - Writes
/etc/systemd/system/api.service: Gunicorn from/srv/api/venv, working in/srv/api/current, run as theapiaccount, restarted if it fails, unable to write to the system or read home directories. Environment variables are read from/etc/api/environmentwhen it exists. - Checks the unit with systemd and the configuration with Python. The service is not started while there is no code.
After the run
For the api application on port 8000:
- Deploy your code to
/srv/api/current. - Install its requirements into the environment:
/srv/api/venv/bin/pip install -r /srv/api/current/requirements.txt. - Put its settings in
/etc/api/environment, oneKEY=valueper line, owned by root with mode 0640 and groupapi. - Start it with
systemctl enable --now api, and check it answers withcurl http://127.0.0.1:8000/. - Put HTTPS in front with Configure Reverse Proxy, forwarding to
http://127.0.0.1:8000.
Common problems
"Port … is already in use by …" — Choose another port. Nothing was changed.
"… already exists and was not written by this playbook." — A service with that name exists. Choose another application name, or remove the existing unit if it is no longer used.
"An account called … already exists and belongs to a person" — The name is taken by a user account. Choose another application name.
"… does not exist. Run Install Gunicorn for … first." — Run Install Gunicorn with the same application name first.
The service starts and then stops — Read its log, for api with journalctl -u api -n 50. A wrong Application module, missing requirements, or a setting the application expects in /etc/api/environment are the usual causes.