Python application hosting on CentOS with Plesk and Phusion Passenger

This guide will show you how I installed a Python application on the terminal, because I have not found a Plesk extension to configure a Phusion Passenger application developed in Python.

Plesk SSH terminal

In a Mac terminal or Git bash for Windows connect to your Virtual Private Server hosted by Contabo or similar hosting provider.

ssh -l root <hostname>

Or you could install the Plesk extension “SSH terminal” to get terminal access on the website in Plesk.  In Plesk under Websites & Domains, find your domain and select the tab Hosting and DNS under which you will see Web Hosting Access. Enter the password for the user that owns the website and in “Access to the server over SSH” select “/bin/bash” (default is forbidden). Now you will see a SSH terminal button on your domain.

Install Python as root

Go to Plesk extension, installed extensions and press SSH terminal to start a terminal root and check if python is installed

python39 -version

If not then install python

yum install -y peel-release
yum install -y python39

Check Python install path and version as well as pip version

whereis python
python3 –version
pip3 –version

If pip is not installed, then install it now

wget https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py

Install a simple text editor like nano.

yum install -y nano

Setup Passenger and reverse proxy

In Plesk under website go to Hosting & DNS and select Apache & Nginx settings. Add the following web server HTTP and HTTPS additional settings as per Phusion Passenger configuration documentation, that will proxy request to port 3000.

PassengerEnabled On
PassengerAppType wsgi
PassengerStartupFile passenger_wsgi.py

<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPreserveHost On
<Location "/">
ProxyPass "http://127.0.0.1:3000/"
ProxyPassReverse "http://127.0.0.1:3000/"
</Location>

Install Python virtual environment as owner

Start a new SSH terminal as the web site owner by pressing SSH terminal under Websites and Domains and your domain name, if you enabled SSH under Web Hosting Access as described above.

Backup any files in your document root

mkdir ~/backup
mv ~/httpdocs/* ~/backup/

Install full virtuelenv instead of minimal Python 3.3+ build in venv

sudo pip3 install virtualenv

Create the virtual environment for your Python app.

cd ~/httpdocs/
python3 -m virtualenv -p python3 python-app-venv

Active the virtual environment as you would any time you start a new terminal

source ./python-app-venv/bin/activate

Run Flask demo app

Install the Flask to host a demo app

pip3 install flask

Create a app.py script:

nano app.py

from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
    return 'Web App with Python Flask!'
app.run(host='0.0.0.0', port=3000)

Press Ctrl+O to write file and Ctrl+X to exit Nano editor.

Run the Flask development server to test the app on port 3000

export FLASK_APP=app.py
flask run –host=0.0.0.0 –port=3000

If you browse to your site you should see “Web app with Python Flask”

If you get a port conflict because something else is running on port 3000, use the following command to find a free port and change port in all places.

sudo lsof -i:3000

Run Phusion Passenger Python application

This is were you configure the Passenger application server to run your app. First make sure you closed the Flask development server or it will be running on port 3000.

Create the file passenger_wsgi.py next to your app.py file with one line:

from app import app as application

This will export your app object returned from Flask as application according to WSGI standard.

Now create a Passengerfile.json in httpdocs with arguments for the passenger start command and specify the website owner as user:

{
  "app_type": "wsgi",
  "startup_file": "passenger_wsgi.py",
  "environment": "production",
  "port": 3000,
  "daemonize": true,
  "user": "askembla"
}

Avoid having Passenger try to compile native support binaries.

export PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0

Start the application under Passenger

passenger start

Will now start the application the same as if you wrote

passenger start –daemonize –port 3000 –user askembla

To stop the Python application by running the following in httpdocs folder, where the passenger process ID (PID file) is stored.

passenger stop

Get a status of the Python application by running the following in httpdocs folder

passenger status

Things to test

Restarting Passenger Python Application by creating restart.txt and browsing to website should also work:

mkdir tmp
touch tmp/restart.txt

I did not try it yet, but you could probably start services on system boot by adding the below for each Python app to /etc/rc.local

export PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0
cd /var/www/vhosts/ask-embla.storybook.events/httpdocs
passenger start