Python App Hosting

Updated Oct 2, 2026 Markdown

WHost lets you host Python web applications — Django, Flask, FastAPI and similar — behind Gunicorn/Uvicorn application servers and an Nginx reverse proxy.

Python hosting is the free Python Hosting plugin: activate it once under Settings → Plugins. While it is inactive, the Python Apps menu entry is hidden in both panels and every Python app endpoint answers 503 PLUGIN_DISABLED.


Supported Stack

FrameworkDjango, Flask, FastAPI, Custom
Application ServerGunicorn (WSGI; ASGI with the Uvicorn worker class), Uvicorn (ASGI)
Python VersionsWhichever of 3.10 – 3.13 are installed on the server (/usr/bin/python3.X)
Web ServerNginx reverse proxy, written automatically — the server's web server setup must include Nginx (Nginx or Nginx + Apache)
Process Managementsystemd (auto-restart, the account's cgroup slice)

Admin Panel

Creating an Application

Tools → Python Apps → New Python App opens a chooser:

  • Smart Deploy (recommended) — upload an archive or point to a path on the server; the project is analyzed and deployed in one run. See Smart Deploy.
  • Create Blank App — creates the runtime scaffold only, with the form below; you add the code and run the setup steps yourself.
Field Description Example
Account Account the application will belong to siteowner
App Name Unique identifier: starts with a lowercase letter, then lowercase letters, digits, _ or - (2–31 characters) turkuaz
Display Name Human-readable name Turkuaz Site Management
Domain A domain of the account — its primary domain, an addon domain or a subdomain (picking the account fills in its primary domain) turkuaz.example.com
Python Version One of the versions installed on the server 3.12
Framework Application type Django
App Server Gunicorn (WSGI) or Uvicorn (ASGI) Gunicorn (WSGI)
Entry Point WSGI/ASGI entry point (module.path:callable) turkuaz.wsgi:application
Workers Worker count (1–16, and no more than the account's Python Workers / App limit) 2
Worker Class Sync, Threaded (gthread) or Uvicorn Worker (ASGI) — used by Gunicorn Sync
WebSocket Support Enable for ASGI applications Off
Auto Restart Automatically restart on crash On

During creation the system automatically:

  • Creates the application directory /home/{user}/{app}/ and a virtualenv
  • Installs Gunicorn (for Uvicorn apps: uvicorn[standard] and Gunicorn)
  • Defines a systemd service and a logrotate rule
  • Configures the Nginx reverse proxy
  • Starts the service — until the code is in place it fails to boot (see Typical Setup Steps)

Managing an Application

From the ⋮ menu on the table row, or the detail screen opened by clicking the application name:

Row menu:

  • Edit App (display name, domain, entry point, workers, worker class, WebSocket support, auto restart)
  • Packages / Environment Variables / Logs / manage.py — open the detail screen on that tab
  • Start (when not running) / Stop (when running) / Restart
  • Delete App (requires confirmation) — removes the service, the Nginx configuration, the virtualenv, the application directory /home/{user}/{app}/ with its code, and the app's log files

Detail screen (5 tabs):

OverviewFull configuration and status
PackagesInstalled pip packages (name, version) — read-only in the admin panel; installing, uninstalling and requirements.txt are in the client panel and the API
Environment VariablesEdit environment variables (KEY=VALUE)
LogsView error and access logs
manage.pyRun Django commands

All Applications View

The Python Apps page in the admin panel lists every application across all accounts in a single table. Narrow the view with search (app name, display name, account, domain), the status filter (Running / Stopped / Failed), or the Python version filter (shown when the apps use more than one version).


Client Panel

Creating an Application

Tools → Python Apps → Create App opens the same chooser (Smart Deploy or Create Blank App). The blank-app form matches the admin form without the Account selector — the application is created under the signed-in user's account — and without Worker Class (change it later with Edit App).

Managing an Application

The client panel has the same row menu and the same five detail tabs. Differences from the admin panel:

  • The Packages tab can also install and uninstall packages and install requirements.txt (see Pip Package Management).
  • The manage.py list also offers createsuperuser and shell (see Django Commands).
  • The list has a search box (app name, display name, domain) but no status or version filter.

Smart Deploy

Available in both panels from the chooser:

  1. Source — Upload Archive (.zip / .tar.gz, up to 250 MB) or Server Path (a folder or an archive inside the account's home directory; use SSH/SFTP and this mode for larger projects).
  2. Analyze — detects the framework, app server, Python version, entry point, static paths and the environment variables the code reads, and names missing system libraries.
  3. Deploy — review the detected values and the options (Overwrite Existing, Include .env Files, Run migrate, Run collectstatic), then deploy. The pipeline copies the files to /home/{user}/{app}/, creates the app, installs requirements.txt, runs migrate and collectstatic for Django when selected, and starts the app; the dialog streams the log live.

Leaving DB_NAME, DB_USER and DB_PASSWORD empty (for a project that reads them) creates a MySQL database and user during the deploy and passes their credentials to the app. A database dump or media folder inside the uploaded project is detected in both panels; uploading a separate SQL dump or media archive works in the admin panel only.


Pip Package Management

Detail screen → Packages tab. The admin panel lists the installed packages; installing and removing them is done in the client panel (or through the API).

Install a packageType the package name and click Install (multiple: separate with spaces)
requirements.txtInstall from requirements.txt installs /home/{user}/{app}/requirements.txt
Remove a packageTrash icon at the end of the row (Uninstall)

Accepted package name formats: django, django==6.0.1, gunicorn>=22.0, uvicorn[standard]


Environment Variables

Detail screen → Environment Variables tab

AddEnter Key and Value, click Add Variable
EditChange the value inline on the row
Remove× icon at the end of the row
SaveSave Variables — additions, edits and removals take effect only when saved

Keys use letters, digits and _ and do not start with a digit; values are single-line, up to 16,384 characters. After saving, the application is automatically restarted if it is running.

The variables are written to /home/{user}/{app}/.env (0600) and handed to the application's service; a variable with an empty value is left out. manage.py commands — from the tab, the API or Smart Deploy — run outside that service and see these variables only when the project reads .env itself (for example with python-decouple or django-environ).

Common variables:

text
DJANGO_SETTINGS_MODULE = myapp.settings.production
SECRET_KEY             = your-secure-random-key
DATABASE_URL           = mysql://user:pass@localhost/dbname
DEBUG                  = false
ALLOWED_HOSTS          = example.com

Viewing Logs

Detail screen → Logs tab

  • Error Log: application errors and tracebacks
  • Access Log: HTTP requests (IP, path, status code)
  • Pick the log type from the dropdown; click Refresh to reload. The tab shows the last 200 lines.

Log files: /home/{user}/logs/{app}-error.log and {app}-access.log


Django Commands (manage.py)

Detail screen → manage.py tab (Django projects — the application directory must contain manage.py)

Pick a command from the dropdown and click Run. The command runs as the account's user in the application directory, with a 5-minute limit; the exit code, output and errors are shown on screen.

migrateApply database migrations (runs with --noinput)
collectstaticCollect static files (runs with --noinput)
showmigrationsShow migration status
checkCheck the project for issues

The client panel's list also shows createsuperuser and shell, and the API accepts both, but they need an interactive terminal, which a panel or API run does not provide. Create the Django admin user over SSH instead, when the account has shell access: cd ~/{app} && ~/venvs/{app}/bin/python manage.py createsuperuser.


Typical Setup Steps

To host a new Django application as a blank app (Smart Deploy covers steps 4–9 in one run):

  1. Create an account — Accounts → Create Account
  2. Add a domain (only if the app uses a domain other than the account's primary domain) — Domains → Add Addon Domain or Add Subdomain
  3. Create a database — Databases → Create Database
  4. Create the Python application — Python Apps → New Python App → Create Blank App
  5. Upload the application code — via FTP, File Manager or SSH/SFTP into /home/{user}/{app}/
  6. Install dependencies — Packages → Install from requirements.txt (client panel, or POST …/pip/requirements through the API)
  7. Set environment variables — Environment Variables → DATABASE_URL, SECRET_KEY, etc.
  8. Run migrations — manage.py → migrate
  9. Collect static files — manage.py → collectstatic
  10. Create an admin user — manage.py createsuperuser over SSH (it needs an interactive terminal)

The service was started when the app was created and fails to boot until the code is in place. With Auto Restart on, systemd retries it every 5 seconds, so it comes up once the code, packages and variables are ready and the application becomes reachable on the domain; otherwise start it from the ⋮ menu.


Updating Application Code

To update an existing application:

  1. Upload the new code (FTP / File Manager / SSH)
  2. If there are new dependencies → Packages → Install from requirements.txt (client panel or API)
  3. If there are new migrations → manage.py → migrate
  4. If static files changed → manage.py → collectstatic
  5. Restart

Plan Limits

Hosting plans expose two limits for Python applications:

Limit Description Default
Max Python Apps Maximum number of applications per account 0 (unlimited)
Python Workers / App Most workers a single application may be given (0 = unlimited) 4

Set these under Plans → Edit Plan → Package Limits; the account create and edit pages carry the same fields. The check reads the account's own values, so a plan change reaches an existing account through a package change or its edit page. Going over a limit is refused with 403 PYTHON_APP_LIMIT or 403 PYTHON_WORKER_LIMIT.


File Layout

Creating a Python application produces the following layout on the server:

text
/home/{user}/
├── {app}/                       ← Application code
│   ├── manage.py
│   ├── gunicorn.conf.py         ← Generated automatically
│   ├── .env                     ← Environment variables (0600)
│   └── ...
├── venvs/{app}/                 ← Virtualenv
│   ├── bin/python
│   ├── bin/pip
│   └── bin/gunicorn             ← and bin/uvicorn for Uvicorn apps
└── logs/
    ├── {app}-error.log
    └── {app}-access.log

/etc/systemd/system/
└── whost-pyapp-{user}-{app}.service

/etc/nginx/sites-available/      ← /etc/nginx/conf.d/ on AlmaLinux, Rocky Linux, CentOS Stream
└── {domain}-pyapp-{app}.conf

/etc/logrotate.d/
└── whost-pyapp-{user}-{app}     ← log rotation, 14 compressed copies kept

/run/whost/{user}/
└── {app}.sock                   ← Unix socket

API Reference

All endpoints live under the /api/v1/ prefix.

Admin Endpoints

Method Path Description
GET /accounts/{user}/python-apps List applications
POST /accounts/{user}/python-apps Create an application
GET /accounts/{user}/python-apps/{app} Detail
PUT /accounts/{user}/python-apps/{app} Update
DELETE /accounts/{user}/python-apps/{app} Delete
POST /accounts/{user}/python-apps/{app}/start Start
POST /accounts/{user}/python-apps/{app}/stop Stop
POST /accounts/{user}/python-apps/{app}/restart Restart
GET /accounts/{user}/python-apps/{app}/status Status
GET /accounts/{user}/python-apps/{app}/pip Package list
POST /accounts/{user}/python-apps/{app}/pip/install Install a package
POST /accounts/{user}/python-apps/{app}/pip/uninstall Uninstall a package
POST /accounts/{user}/python-apps/{app}/pip/requirements Install from requirements.txt
GET /accounts/{user}/python-apps/{app}/env Get environment variables
PUT /accounts/{user}/python-apps/{app}/env Set environment variables
GET /accounts/{user}/python-apps/{app}/logs Get logs
POST /accounts/{user}/python-apps/{app}/manage Run a manage.py command
POST /accounts/{user}/python-apps/analyze Smart Deploy: analyze an uploaded archive (multipart, up to 250 MB) or a server_path
POST /accounts/{user}/python-apps/migration/upload Smart Deploy: stage an SQL dump and/or media archive for the next deploy
POST /accounts/{user}/python-apps/deploy Smart Deploy: start the pipeline; returns a task_id
GET /accounts/{user}/python-apps/deploy/{task_id} Deploy task status and its events
GET /accounts/{user}/python-apps/deploy/{task_id}/events Live deploy log (Server-Sent Events)
GET /system/python/versions Installed Python versions
GET /system/python/apps All applications

Client Endpoints

Client endpoints live under the /client/python-apps/ prefix and authenticate with the account's session cookie (or an API key bound to the account). The account name is not supplied — it is taken from that identity.

Method Path Description
GET /client/python-apps My applications
POST /client/python-apps Create an application
GET /client/python-apps/{app} Detail
PUT /client/python-apps/{app} Update
DELETE /client/python-apps/{app} Delete
POST /client/python-apps/{app}/start Start
POST /client/python-apps/{app}/stop Stop
POST /client/python-apps/{app}/restart Restart
GET /client/python-apps/{app}/status Status
GET /client/python-apps/{app}/pip Package list
POST /client/python-apps/{app}/pip/install Install a package
POST /client/python-apps/{app}/pip/uninstall Uninstall a package
POST /client/python-apps/{app}/pip/requirements Install from requirements.txt
GET /client/python-apps/{app}/env Get environment variables
PUT /client/python-apps/{app}/env Set environment variables
GET /client/python-apps/{app}/logs Get logs
POST /client/python-apps/{app}/manage Run a manage.py command
POST /client/python-apps/analyze Smart Deploy: analyze an uploaded archive (multipart, up to 250 MB) or a server_path
POST /client/python-apps/deploy Smart Deploy: start the pipeline; returns a task_id
GET /client/python-apps/deploy/{task_id} Deploy task status and its events
GET /client/python-apps/deploy/{task_id}/events Live deploy log (Server-Sent Events)
GET /client/python-apps/versions Installed Python versions
Still Need Help?

Our support team is here around the clock for anything you can't find above.