For a long time only PHP applications were well supported in cPanel, but now Python, Ruby, and Node.js apps can be deployed easily. In this guide, I will walk through the steps and configuration needed to run a plain WSGI app, a Flask app, and a Django app. In my cPanel version, it says cPanel 11 (86.0.13).
I am using cPanel provided by Interserver.net, a provider I have been using for years. They offer an unlimited hosting plan that lets you set up as many Python apps and domains as you want.
- Go to cPanel home.
- Under "Software" section, choose "Setup Python App"
- Choose "Create application"
- Fill out the options:
- Python version - pick the latest Python 3 if you are unsure
- Application root - Path relative to your home directory. You can provide full path like
/home/nanodano/mypyappbut it will replace it with
- Application URL - Choose the domain name and URL to use. Leave blank or enter
/to use the root of the domain. Note if you are using the default domain that points to
public_html/and you have an
index.htmlfile, that index file will take precedence for the root
- Application startup file - e.g.
app.py, the file that contains the WSGI application (Examples below). It will create a default file with some boilerplate to demonstrate it works so you do not have to provide a file before-hand.
- Application Entry point - The name of the function/object that WSGI should load. e.g.
app. Examples below, but it will automatically generate an example using your value.
- Passenger log file - Path to store log entries
- Environment variables - Any environment variables the app needs
- Click "Create" to save and run the app
After creating the application, it will create a virtual environment for your application, and configure the web server to run your app. You can use the cPanel Terminal or SSH in to activate the virtual environment and
pip install any modules you need to. For example, to install Flask:
pip install flask
Any time you make changes to the Python code, you need to restart the app from this panel.
Error messages will show up in your app directory in
At the top of the app detail page, it should tell you where the virtual environment is. The virtual environments for all apps by default are in your home directory like
It will also add a
.htaccess in the
public_html directory that contains something like the following:
PassengerAppRoot "/home/nanodano/mypyapp" PassengerBaseURI "/" PassengerPython "/home/nanodano/virtualenv/mypyapp/3.7/bin/python3.7" PassengerAppLogFile "/home/nanodano/passenger.log"
Make sure you don't remove that
.htaccess file or the directory it creates. If you map your Python app to a URL like
/myapp then it will create an empty directory with the same name in the
public_html/ directory. For example:
public_html/myapp. That is where the
.htaccess file will be mapping that path to the Python app. If you mapped it to
/ then the
.htaccess will be in
It will also create a file named
passenger_wsgi.py that bootstraps our custom app. This is the code it generates automatically. You generally shouldn't have to modify it but it does give you the option.
import imp import os import sys sys.path.insert(0, os.path.dirname(__file__)) wsgi = imp.load_source('wsgi', 'app.py') application = wsgi.application
Also note that cached Python files can cause your changes not to take effect even after restarting your app.
You may need to run a command like this to remove all the
.pyc, and other files.
find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
You can run your own custom WSGI apps, or use a framework like Flask or Django since they are WSGI compliant. For this example I'll show the basic example as well as a Flask and Django example. These Python scripts correspond with the cPanel field for "Application startup file". I prefer to name them
This is the default WSGI boilerplate provided by my cPanel.
There is nothing special about it except it does add its own
directory to the path so you can include your own packages locally.
To learn more about
sys.path and how import works, check out my Python import, sys.path, and PYTHONPATH Tutorial.
# app.py import os import sys sys.path.insert(0, os.path.dirname(__file__)) def app(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) message = 'It works!\n' version = 'Python v' + sys.version.split() + '\n' response = '\n'.join([message, version]) return [response.encode()]
Here is an example modified from above that will let you create a Flask application. We keep the
sys.path modification to keep allowing us to import custom packages from the app directory if we want to later.
# app.py import os import sys from flask import Flask sys.path.insert(0, os.path.dirname(__file__)) app = Flask(__name__) @app.route('/') def index(): return 'hi'
You can setup Django in a similar fashion. You just need to find and configure the
wsgi.py file and the name of the object in that file. If you use Django's
startproject command, the entry point will be named
application. Take the following example:
# Assuming you have activated the virtual environment. E.g.: source ~/virtualenv/pyapp/3.7/bin/activate # and installed django pip install django # Create a new Django project django-admin startproject myproject
Then the "Application Startup File" will be
The "Application Entry Point" will be
You will also need to update your
ALLOWED_HOSTS entry to include the ip/domain name you are using to access the site.
If you get an error about SQLite requiring a newer version than available, you can work around this by commenting out the
DATABASE object in the settings file or changing it to a database to another type.
If you get an error about not finding the settings file, you may need to alter the import path.
For example, when I create the Python app in my cPanel dashboard, it auto-generates a file named
passenger_wsgi.py that loads our WSGI application. The default file looks like this in my example:
import imp import os import sys sys.path.insert(0, os.path.dirname(__file__)) wsgi = imp.load_source('wsgi', 'myproject/myproject/wsgi.py') application = wsgi.application
passenger_wsgi.py file may be regenerated by the system if you restart the Python app. For this reason, it is better not to modify it, and modify your Django source code to include any extra
sys.path modification so you changes will persist instead of doing it in the
passenger_wsgi.py file which will get overwritten.
You can modify you Django's
wsgi.py to include the following line:
This line will allow the proper importing of the settings file. This is what a Django's
wsgi.py might look like after the additional line is added.
""" WSGI config for myproject project. It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ """ import sys import os # Add this line sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..')) from django.core.wsgi import get_wsgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') application = get_wsgi_application()
Be sure to remove any cached files like
.pyc in your app and restart the Python app in cPanel for changes to take effect.
To learn more about how the
sys.path and imports work, check out my Python import, sys.path, and PYTHONPATH Tutorial.
After reading this guide, you should understand how to deploy any Python WSGI app including:
- plain WSGI apps
- Flask apps
- Django apps