FastAPI is an ASGI framework: it normally runs under Uvicorn. cPanel's Setup Python App serves Python apps through Phusion Passenger, which speaks WSGI. The two meet through a small adapter, a2wsgi, which wraps your FastAPI app as a WSGI application. For a normal REST API this works well. Here is the whole setup.
1. Upload the project
Put the code in a folder outside public_html, e.g. /home/youruser/api. A minimal app in main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health():
return {"ok": True}
Make sure requirements.txt includes the adapter:
fastapi
a2wsgi
2. Create the Python application
In Setup Python App → Create Application, choose a Python version (3.9 or newer for current FastAPI), set Application root to api, the Application URL to your domain or a sub-path like /api, and keep the startup file passenger_wsgi.py with entry point application.
3. Write passenger_wsgi.py
Replace the generated file's content with:
import os, sys
sys.path.insert(0, os.path.dirname(__file__))
from a2wsgi import ASGIMiddleware
from main import app
application = ASGIMiddleware(app)
4. Install the requirements and restart
In the app's screen, add requirements.txt under Configuration files, press Run Pip Install, then Restart. Open https://yourdomain.com/health. You should get {"ok":true}. The interactive docs are at /docs, so protect or disable them in production (FastAPI(docs_url=None, redoc_url=None)).
Sub-path deployments
If the app lives at /api rather than the domain root, your routes still start at / inside the app. If the interactive docs at /api/docs can't load openapi.json, set FastAPI(root_path="/api") so generated URLs include the prefix.
Environment variables and databases
Add secrets (database URL, API keys) as environment variables in the app's screen and read them with os.environ or pydantic-settings. Create the MySQL database and user in cPanel → MySQL Databases and connect with SQLAlchemy using mysql+pymysql:// (add pymysql to requirements). It needs no compiler, unlike mysqlclient.
What this setup is not for
- WebSockets: WSGI has no WebSocket support, so
@app.websocketroutes won't work through Passenger. - Long-running background work:
BackgroundTasksrun after the response inside the same request worker. Keep them short, or use a cron job (cPanel → Cron Jobs) for scheduled work. - Server-sent events / long streaming: responses are buffered by the adapter, so heavy streaming APIs belong on a VPS.
For typical JSON APIs, webhooks, admin backends and small SaaS services, this is a cheap, low-maintenance way to run FastAPI with SSL, backups and a database included.
Troubleshooting
- "ModuleNotFoundError: No module named 'main'": the application root is wrong, or
sys.pathdoesn't include the project folder (check the first two lines of passenger_wsgi.py). - 503 or "Incomplete response": an import error at start. Read
stderr.login the app folder, or runpython -c "import main"in the app's virtual environment over SSH (the screen shows the command to enter it). - Changes don't show up: press Restart after every code change.
Droxin Python hosting comes with Setup Python App, SSH and the CPU, RAM and storage you choose. If your FastAPI or Django app won't start, open a ticket and an engineer fixes it with you. Also see our Django and Flask deployment guide.