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
sudoprivileges. - At least 1 GB of RAM. Building native npm modules on smaller servers may need swap.
NoteUbuntu 24.04 includes a
nodejspackage in its own repositories, but it is Node.js 18, which is already end of life. Use NodeSource or nvm to get a supported release.
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.
TipTo install a different major version later, change
node_24.xin/etc/apt/sources.list.d/nodesource.listand runsudo apt update && sudo apt install nodejs.
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)
Importantnvm is a shell function loaded from
~/.bashrc. It is not available toroot,sudo, cron or systemd units. Services started outside your interactive shell need the full path to the binary (for example~/.nvm/versions/node/v24.11.1/bin/node), which is why NodeSource is the simpler choice for production servers.
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 ciin your deployment process so production installs matchpackage-lock.jsonexactly.
