Open sourceIn the free reqad package (GPL-3.0).

Node.js and Python apps

Run an Express, Next.js, Nuxt, Flask, Django or FastAPI site on a domain. The app runs in the background as the hosting account. It restarts when it crashes and when the server boots. nginx passes the domain's visitors to it over HTTPS, with websockets.

Where: Accounts & Domains > Deployments in the panel (a site's Runtime), reqad app on the command line, and the REST API. An app serves a whole domain: the main domain of an account or one of its addon domains. Apps need nginx in front.
Off by default. Git deployments and Node.js / Python apps are one feature. Turn it on with deployments=1 in /usr/local/reqad/etc/server-software.ini; the Deployments page then appears under Accounts & Domains. While it is off, apps that already run keep running, but the page, reqad deploy, reqad app, their API endpoints and push webhooks are turned off.

Runtimes

Install the versions your apps need under Runtimes on the Deployments page, or with reqad app runtime install. Every app on the server can use them.

RuntimeWhere it comes from
Node.jsThe official Linux build of a major version (22, 24, ...), downloaded from nodejs.org and checked against its published SHA-256 checksums before it is installed, into /opt/reqad/node/<major>. Several majors can be installed side by side. Update moves a major to its latest release and restarts the apps that use it.
PythonPython 3.11 or 3.12 from the operating system's packages, updated with the rest of the system. Each app has its own virtualenv (.venv) in its folder.

Creating an app

  1. New deployment (or Settings of a site already there): choose the site, set Runtime to Node.js or Python, and check the start command: the panel reads it from the code (see below). Start from: Node.js app / Python app fills in a typical setup with Git; switch Code from Git off to upload the files yourself.
  2. The app must listen on 127.0.0.1 and the port in the PORT environment variable (HOST is set too). Each app gets its own port.
  3. Put the code in the app folder:
    • for a site deployed from Git, the deployment's current release;
    • otherwise ~/apps/<domain>/app, uploaded over SFTP;
    • or any folder of the account you choose.

From then on every request to the domain goes to the app, and PHP is off for that domain. When you remove the app, the domain serves its document root with PHP again. The app's files are kept.

Serve files from the document root first: nginx answers requests for files that exist in the document root itself, without asking the app. Use it for a built public folder such as public or dist. Do not use it when the document root holds the app's source code.

The start command

When the form opens, and when you change the app's folder, the panel reads the code in it (as the account; nothing runs) and fills in the start command. Below the field are the commands it found, by name, and the usual ones. Choose another one or write your own; what you type is never replaced.

It findsFromStart command
Djangomanage.py and the project's wsgi.py.venv/bin/gunicorn -w 2 -b 127.0.0.1:$PORT mysite.wsgi
Flask, Bottleapp = Flask(__name__) or a create_app() factory.venv/bin/gunicorn -w 2 -b 127.0.0.1:$PORT app:app
FastAPI, Starlette, Litestar, Quartapp = FastAPI().venv/bin/uvicorn main:app --host 127.0.0.1 --port $PORT
Next.js, Nuxt, SvelteKit (adapter-node), Astro (@astrojs/node), NestJSpackage.jsonthe framework's own server, e.g. node_modules/.bin/next start -H 127.0.0.1 -p $PORT
Other Node.js appsthe start script or main of package.json, or server.js, app.js, index.jsnpm start or node server.js
A Procfileits web: linethe same, with the .venv's server, on 127.0.0.1 and $PORT

The Python or Node.js version is chosen from .python-version, runtime.txt, pyproject.toml, .nvmrc or engines in package.json, among the versions installed. The panel also warns about what would stop the app from working: a server file that listens on a fixed port instead of process.env.PORT, no requirements.txt, a static site or a PHP site that needs no app, and Django's ALLOWED_HOSTS.

With Git, the code is often not on the server yet when you set up the app. Leave the start command empty then: the first deploy reads it from the new release, saves it and starts the app with it. If it finds none, or finds a Python app while the app is set to Node.js, the deploy stops and the site stays as it was. On the command line: reqad app detect <domain> [--dir=PATH].

Packages

Install packages installs what the app's folder lists, as the account, and then restarts the app. It runs in the background and shows its output while it works.

RuntimeWhat it does
PythonMakes the app's own .venv with the app's Python version (again, when you change the version). Then installs requirements.txt, or else the dependencies in pyproject.toml, or else the project itself (setup.py). If the start command uses gunicorn, uvicorn, hypercorn, waitress or daphne and the requirements leave it out, that is installed too.
Node.jsnpm ci when there is a package-lock.json, else npm install. Then npm run build if package.json has a build script.

It stops after 15 minutes. The last result stays on the app's row, with its output. On the command line: reqad app install <domain> --wait.

With Git deployments

An app and a Git deployment on the same domain work together:

  • An app with no start command yet gets it from the first release (the start command).
  • Each new release gets the app's packages the same way, before anything else runs: its own .venv or node_modules, so rolling back also brings back the packages of that release. If installing them fails, the deploy stops and the site stays as it was. Build commands that install packages themselves (pip install, npm ci...) are left to do it.
  • The build commands run after that, with the app's Node.js or Python first in PATH.
  • After the switch the app restarts on the new release.
  • If the app does not start, or does not listen on its port within 30 seconds, the deploy goes back to the previous release and restarts the app there.
# a Flask site from Git
reqad deploy create shop.example.com --repo=git@github.com:you/shop.git
reqad app create shop.example.com --runtime=python:3.12
reqad deploy run shop.example.com --wait    # finds the start command, installs, starts

Environment

Environment edits the app's variables, one KEY=value per line: database passwords, API keys, NODE_ENV. They are kept in ~/apps/<domain>/app.env, readable only by the account, and saving restarts the app. Node.js apps start with NODE_ENV=production. In Python apps, .venv/bin of the app folder comes first in PATH.

Limits and isolation

  • The app runs as the hosting account, in its own service (reqad-app-<id>), with a memory limit you choose (512 MB by default), one CPU and 256 processes.
  • It sees only its own account's home folder. Other accounts' homes and the panel's files are hidden from it, and the system folders are read-only.
  • Its port is reachable only by its own account and the web server. Other accounts on the server cannot connect to it and bypass nginx.
  • A crash restarts it after 3 seconds. If it crashes 5 times within 2 minutes it stays stopped, the site shows a "Temporarily unavailable" page, and the dashboard's Needs attention card says so.

Running apps

The Deployments page shows each app's state: running, not listening (the process runs but nothing answers on its port), stopped or failed. It also shows the memory used and the number of restarts. App log shows what the app printed, newest last. Stop keeps the app from starting again at boot, until you press Start.

On the command line

reqad app runtimes --available          # Node.js majors you can install
reqad app runtime install node 24
reqad app runtime install python 3.12
reqad app detect api.example.com --dir=apps/api.example.com/app   # the start command its code needs
reqad app create api.example.com --runtime=node:24 --start="node server.js"
reqad app list
reqad app logs api.example.com --lines=200
reqad app env api.example.com --file=production.env
reqad app restart api.example.com
reqad app delete api.example.com

See Command line (CLI) for every option.


Need a hand? Create a free account or contact us.