Running the NVM Service Manager
Publish a Studio "Service" project — a headless JS entry point, no HTML/UI at all — and run it as its own isolated, persistent process, reachable by name over the relay network.
Overview
A Service project's only file is JavaScript, with a top-level entry point:
async function AsyncNodoMain(input, callback) {
callback({ hello: input.name || 'world' });
}
Publishing it (right-click the project in Studio → Publish Service…) sends that code
to a Manager, which forks a brand-new, isolated Node.js process for it — a real OS process boundary, so
a crash or an infinite loop in one service can't touch another — and connects that process to the relay
under the project's own id. From then on, anything that can reach that relay can call it exactly the way
it would call a node: NodoRequest/NodoRequestAsync, or the same wire protocol
directly.
Studio's "Publish Service…" dialog addresses a Manager by relay + name, never a direct URL — the Manager itself also joins the relay under its own name, so this works even when it has no reachable address of its own (behind NAT/CGNAT, a home connection), the same reason every other worker in this ecosystem (a node, a CloudDB worker) is reached by name over the relay rather than a URL.
Every published service also gets, for free, no imports needed: NodoRequest/
NodoRequestAsync (call another service or node), JozieAI.ask/
NODOFI.request, NVMDNS.lookup, CONSOLE(text) (shows up in this
Manager's own dashboard), and NodoCloudDB — a full
Node port of the same database client a regular app uses, so a service can read/write shared data with
no extra setup.
Requirements
- Node.js 18 or later — the only real prerequisite. Everything else (the app's own dependencies) installs automatically on first run.
- Windows, Linux (any systemd-based distribution), or macOS (run from source).
- Unlike Nodofi Node, this needs a little configuration before it does anything: a relay to join, its own name on that relay, and a secret key — see Quickstart below.
Quickstart
Windows
- Download nodofi-nvm-manager-win-x64.zip and extract it anywhere you'll keep it.
- Double-click
install-startup.bat— the first time, this also installs dependencies and creates a.envfile from.env.example. - Open
.envin that folder and setMANAGER_KEY(a long random string) andMANAGER_NAME(unique on the relay you're using —RELAY_URLalready defaults to Nodofi's own public relay). Then runinstall-startup.batagain, orschtasks /run /tn "NodofiNvmManager". - Open http://localhost:8841 to finish setup.
Linux
tar -xzf nodofi-nvm-manager-linux-x64.tar.gz
cd nodofi-nvm-manager-linux-x64
sudo ./install.sh # creates .env from .env.example and tells you what still needs setting
Edit /opt/nodofi-nvm-manager/.env (set MANAGER_KEY/MANAGER_NAME),
then sudo systemctl start nodofi-nvm-manager. Open
http://localhost:8841 in a browser on that machine to finish setup.
macOS (or any OS, from source)
git clone <this repository>
cd nvm-service-manager
npm install
cp .env.example .env # then edit it — set MANAGER_KEY and MANAGER_NAME
npm start
The dashboard (:8841) redirects a first visit to a one-time setup page to create a
username and password — from then on it's also reachable remotely with those credentials (see
Remote dashboard access below). In Studio, right-click a Service project →
Publish Service…, and enter this Manager's RELAY_URL and
MANAGER_NAME — no URL needed.
Developers & API keys
The .env MANAGER_KEY is a root credential — it always works, for anyone who
has it. For attributing publishes to individual developers instead, create a per-developer API key from
the dashboard's Developers panel: enter a name, click New API key, and
copy the key shown — it's only ever shown once, only its hash is stored. That developer then uses their
own key in Studio's dialog exactly like the shared key. Every publish is attributed to whichever key made
it (the Services table's "Published by" column); revoking a key takes effect immediately for further
publishes, without stopping services that developer already published.
Analytics
Every handled request is timed and counted automatically — the dashboard's Services table shows live
request/error/latency totals per service, and each service's own Stats view shows a
per-minute breakdown for the last 24 hours. Minute-level buckets are pruned after
STATS_RETENTION_DAYS (default 14); the cumulative totals are kept forever.
Remote dashboard access
The dashboard is reachable locally with no setup at all. The first time you open it (local or remote — see below), it redirects to a one-time setup page to create a username and password; from then on it's also reachable from anywhere with those credentials (on by default the moment they're created — a "Turn off remote access…" button, reachable even from a remote session, is the kill switch). An authenticator app (TOTP) is a separate, optional second step added after your first sign-in.
ADMIN_PORT open on the internet
any longer than you have to.Login attempts are rate-limited (exponential backoff per source IP). An optional extra layer,
Beezifi Security "Ghost
Response" protection, can gate /admin/login specifically — every sign-in attempt checked
against your own Beezifi rules before this Manager's own password/TOTP check ever runs, failing closed
if Beezifi itself can't be reached.
Reverse proxy (Apache)
Two separate things can be proxied — the dashboard and, optionally, the HTTP publish API — kept on two separate (sub)domains, since the dashboard's own pages reference absolute root paths that can't safely be mounted under a sub-path. Neither needs WebSocket proxying (this Manager's own outbound connection to its relay doesn't go through either vhost).
# The dashboard — nvm-admin.example.com -> 127.0.0.1:8841
<VirtualHost *:443>
ServerName nvm-admin.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/nvm-admin.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/nvm-admin.example.com/privkey.pem
# Not optional: the dashboard's CSRF check compares the browser's Origin against the Host header it
# sees, and its login sets the session cookie Secure based on X-Forwarded-Proto.
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
ProxyPass "/" "http://127.0.0.1:8841/"
ProxyPassReverse "/" "http://127.0.0.1:8841/"
</VirtualHost>
A full ready-to-adapt config (both vhosts, plus a troubleshooting note on OCSP stapling) ships in
the download as apache.conf.example.
Uninstalling
Linux: sudo ./uninstall.sh from the folder you extracted (your .env and
data are kept). Windows: double-click uninstall-startup.bat, then delete the extracted
folder.