Use DirectAdmin/cPanel to run ANY WEB APPLICATION in ANY LANGUAGE!

Why?

Echoing my comments in https://lowendtalk.com/discussion/177687/nodejs-hosting-using-directadmin -

Since Apache can be used as reverse proxy why should we be limited by environment provided by the host?

How?

Apache ProxyPass (nope)

Of course Apache can act as reverse proxy natively - but this function is almost guaranteed to be disabled in shared hosting environment.

CloudLinux + Python Selector + Passenger (not natively)

DirectAdmin, or cPanel, is extremely flexible since it's a wrapper on top of Apache(aka LiteSpeed). Most hosts are using CloudLinux, which usually comes with Python Selector, although the logic behind is to ensure full isolation between users and allocate resources among every user for anti abuse.

Python(or Ruby/NodeJS) Selector is developed on Passenger, a plugin for Apache: starting from version 6.0 it's possible to use ANY language with this plugin as long as the app is taking in a port argument. However this does not seems possible with Apache, leaving us looking for other solutions.

CloudLinux + Python Selector + Passenger + Python WSGIProxy + flock

We can design a system like this:

  • DirectAdmin use CloudLinux as host
  • CloudLinux has Passenger installed exposing Python Selector
  • Write a custom WSGI Proxy talking to the app locally
  • Make the app listen to localhost and a port
  • Ensure the app is always running

Steps

You want SSH access to the host.

Upload application to host

Upload the application you want to run to the host. Make it run by listening to a random local port and 127.0.0.1. Use curl to ensure the app is actually running.

Setup Python Selector

Use any Python 3 provided.

Setup files

Enter the virtualenv by copy and pasting the command provided.

passenger_wsgi.py looks like:

import imp
import os
import sys

sys.path.insert(0, os.path.dirname(__file__))

wsgi = imp.load_source('wsgi', 'app.py')
application = wsgi.application

Create an app.py with:

import sys, os

import webob     # https://pypi.org/project/WebOb/
import wsgiproxy # https://pypi.org/project/WSGIProxy2/

BACKEND_HOST = os.getenv("ROCKET_ADDRESS", "localhost")
BACKEND_PORT = os.getenv("ROCKET_PORT", 30000)

BACKEND_URL = "http://{}:{}".format(BACKEND_HOST, BACKEND_PORT)
PROXY = wsgiproxy.HostProxy(BACKEND_URL)

def application(environ, start_response):
    req = webob.Request(environ)

    res = req.get_response(PROXY)

    start_response(res.status, res.headerlist)
    return [res.body]

Create a requirements.txt with:

WebOb
WSGIProxy2

Change the environment variables with:

  • ROCKET_PORT: the port your application shall listen on

Save the config. Use panel to install dependencies, or use SSH to run pip install -r requirements.txt.

Test your site: it should be working.

Setup application monitoring

In the "Cron Job" section in the panel, setup

flock -nx ~/tmp/app.lock -c "THE_STARTUP_COMMAND_OF_YOUR_APP"

Disable Email, and set the cron to * * * * * to check every minute.

References

https://github.com/jjlin/vaultwarden-shared-hosting

Leave a Reply

Your email address will not be published. Required fields are marked *