Deploy Django on cPanel Shared Hosting

Deploy Django on cPanel shared hosting with Setup Python App and Phusion Passenger: create the app and virtualenv, write passenger_wsgi.py, use MySQL or PostgreSQL, serve static files from public_html, and know the hosting limits.

Problem statement

Many people already pay for shared hosting with cPanel, and it often supports Python through the Setup Python App tool, which runs apps with Phusion Passenger. You cannot install Nginx, Gunicorn, or systemd services on shared hosting, so the usual VPS guides do not apply. You can run a Django site, though, if you follow cPanel's model: Passenger loads a passenger_wsgi.py file, cPanel manages a virtualenv for you, and static files are served by the host's web server from your public directory.

Django on cPanelSetup Python Appcreates venv + apppassenger_wsgi.pyloads DjangoStatic filescopied to public_htmlRestart via touchtmp/restart.txtPassenger starts Django on demand; you manage code, venv packages, and static files.
  1. In cPanel, open Setup Python App, create an app with the newest Python version offered, application root (for example myapp), and URL.
  2. Upload or git clone the project into the application root.
  3. Enter the virtualenv using the command cPanel shows, then pip install -r requirements.txt.
  4. Point passenger_wsgi.py at your Django WSGI application.
  5. Create a MySQL (or PostgreSQL, if offered) database in cPanel and set the credentials as environment variables in the app settings.
  6. Set STATIC_ROOT inside public_html (or a subfolder), run collectstatic, migrate, then restart the app.

Step-by-step solution

1. Create the Python app

In cPanel → Software → Setup Python App → Create Application:

  • Python version: the newest available (3.11+).
  • Application root: myapp (a folder in your home directory, outside public_html).
  • Application URL: your domain or a subdomain.
  • Application startup file: passenger_wsgi.py; entry point: application.

cPanel creates a virtualenv under ~/virtualenv/myapp/<version>/ and shows a command to activate it.

2. Upload code and install packages

With SSH (enable it in cPanel if available) or the Terminal feature:

source ~/virtualenv/myapp/3.12/bin/activate
cd ~/myapp
git clone https://github.com/you/myapp.git .
pip install -r requirements.txt

Without SSH, upload files with the File Manager and use the "Run Pip Install" button in Setup Python App. Packages that need compilation may fail on shared hosts without compilers; prefer pure-Python or wheel-available packages, and mysqlclient may need the host's support, with PyMySQL as a fallback.

3. Write passenger_wsgi.py

# ~/myapp/passenger_wsgi.py
import os
import sys

sys.path.insert(0, os.path.dirname(__file__))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")

from config.wsgi import application  # noqa: E402

Passenger imports this file and calls application for each request, starting worker processes on demand.

where everything lives in your account~/public_html/static/collected static, served directly~/myapp/project code, outside public_html~/myapp/passenger_wsgi.pyPassenger entry point~/virtualenv/myapp/3.12/packages, managed by cPanel~/myapp/tmp/restart.txttouch to restart the appKeep code outside public_html so settings files are never downloadabledjango-deployment.com
Only the static folder belongs in public_html; never put settings or .env files there.

4. Database and environment

Create a database and user in MySQL Databases (or PostgreSQL Databases if the host offers it), grant all privileges, and add environment variables in the Setup Python App screen: SECRET_KEY, DATABASE_URL (for example mysql://cpuser_app:pass@localhost/cpuser_myapp), ALLOWED_HOSTS. For MySQL, set OPTIONS = {"charset": "utf8mb4"}.

5. Static files, migrations, restart

STATIC_URL = "/static/"
STATIC_ROOT = os.path.expanduser("~/public_html/static")
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.expanduser("~/public_html/media")
python manage.py migrate
python manage.py collectstatic --noinput
touch ~/myapp/tmp/restart.txt

The host's web server (Apache or LiteSpeed) serves /static/ and /media/ directly from public_html. Restart by touching tmp/restart.txt or clicking Restart in Setup Python App after every code change.

6. HTTPS

Enable AutoSSL (or Let's Encrypt in cPanel) for the domain. Add SECURE_PROXY_SSL_HEADER if the host proxies to Passenger, and force HTTPS with the cPanel Domains "Force HTTPS Redirect" switch.

shared hosting capabilitiesSupportWorkaroundWeb requests✓yes, Passengernone neededBackground workers!usually nocron-driven tasksScheduled jobs✓cPanel Cron Jobsvenv python pathCompiled packages!limitedpure-Python fallbacksResource limits!CPU and memory cappedmove to a VPS when hitShared hosting suits small sites; growth means a VPS or PaaSdjango-deployment.com
Check your host's resource limits page before launching anything busy.

Verification check: visit the domain over HTTPS, confirm admin CSS loads from /static/, check the Passenger error log (often ~/myapp/stderr.log or under ~/logs/) for startup errors, and edit a template then touch restart.txt to confirm changes appear.

Explanation

Phusion Passenger is an application server that integrates with Apache and LiteSpeed. cPanel's Setup Python App (provided by CloudLinux on many hosts) wraps Passenger with a per-app virtualenv and environment settings. Passenger spawns Python processes as requests arrive and can stop idle ones, which suits shared servers where many accounts share resources. Django runs normally inside it; the constraints come from the shared environment: no root access, capped resources, and no long-running processes of your own.

Edge cases / notes

  • 500 errors with no detail: check stderr.log in the app root and set up file logging to a writable path.
  • Python version is limited to what the host installs; ask the host if you need newer.
  • Celery generally cannot run; use cron with management commands for periodic work.
  • Database limits on shared plans (connections, size) can bite as traffic grows.

Next steps

FAQ

Can I host Django on cPanel?

Yes, if your host offers Setup Python App (Passenger). Without it, you need a VPS or PaaS.

How do I restart a Django app on cPanel?

Touch tmp/restart.txt in the app root or click Restart in Setup Python App.

Can I use PostgreSQL on cPanel?

Some hosts offer PostgreSQL Databases in cPanel. Otherwise use MySQL with utf8mb4.

Why are my static files not loading?

STATIC_ROOT must be inside public_html (or served by the host), and you must run collectstatic after each change.

Keep going