Node.js is a JavaScript runtime that lets you run JavaScript on the server, and npm is the package manager that ships with it. In this tutorial you will install the current Node.js LTS release (Node.js 24) and npm on Ubuntu 24.04 from the NodeSource repository, which is the right choice for a server that runs applications as system services. You will also see how to use nvm instead when you need several Node.js versions per user, and you will finish by running a small Express app to confirm everything works.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS, for example a CubePath VPS.
  • A non-root user with sudo privileges.
  • At least 1 GB of RAM. Building native npm modules on smaller servers may need swap.

Step 1 - Removing old Node.js packages

If Node.js was installed earlier from the Ubuntu repositories, remove it so it does not conflict with the NodeSource packages. apt reports that a package is not installed if it is not present, which is fine:

sudo apt remove nodejs npm

Check that no node binary is left in your PATH:

which node

The command should print nothing.

Step 2 - Adding the NodeSource repository

NodeSource publishes one apt repository per Node.js major version. Install the tools needed to fetch its signing key:

sudo apt update
sudo apt install ca-certificates curl gnupg

Download the NodeSource GPG key into /etc/apt/keyrings, the standard location for third-party repository keys:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg

Add the repository for Node.js 24, pinned to that key:

echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list

Refresh the package index and confirm that apt now picks the NodeSource package:

sudo apt update
apt policy nodejs
nodejs:
  Installed: (none)
  Candidate: 24.11.1-1nodesource1
  Version table:
     24.11.1-1nodesource1 500
        500 https://deb.nodesource.com/node_24.x nodistro/main amd64 Packages
     18.19.1+dfsg-6ubuntu5 500
        500 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages

The exact version numbers will differ; what matters is that the candidate comes from deb.nodesource.com.

Step 3 - Installing Node.js and npm

The NodeSource nodejs package includes both node and npm, so a single package is enough. Also install build-essential, which provides the compiler and make that npm needs to build packages with native add-ons:

sudo apt install nodejs build-essential

Verify the installed versions:

node --version
npm --version
v24.11.1
11.6.2

Updates now arrive through the normal system update process, so sudo apt upgrade keeps Node.js patched within the 24.x line.

Step 4 - Installing global npm packages without sudo

With a system-wide Node.js, npm install -g writes to /usr/lib/node_modules and requires sudo. That is acceptable for tools every user needs, but for your own command-line tools it is cleaner to give npm a prefix inside your home directory.

Create the directory and tell npm to use it:

mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global

Add its bin directory to your PATH in ~/.profile so it applies to every login shell:

echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.profile
source ~/.profile

Install a small CLI to test it, without sudo:

npm install -g http-server
which http-server
/home/your_user/.npm-global/bin/http-server

Step 5 - Testing Node.js with an Express app

To confirm that npm can download dependencies and Node.js can serve traffic, create a minimal Express application. Create a project directory and initialize it:

mkdir ~/hello-node
cd ~/hello-node
npm init -y
npm install express

npm init -y creates package.json with defaults, and npm install express adds Express to its dependencies and writes package-lock.json.

Create the application file:

nano index.js
const express = require('express');

const app = express();
const port = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send(`Hello from Node.js ${process.version}\n`);
});

app.listen(port, '127.0.0.1', () => {
  console.log(`Listening on http://127.0.0.1:${port}`);
});

Start it:

node index.js
Listening on http://127.0.0.1:3000

In a second SSH session, send a request:

curl http://127.0.0.1:3000
Hello from Node.js v24.11.1

Stop the app with CTRL+C. The app listens only on 127.0.0.1, so it is not exposed to the internet; in production you would keep it that way and put a reverse proxy such as Nginx in front of it.

Alternative: Installing Node.js with nvm

nvm (Node Version Manager) installs Node.js inside your home directory and lets you switch versions per project. It is useful on development machines or when different apps need different Node.js releases. Do not combine it with the NodeSource package for the same user unless you are aware of which node comes first in your PATH.

Download the install script, review it, then run it. Check the nvm releases page for the latest version number:

curl -fsSL -o install-nvm.sh https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh
less install-nvm.sh
bash install-nvm.sh

The script clones nvm into ~/.nvm and adds its loader to ~/.bashrc. Load it into the current shell:

source ~/.bashrc
nvm --version

Install the latest LTS release and make it the default for new shells:

nvm install --lts
nvm alias default 'lts/*'
node --version

To pin a version per project, write it to an .nvmrc file in the project root; nvm use and nvm install read it automatically:

echo "24" > .nvmrc
nvm use
Found '/home/your_user/hello-node/.nvmrc' with version <24>
Now using node v24.11.1 (npm v11.6.2)

Troubleshooting

EACCES: permission denied when running npm install -g. You are installing globally into /usr/lib/node_modules without sudo. Either use sudo npm install -g <package> or configure a user prefix as shown in Step 4. Never run chown on /usr to work around it.

gyp ERR! build error while installing a package. The package compiles a native add-on. Make sure build-essential and python3 are installed with sudo apt install build-essential python3, then run npm install again.

node --version still shows an old version. More than one Node.js is installed. List every node in your PATH:

which -a node

Remove the one you do not want (the Ubuntu package or the nvm version) and run hash -r to clear the shell's command cache.

npm ERR! code ETIMEDOUT during installs. The server cannot reach registry.npmjs.org. Check outbound HTTPS with curl -I https://registry.npmjs.org/ and review any outbound firewall rules or proxy settings.

Conclusion

You installed Node.js 24 LTS and npm on Ubuntu 24.04 from the NodeSource repository, configured a user-level prefix for global packages, and confirmed the setup with a small Express app. You also saw how nvm fits when you need several Node.js versions side by side.

From here you can:

  • Keep your app running in the background and across reboots with PM2.
  • Put Nginx in front of the app as a reverse proxy and add HTTPS with Let's Encrypt.
  • Use npm ci in your deployment process so production installs match package-lock.json exactly.