Hosting Next.JS on Plesk + Passenger (in 2021)

Vincent Van Uffelen
4 min readJun 3, 2021

Install the Node.JS version (X) you like/need

  1. Connect to the server via SSH (either directly as root user, change to root using su or try to use sudo in front of all commands to gain write permissions on the needed folders)
  2. Install NVM:
    curl -o- | bash
  3. Restart the SSH connection. or source your terminal profile file:
    source ~/.bashrc or source ~/.bash_profile or whatever shell you’re using
  4. Install Node.js version X:
    nvm install X
    (FYI: you can always switch node versions by running nvm use X - no need to be root user for that)
  5. Copy the installed files to Plesk working directory:
    List available versions:
    ls ~/.nvm/versions/node/
  6. Choose the one you’ve just installed and make it available to plesk (please note node 16 might actually be saved in v16.2.0):
    cp -R ~/.nvm/versions/node/X/ /opt/plesk/node/
  7. Register the installed version in Plesk:
    plesk sbin nodemng register /opt/plesk/node/X/bin/node
  8. Log in to Plesk and go to Extensions > Node.js.
  9. Click Refresh: to make sure that the newly installed. Once listed you will be able to select them while installing a plesk app on step 2.

To ensure that the “NPM Install” and “Execute Script” buttons on the plesk node app settings page do work with the correct version. You can also choose to register the just installed version globally accessible by creating symlinks to the currently choosen version:

ln -s /opt/plesk/node/v16.2.0/bin/node /usr/bin/node
ln -s /opt/plesk/node/v16.2.0/bin/npm /usr/bin/npm

More info:

2. Create a Node.JS app in Plesk

Primarily follow (its a :

Please note that if you’ve symlinked the node versions above you can omit the full path to npm in the post deploy actions. Touching tmp/restart.txt will instruct the server to restart the next time a user hits the app

npm ci --scripts-prepend-node-path
npm run build --scripts-prepend-node-path
touch tmp/restart.txt

Use the --scripts-prepend-node-path option to include the path. e.g. npm ci –scripts-prepend-node-path to avoid executed scripts to run accidentally the wrong npm/node version

3. Next.JS + Plesk Passenger

It does work. With SSR and ISR but you need to tweak some things and be aware of the following.

Environment Variables

While you can configure environment variables in the Plesk settings next.js does not pick these up. You will need to provide a .env.local file in the apps root. Do not commit the file into your repository. Further pulls/deploys keep it, you can place it right in the app root folder on the server (use SSH, SFTP or the file manager to adjust it to your needs).

Start Script.

You don’t need a custom server. But you can use the the next script node_modules/bin/next as the start script.

Even if Plesk complains

it does work.

HOWEVER! Executing node_modules/bin/next without any parameter (dev, build, start) does start the script in dev mode.

As it is not currently (June 2021) possible to configure an „Application Startup File“ with a parameter: e.g. node_modules/bin/next start (this breaks the passenger configuration). And the defaultCommand of the start script can’t be changed. I had to create a clone of the script in the app root (called it next-start.js), change the defaulCommand from „dev“ to „start“, and adjust all requires to match the new location of the script.

What I did was

  1. cp node_modules/bin/next next-start.js
  2. Then I edited the file to change
    const defaultCommand = “dev”;
    const defaultCommand = “start”;
  3. And replaced all
    require(“../ and require(“next/dist/…
  4. I then pointed the application startup file to the new startup file and all works as it should

Here is a quick excerpt of the file.

#!/usr/bin/env node"use strict";var log = _interopRequireWildcard(require("./node_modules/next/dist/build/output/log"));
var _index = _interopRequireDefault(require("./node_modules/next/dist/compiled/arg/index.js"));
var _constants = require("./node_modules/next/dist/lib/constants");
...const defaultCommand = "start";const commands = {build: () =>Promise.resolve().then(() => _interopRequireWildcard(require("./node_modules/next/dist/cli/next-build"))).then((i) => i.nextBuild),start: () =>Promise.resolve().then(() => _interopRequireWildcard(require("./node_modules/next/dist/cli/next-start"))).then((i) => i.nextStart),export: () =>Promise.resolve().then(() => _interopRequireWildcard(require("./node_modules/next/dist/cli/next-export"))).then((i) => i.nextExport),dev: () =>Promise.resolve().then(() => _interopRequireWildcard(require("./node_modules/next/dist/cli/next-dev"))).then((i) => i.nextDev),telemetry: () =>Promise.resolve().then(() => _interopRequireWildcard(require("./node_modules/next/dist/cli/next-telemetry"))).then((i) => i.nextTelemetry),};...if (command === "dev") {const { CONFIG_FILE } = require("./node_modules/next/dist/next-server/lib/constants");});}//#