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.