If you’ve ever uploaded a built API through the File Manager, opened the panel
terminal to run npm install, and been stopped cold — this guide is for you.
That dead-end is expected, not a bug, and there’s a cleaner path that never
needs the terminal at all.
The one thing to know first
The panel terminal runs as an unprivileged user and cannot use sudo. That’s
a deliberate security boundary: a web terminal with root access would mean anyone
who gets into your panel session owns the whole server. So you’ll never install
system packages or run sudo npm install from there — and you shouldn’t have to.
Instead, let OrbixPanel install dependencies and build your app for you,
server-side, with the right permissions. There are two sudo-free ways to do that:
You have…
Use
Terminal needed?
A Git repo (GitHub/GitLab/etc.)
Deploy from Git — the panel clones, installs, builds, starts
No
A local build you upload by hand
App Manager → Maintenance → Install dependencies
No
The old habit of “upload dist/, then SSH in to npm install” is the thing we’re
replacing. The Maintenance panel runs npm install, builds, and Prisma tasks
for you — server-side, as the service user, with your app’s env vars loaded. You
only fall back to SSH as a genuine last resort (covered at the end).
Path A — Deploy from Git (recommended)
This is the fastest and most repeatable way to run an API. The panel’s agent does
the privileged work for you: clone → npm ci (or npm install) → npm run build
(if you have a build script) → start under systemd. Nothing runs in your terminal.
Push your project to a repo. Keep package.json and package-lock.json at
the repo root. You do not need to commit node_modules or dist/ — the
panel builds them on the server.
App Manager → Create → Deploy from Git. Paste the repository URL.
Public repo: URL is all you need.
Private repo: add a personal access token (PAT) when prompted. It’s stored
encrypted, injected only for the clone, and redacted from the deploy log.
Pick the branch (defaults to the repo default) and deploy.
The agent detects the runtime automatically:
Node (package.json): runs npm ci || npm install, then npm run build if a
build script exists, then npm start — or node <entry> if there’s no start script.
Python (requirements.txt / Pipfile / pyproject.toml): creates a venv and
installs, adding uvicorn/gunicorn if needed.
Go (go.mod): go build.
PHP (composer.json): installs via Composer and serves through php-fpm.
To ship a new version later, just Deploy again (App Manager → your app →
Deploy). It re-clones, re-installs, and rebuilds — so this is your “run npm
install” button. Previous deployments are kept, so you can promote/rollback.
Why this works without sudo: the deploy runs through the OrbixPanel agent,
a privileged service that installs as the app’s service account (www-data) on
your behalf. Your browser session never holds those privileges — the agent does,
for exactly this one job.
Path B — Upload a build by hand, install from the panel
If you can’t or don’t want to use Git, you can still avoid the terminal entirely.
Upload your build, then let the panel install the dependencies for you.
Build locally, keeping package.json and package-lock.json at the root.
You do not need to upload node_modules:
Terminal window
# on your machine
npmrunbuild# produces dist/
myapp/
dist/ # compiled output (e.g. dist/src/main.js)
package.json
package-lock.json
prisma/ # if you use Prisma
Zip the folder, upload the zip via File Manager, and Extract it in
place under your app directory (e.g. /var/www/myapp). Uploading one archive is
far faster than thousands of individual files.
Create the app in App Manager pointing at the uploaded folder (see the next
section).
Install dependencies from the panel. Expand the app → Maintenance →
Install dependencies. OrbixPanel runs npm ci --omit=dev (falling back to
npm install) in the app directory, as the service user, and shows the output
live. Click Build too if your start command needs a fresh dist/. No
terminal, no sudo.
Prefer to pre-bundle instead? You can still ship node_modules inside the zip
(run npm ci --omit=dev locally first) so the app runs with no install step. If
you do, build on the same OS/architecture as your server (Linux x64/arm64) —
otherwise native modules like bcrypt, sharp, or better-sqlite3 won’t load.
When in doubt, use the Install dependencies button and let the server build them.
Create the app in OrbixPanel
Whichever path you used, the app settings are the same (Deploy from Git fills most
of these in for you):
Name: myapp → becomes the systemd service orbixapp-myapp
Runtime: Node
Directory: the project root — /var/www/myapp (not dist/src, so relative
paths like ./uploads resolve correctly and survive rebuilds)
Entry point: dist/src/main.js
Port: the port your app listens on, e.g. 5000
OrbixPanel writes a systemd unit (User=www-data, auto-restart), makes sure the
app directory is owned by www-data, and starts it.
Set environment variables
Expand the app → Environment Variables → paste KEY=value lines → Save &
restart. PORT is injected automatically; everything else (database URL, JWT
secrets, SMTP, etc.) goes here. Values are stored encrypted and reload into the
editor on refresh.
If your API uses a database, create the DB and user first and point DATABASE_URL
at it. Keep the password to letters and digits — special characters like @ : / #
must be percent-encoded in a connection string and are a common cause of
P1000: authentication failed.
Run Prisma (generate, migrate, seed) — no SSH
Prisma is the classic case where people reach for SSH, because prisma generate,
prisma migrate deploy, and the seeder all need to run on the server, against the
real database, with DATABASE_URL set. The Maintenance panel does exactly
that — it runs each command in the app directory with your saved env vars loaded,
so Prisma connects to the same database your app uses.
Set DATABASE_URL in Environment Variables first (above), then expand the app →
Maintenance → Prisma:
Button
Runs
When to use
Generate
prisma generate
After install, or whenever the schema changes — regenerates the Prisma Client
DB Push
prisma db push
Sync the schema to the database without migration files (prototyping)
Migrate
prisma migrate deploy
Apply committed migrations to the database (production)
Seed
prisma db seed
Run your seeder
Each runs server-side and streams its output into the panel — no terminal, no sudo.
Order that usually works: Install dependencies → Generate → Migrate (or DB
Push) → Seed → Restart.
Seeder setup:prisma db seed runs the command you declare in package.json.
Point it at compiled JS so it doesn’t need ts-node on the server:
{
"prisma": { "seed": "node dist/prisma/seed.js" }
}
If your seed is TypeScript (prisma/seed.ts), compile it as part of your build, or
set the seed command to "tsx prisma/seed.ts" and include tsx in your
dependencies — otherwise the server has no TypeScript runtime and the seed fails
with Cannot find module './seed.ts'.
Attach the domain + SSL
Point DNS: an A recordapi.example.com → <server IP>.
App Manager → your app → Domain → api.example.com → Save. OrbixPanel writes
an nginx reverse-proxy vhost pointing the domain at your app’s port.
Request SSL on the app. certbot issues the certificate and wires it into the
vhost.
Verify:
Terminal window
curl-shttps://api.example.com/health; echo
(Run that from your own machine — not the panel terminal.)
Last resort — the SSH path
If you’re doing something the panel doesn’t support yet (a custom build step,
system-level tooling), SSH into the server as a user with sudo and run the
privileged commands there:
Terminal window
cd/var/www/myapp
sudo-uwww-datanpmci--omit=dev# install AS the service user
sudochown-Rwww-data:www-data/var/www/myapp# if you installed as root by mistake
Installing as www-data matters: if you install as root, the app (which runs as
www-data) can’t write to node_modules or create runtime folders, and you’ll see
EACCES errors. This is precisely the manual bookkeeping that Path A and Path B
remove — reach for SSH only when you truly need it.
Quick error → fix reference
Error
Cause
Fix
Can’t run npm install in the panel terminal
The terminal has no sudo, by design
Use Maintenance → Install dependencies, or Deploy from Git — don’t install from the terminal
Cannot find module '@nestjs/core'
Dependencies not present
Maintenance → Install dependencies, or Deploy from Git
Prisma Cannot find module './seed.ts'
No TypeScript runtime on the server
Point prisma.seed at compiled JS, or use tsx and add it to dependencies
EACCES: permission denied, mkdir 'uploads/…'
App dir not owned by www-data
Deploy from Git (handles ownership), or sudo chown -R www-data:www-data /var/www/myapp over SSH
Prisma P1000
DB user/password/name missing or mismatched
Create the DB + user; check DATABASE_URL encoding
“Start request repeated too quickly”
A crash-loop tripped systemd’s limit
The panel resets this for you on Deploy/Restart; over SSH it’s sudo systemctl reset-failed orbixapp-myapp
Native module fails to load after a hand-upload
node_modules built on a different OS/arch
Rebuild on matching Linux arch, or use Deploy from Git