Skip to content
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Login Client Area
ALL SYSTEMS OPERATIONAL
Hosting

Deploy a Python/Django App in cPanel: Setup Guide

Getwebup 5 min read

If you've only ever deployed WordPress or a Node app through cPanel, "Setup Python App" feels like a different planet: a virtualenv you didn't create yourself, a passenger_wsgi.py file you're expected to write, and a 500 error that gives you nothing to go on. Here's how Python hosting actually works in cPanel, and how to fix the errors that trip people up most when getting Django (or Flask) running.

Where cPanel's Python support comes from

cPanel doesn't run your Python app directly. It hands the job to Phusion Passenger, the same application server that runs Node and Ruby apps on shared hosting. When you use Setup Python App (under Software in cPanel), it creates an isolated virtual environment for that one app, wires up a Passenger config behind the scenes, and expects a file called passenger_wsgi.py to expose your app as a WSGI callable named application. Get that contract wrong and Passenger just fails silently.

Step 1: Create the application

  1. In cPanel, go to Software → Setup Python App → Create Application.
  2. Pick a Python version (available versions depend on what your host has compiled with EasyApache/CloudLinux SCL - check what's offered before assuming the newest is there).
  3. Set the Application root, e.g. myproject - keep it outside public_html, cPanel handles the routing for you.
  4. Set the Application URL - this can be your domain, a subdomain, or a path.
  5. Leave Application startup file as passenger_wsgi.py and Application Entry point as application unless you have a specific reason to change them.

Click Create. cPanel now shows you an activation command for the virtualenv it just built - copy it, you'll need it in the next step.

Step 2: Activate cPanel's virtualenv before installing anything

This is where most Python deployments go wrong on day one. Don't just SSH in and run pip install django - that installs into the system Python, not the isolated environment Passenger will actually use. Run the exact command cPanel gave you:

source /home/yourusername/virtualenv/myproject/3.11/bin/activate
cd /home/yourusername/myproject

You'll see the prompt change to show the venv name. Everything you pip install from here goes into that isolated environment.

Step 3: Install your dependencies

pip install -r requirements.txt

For a fresh Django project that's usually just pip install django plus whatever you actually use (psycopg2-binary, whitenoise, etc.). You do not need gunicorn or uwsgi - Passenger is the WSGI server here, and running your own on top of it just adds a broken extra hop.

Step 4: Write passenger_wsgi.py correctly

For Django, bridge to its own WSGI application instead of reinventing one:

import sys, os

sys.path.insert(0, os.path.dirname(__file__))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

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

Two things people get wrong here: naming the variable anything other than application (Passenger looks for that exact name and nothing else), and pointing DJANGO_SETTINGS_MODULE at the wrong package path relative to where passenger_wsgi.py actually sits.

Common errors and what's really causing them

SymptomUsual causeFix
"We're sorry, but something went wrong" / bare 500passenger_wsgi.py throws on import, but Passenger swallows the traceback by defaultOpen Setup Python App → your app → Logs, or check the stderr log path shown there. That's where the real traceback lives.
ModuleNotFoundError: No module named 'django'Package installed to system Python, not the app's virtualenvRe-run the source .../activate command, reinstall inside it, then restart the app
DisallowedHost at / (Invalid HTTP_HOST header)Domain isn't in Django's ALLOWED_HOSTSAdd it in settings.py, save, restart the app
Django admin loads with no CSSDEBUG=False and static files were never collected or servedRun collectstatic and serve STATIC_ROOT via whitenoise or a dedicated alias - Passenger won't proxy static requests like runserver does
Code changes don't show up after deployPassenger caches the running process; cPanel doesn't watch filesClick Restart in Setup Python App, or run touch tmp/restart.txt in the app root over SSH

Fixing the static files problem properly

The cleanest fix for CSS/JS 404s in production is whitenoise - it lets Django serve its own static files without needing a separate web server config:

pip install whitenoise
# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ...rest of your middleware
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Then run python manage.py collectstatic and restart. No separate subdomain or symlink juggling needed.

Restart discipline matters more than it does with WordPress

A PHP change on cPanel shows up the moment you save the file. A Python app doesn't - Passenger keeps the process alive until you explicitly tell it to reload. Get in the habit of restarting after every deploy: code changes, settings.py edits, new environment variables, and new pip installs all require it. If you forget, you'll be debugging a bug that was actually fixed three deploys ago.

Prevention checklist

  • Pin your requirements.txt versions - an unpinned Django upgrade mid-project has broken more than one working deployment
  • Set DEBUG = False and a correct ALLOWED_HOSTS before going live, not after a customer reports a blank page
  • Store secrets (SECRET_KEY, database passwords) in the Environment Variables tab of Setup Python App, not hardcoded in settings.py
  • Always activate the app's own virtualenv before running pip, never the system Python
  • Restart the app after every deploy - no exceptions
  • Check the app-specific log path first when something breaks; the generic cPanel Errors page is a second stop, not the first

Once the venv and passenger_wsgi.py are set up correctly, Python apps on cPanel are actually low-maintenance - there's no separate systemd service to babysit, and Passenger restarts crashed workers on its own. The setup step is just unforgiving about getting the contract right the first time.

Frequently asked questions

Can I use Flask instead of Django with Setup Python App?

Yes. The setup is identical: create the app, activate the venv, install Flask, and in passenger_wsgi.py import your Flask app object and assign it to a variable named application, e.g. `from myapp import app as application`.

Do I need Gunicorn or uWSGI on cPanel?

No. Passenger is already acting as the WSGI server for your app. Running Gunicorn on top of it adds an extra process that Passenger isn't expecting to manage, and usually just breaks the routing.

Why does my app work locally but not on cPanel?

Almost always a virtualenv mismatch: packages installed to your local Python but not to the isolated venv cPanel created, or a DEBUG=True locally masking an ALLOWED_HOSTS or static files issue that only shows up in production.

Where do I find error logs for a Python app in cPanel?

Open Setup Python App, select your application, and check the Logs section. It shows the path to the app's stderr/error log where passenger_wsgi.py exceptions actually get written, which is more useful than the general cPanel Errors page.

Does changing requirements.txt take effect automatically?

No. You need to reactivate the app's virtualenv, run pip install -r requirements.txt again, and then restart the app (via the UI or touch tmp/restart.txt) before the new packages are picked up.

#python #django #cpanel #passenger #wsgi #deployment

Keep reading

Chat with Support