> ## Documentation Index
> Fetch the complete documentation index at: https://help.noxity.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Python

> Run Python WSGI apps on cPanel via the Python Selector. Pick an alt-python version, set the entry point, manage with Pip Install.

The cPanel **Setup Python App** tool registers a Python WSGI app under your account, builds a virtualenv, and hands the running process to Phusion Passenger.

CloudLinux ships Python interpreters as `alt-python` packages. Each app picks its own version, and the virtualenv lives separate from the system Python.

## Available versions

Available versions vary by host. Typical rotation:

* **Python 3.11.** Active.
* **Python 3.10.** Maintained.
* **Python 3.9.** Older, still common for legacy apps.

Older alt-python (3.7, 3.8, 2.7) may be available for compatibility. Avoid Python 2 for anything new.

## Set up an app

<Steps>
  <Step title="Open Setup Python App">
    From cPanel home, scroll to **Software** and click **Setup Python App**.

    <Frame caption="cPanel home → Software → Setup Python App">
      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/web-hosting/virtual-containers/python/open-light.png" alt="Setup Python App tool icon" className="block dark:hidden" />

      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/web-hosting/virtual-containers/python/open-dark.png" alt="Setup Python App tool icon" className="hidden dark:block" />
    </Frame>
  </Step>

  <Step title="Click Create Application">
    On an empty account, you land on a list page with a **+ Create Application** button.
  </Step>

  <Step title="Fill in the form">
    * **Python version**: pick from the dropdown.
    * **Application root**: directory under your home, e.g. `myapp`. Created if it doesn't exist.
    * **Application URL**: domain dropdown plus optional path. Use `/` for the root or `/api` for a sub-path.
    * **Application startup file**: defaults to `passenger_wsgi.py`. Leave it as that unless you have a reason.
    * **Application Entry point**: dotted path plus callable, format `module:callable`. For Django: `<project>.wsgi:application`. For Flask: `<module>:app`.
    * **Passenger log file**: optional. Useful for catching boot errors.
  </Step>

  <Step title="Save">
    Click **Create**. Passenger starts the app in the background.
  </Step>
</Steps>

## Manage an app

| Button              | What it does                                                       |
| ------------------- | ------------------------------------------------------------------ |
| **Run Pip Install** | Reads `requirements.txt` and installs into the per-app virtualenv. |
| **Stop App**        | Halts Passenger for this app. The URL returns 503.                 |
| **Restart**         | Equivalent to `touch tmp/restart.txt`. Reloads the running app.    |
| **Edit**            | Reopens the form. Saving overwrites the `.htaccess`.               |
| **Destroy**         | Removes Passenger registration and the per-app virtualenv.         |

The **Configuration files** field accepts paths like `requirements.txt` (relative to the application root). The **Environment variables** editor sits below the buttons.

## The Passenger contract

Passenger expects a WSGI callable named `application`. Your `passenger_wsgi.py` either defines it directly or imports it from your app.

For Flask:

```python passenger_wsgi.py theme={}
from myapp import app as application
```

For Django:

```python passenger_wsgi.py theme={}
import os
import sys

sys.path.insert(0, '/home/<user>/myapp')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
```

Your code does not run a development server. No `app.run()`, no `manage.py runserver`.

<Warning>
  Calling `app.run()` (Flask) or `runserver` (Django) inside a Passenger-managed app makes Passenger see no `application` and return a 500 with `passenger_wsgi.py did not provide an "application" callable`. Remove the call.
</Warning>

## ASGI apps

Native ASGI (FastAPI, Starlette, Channels) needs a WSGI shim. The common bridge is `asgiref.WsgiToAsgi` reversed, but Passenger's WSGI mode does not handle WebSockets or HTTP/2 streaming over ASGI. For a sync FastAPI subset, wrap with `a2wsgi`:

```python passenger_wsgi.py theme={}
from a2wsgi import ASGIMiddleware
from main import app as asgi_app

application = ASGIMiddleware(asgi_app)
```

For real WebSockets, run Daphne or Uvicorn outside the Selector. {/* TODO: write a Power-plan recipe for ASGI on a dedicated port */}

## Reference: where things live

| What                     | Path                                             |
| ------------------------ | ------------------------------------------------ |
| Activated env script     | `~/virtualenv/<app-root>/<version>/bin/activate` |
| Installed packages       | `~/virtualenv/<app-root>/<version>/lib/...`      |
| Restart trigger          | `~/<app-root>/tmp/restart.txt`                   |
| Passenger config         | `~/<app-root>/.htaccess` (Selector-managed)      |
| Boot log (if configured) | path you set in **Passenger log file**           |

From SSH, activate manually:

```bash theme={}
source ~/virtualenv/myapp/3.11/bin/activate && cd ~/myapp
pip install -r requirements.txt
```

## Common issues

<AccordionGroup>
  <Accordion title="500: 'did not provide an application callable'">
    `passenger_wsgi.py` doesn't expose a top-level name `application`. Either rename your callable to `application`, or alias it: `application = app`.
  </Accordion>

  <Accordion title="ImportError on a package that pip just installed">
    The package was installed against the system Python, not the per-app virtualenv. Run **Pip Install** from the cPanel UI, or activate the env in SSH first: `source ~/virtualenv/<app>/<ver>/bin/activate`.
  </Accordion>

  <Accordion title="Static files 404 on Django">
    Passenger only serves the WSGI app. Run `manage.py collectstatic` and serve `/static/` directly from Apache. Add to `.htaccess`:

    ```apache theme={}
    Alias /static/ /home/<user>/myapp/static/
    <Directory "/home/<user>/myapp/static">
      Require all granted
    </Directory>
    ```
  </Accordion>

  <Accordion title="`pip install pandas` (or numpy) runs out of memory">
    PMEM is \~1 GB. Heavy compiled wheels can OOM. Use prebuilt wheels (the default for pandas / numpy on linux x86\_64), avoid `--no-binary`, and consider installing one package at a time.
  </Accordion>

  <Accordion title="Boot times out on a Django app">
    Default Passenger startup timeout is 60 seconds. Long migrations or heavy `INSTALLED_APPS` initialization can exceed it. Bump the timeout in `.htaccess`:

    ```apache theme={}
    PassengerStartTimeout 120
    ```
  </Accordion>
</AccordionGroup>

## Recipes

<CardGroup cols={2}>
  <Card title="Deploy Django" icon="layer-group" href="/how-to/virtual-containers/python/django">Django app, virtualenv, static files.</Card>
  <Card title="Deploy Flask" icon="flask" href="/how-to/virtual-containers/python/flask">Flask service via `passenger_wsgi.py`.</Card>
</CardGroup>

## Need a hand?

<CardGroup cols={2}>
  <Card title="Open a ticket" icon="life-ring" href="https://members.noxity.io/submitticket.php">
    Best for anything that needs an account check or a config change on our end.
  </Card>

  <Card title="Live chat" icon="messages" href="https://noxity.io/contact">
    Faster for quick questions during business hours.
  </Card>
</CardGroup>

<div className="mt-8">
  <Accordion title="Sources" icon="book-bookmark">
    * [Virtual Containers overview](/web-hosting/virtual-containers/overview)
    * [Setup Python App ↗](https://docs.cpanel.net/cpanel/software/setup-python-app/)
    * [CloudLinux Python Selector ↗](https://docs.cloudlinux.com/cloudlinuxos/cloudlinux_os_components/#python-selector)
    * [Phusion Passenger Python ↗](https://www.phusionpassenger.com/library/walkthroughs/start/python.html)
  </Accordion>
</div>
