Skip to main content

Deploy Node Apps

Node is a back-end JavaScript runtime environment, executes JavaScript code outside a web browser. Although Node is served as an compiled language, it doesn't emit binaries, so you don't need to compile your code before running it.

There's a default Node interpreter from system but we recommend you to install it as your own through deployment scripts.

warning

Serving Node apps can be run using CJS-only binding or via GLS. If you choose to run via GLS, you have to listen from given PORT env/args. If you choose to run it via CJS-only binding, please note the default app name (that's app.js) and the path of node interpreter to run with.

Example

The deployment script below installs the latest node compiler and writes app.js and serves that through CJS-only bindings.

https://github.com/domcloud/recipes/blob/master/node.yml
source: clear
features:
- node latest
nginx:
root: public_html/public
passenger:
enabled: "on"
app_type: node
startup_file: app.js
node: .local/opt/node/bin/node
commands:
- filename: app.js
content: |
const http = require('http');
const html_text = `
<!DOCTYPE html>
<html>
<head>
<title>Node App</title>
<link rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css">
</head>
<body class="p-5 text-center">
<p><img src="//images.unsplash.com/photo-1465153690352-10c1b29577f8?fit=crop&w=200&h=200"
class="img-fluid rounded-circle"></p>
<h1 class="mb-3">Hello, world!</h1>
<p>Serving from Node version ${process.version}</p>
<p class="text-muted">DOM Cloud</p>
</body>
</html>
`
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(html_text);
});
server.listen(process.env.PORT || 8080);

With CJS-only bindings, it doesn't matter what port number server.listen is being assigned, it will be corrected automagically. However with CJS-only bindings, you can't use ESM-style imports, you have to use GLS as the only option if your project uses that.

Existing Node projects

For existing node apps, use the deployment script below. Note the startup file name (app.js) and the package installer (whether you're using npm/yarn/pnpm these all are already installed with the help of corepack).

https://github.com/domcloud/recipes/blob/master/node-cjs.yml
features:
- node lts
nginx:
root: public_html/public
passenger:
enabled: "on"
app_type: node
startup_file: app.js
commands:
- npm install

Other deployment scripts we offer also listed below.

For projects that using ESM-style imports, GLS binding can be used as it's the basic for any custom web server either for Node and other code languages. The requirement to use this is your app must listen to given PORT env/args (either node ... --port=$PORT or env PORT=$PORT node ...). You can also use alternative calls such as node app.js here.

https://github.com/domcloud/recipes/blob/master/node-esm.yml
features:
- node lts
nginx:
root: public_html/public
passenger:
enabled: "on"
app_start_command: env PORT=$PORT npm start
commands:
- npm install

Use other Node versions

To switch node version use feature syntax like node stable, node latest, node 16.2.1, node 16, etc. Check your current node version using node --version in SSH.

features:
- node 16.2.1

Node install scripts is powered by nvm.

App Management

Your app do not restarted automatically after file changes. To restart, run restart via SSH.

Environment variables can be set either using NGINX's env_var_list or ~/.bashrc. Usually your language framework also reads .env files.

See NGINX and App Daemon for more information about NGINX and App managements including restarting, environment variables, and other global limitations.

App Development

If you're editing your Node.js app in place (e.g. using Visual Studio Code Remote), it is helpful to run a separate Node instance so you can see your changes live using nodemon or npm run dev or other similar tools.

The requirement is you need to use port 32000 or above, since these port will not be blocked from the server. So when starting a development instance, use something like PORT=31234 npm run dev in SSH.

To apply your changes back to NGINX, run your build flow (e.g. npm run build) then restart it by calling restart on SSH.

App Logging

You can see app log from Check -> Check Process Logs tab. Only startup problems displayed in the browser.

Please use a proper logging mechanism such as Pino or Winston then write it to a log file, or any other solution that suits you.

NGINX errors and traffic logs can be examined via Webmin or Check -> Check Process Logs tab.

Troubleshooting

FATAL ERROR: Reached heap limit Allocation failed during package installation

We limit all processes to have either 2GB (Tier I server) or 512MB RAM (Tier II server) to avoid crashing the whole system.

Most likely you're installing with npm which is bad at managing memory, please use yarn instead.

digital envelope routines::unsupported during script builds

You're using Create-React-App but having version that uses old OpenSSL.

Please update your depedencies to latest version with npx npm-upgrade. For Create-React-App, please try yarn create react-app my-app locally and copy all of their depedencies to your project.

Server is disabled due to storage violation

Please clear all yarn/npm caches. If you're not sure, use ncdu on SSH.

You should not run the Vite HMR server in CI environments. You should build your assets for production instead

Please do not run npm run dev or npm start in deployments. That's not how it works. Most likely what you want to do npm run build.

If you want to run npm run dev for live-in-production edits, use PORT > 32000 (e.g. PORT=33210 npm run dev).

error: cannot pull with rebase: You have unstaged changes.

You have uncommitted changes in your server. To resolve it please do git stash then git pull. Take your stashed changes back with git stash pop.

pnpm: command not found

You need to add node feature in your deployment script. Which enables corepack and pnpm.

Git changes after depedency install

Please add --frozen-lockfile to npm/yarn/pnpm install to prevent changing the lockfile. Also, you might want to add "packageManager" changes to your package.json because we have corepack enabled by default.

Any other error

Please open WebSSH or VSCode remote to fix it yourself. Or chat us if you stuck with "but it works on my machine".