• Plesk Uservoice will be deprecated by October. Moving forward, all product feature requests and improvement suggestions will be managed through our new platform Plesk Productboard.
    To continue sharing your ideas and feedback, please visit features.plesk.com

Issue 502 error Node and Angular SSR

igorosabel

New Pleskian
Server operating system version
Debian 11.11
Plesk version and microupdate number
18.0.69 #3
Hi!
I am setting up an Angular app that uses SSR on a Linux Debian 11.11 server with Plesk Obsidian 18.0.69. I have installed NodeJS Toolkit and I have enabled Node on a subdomain where the app will go.

The Angular app is using Angular 19.2.10, and the Node configuration is this:

Code:
Node.js version: 22.15.0
Package administrator: npm   
Document root: /dev.domain.com/public/dist/browser   
Application mode: development
Application URL: http://dev.domain.com
Application root: /dev.domain.com/public/dist   abierto
Application start file: server/server.mjs
Custom environment variables: - PORT: 4000

The problem is that I get a 502 Bad Gateway error when I open the app on a browser. Check the log I saw this:

2265912#0: *189198 connect() failed (111: Connection refused) while connecting to upstream

Looks like nginx cannot get to the Node app. On the nginx configuration I have this configuration:

Proxy mode - unchecked
Smart processing of static files - checked
Serve static files directly with nginx - unchecked
Activate nginx cache copy - unchecked
Aditional nginx directives:

Code:
location / {
    proxy_pass http://127.0.0.1:4000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}


location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|webp)$ {
    root /var/www/vhosts/domain.com/dev.domain.com/public/dist/browser;
    expires 1y;
    access_log off;
    add_header Cache-Control "public";
}

I opened a ssh to the server and I tried starting the Angular SSR application directly with:

node public/dist/server/server.mjs

And everything started working. Using this command:

ss -tuln | grep 4000

I saw the node application running, but when I stop it using Control + C the application didn't show up anymore. If I click on "Restart app" on the Node section of the subdomain, a message appears saying "the application will restart after the first request", but I still get a 502 and using the "ss" command it doesn't show anything working on port 4000.

The Angular SSR app on the server.mjs basically starts an Express server, so any help on setting this up? I have been looking everywhere but the Node documentation for Plesk is almost nothing.

Thanks!
 
I couldn't make it work using NodeJS Toolkit extension... so I went to more "native" solutions.

I installed "pm2" (process manager for node applications" running this as root:

npm i -g pm2

After that I made a shell script that allows me to add or update an application (I ran this on the first installment and every time I upload a new version):
Bash:
#!/bin/bash

# Configuration
PROYECT_DIR="/var/www/vhosts/example.com/dev.example.com"
NEW_DIST_DIR="$PROYECT_DIR/dist"
DEPLOY_DIST_DIR="$PROYECT_DIR/public/dist"
PM2_APP_NAME="example-test"
PM2_SCRIPT="$DEPLOY_DIST_DIR/server-wrapper.js"
PM2_PORT=4002
OWNER="igorosabel:psacln"

echo "==> Stopping and deleting current application from PM2..."
pm2 stop $PM2_APP_NAME
pm2 delete $PM2_APP_NAME

echo "==> Deleting previous deployment..."
rm -rf "$DEPLOY_DIST_DIR"

echo "==> Copying new dist version..."
cp -r "$NEW_DIST_DIR" "$DEPLOY_DIST_DIR"

echo "==> Installing NPM dependencies..."
cd "$DEPLOY_DIST_DIR" || { echo "Couldn't access $DEPLOY_DIST_DIR"; exit 1; }
npm install --production

echo "==> Fixing file permissions..."
chown -R $OWNER "$DEPLOY_DIST_DIR"

echo "==> Adding application to PM2..."
pm2 start "$PM2_SCRIPT" \
  --name "$PM2_APP_NAME" \
  --interpreter node \
  --env NODE_ENV=development \
  --env PORT=$PM2_PORT

echo "==> Saving PM2 configuration for automatic startup..."
pm2 save

echo "==> Deploy finished. PM2 status:"
pm2 list

On the Angular project I made these 3 scripts on the package.json file:
"build:test": "ng build --configuration test && npm run postbuild",
"build:prod": "ng build --configuration test && npm run postbuild",
"postbuild": "copy package.json dist\\ && copy package-lock.json dist\\ && copy src\\server-wrapper.js dist\\",

When I want to build a test version I run "npm run build:test", this compiles the application for the "test" environment and runs the "postbuild" script. The "postbuild" script just copies the package files and a "server-wrapper" file to the dist folder (which I upload to the server afterwards).

The "server-wrapper" is just a file that loads the "server" side of an Angular SSR application and runs it.

JavaScript:
console.log("Starting Example...");

import("./server/server.mjs")
  .then((module) => {
    console.log("File server.mjs correctly imported.");
    const port = process.env["PORT"] || 4002;
    module.default.listen(port, () => {
      console.log(
        `Node Express server started on http://localhost:${port}`
      );
    });
  })
  .catch((err) => {
    console.error("Error importing server.mjs", err);
  });

After all this code and files... I run "npm run build:test" to compile, upload the dist folder to the server and finally run the script on the server.

If you have any doubts I'll try to help :)
 
Back
Top