Node.js

Node.js ist eine JavaScript-Runtime auf Basis der V8-Engine aus Google Chrome. Das Ausführungsmodell ist single-threaded und ereignisorientiert; I/O-Operationen laufen über eine asynchrone Event-Loop, CPU-intensive Arbeit hingegen bleibt Single-Thread und braucht bei Bedarf Worker-Threads oder mehrere Prozesse. Für Linux-Admins tritt Node.js meist in zwei Rollen auf: als Laufzeit für Server-Applikationen (Rocket.Chat, NodeBB, Grafana-Plugins, GitLab-Komponenten) oder als Werkzeug hinter Build-Tools von Front-End-Projekten.

Der schwierige Teil an Node.js ist selten die Runtime selbst, sondern das Zusammenspiel mit Paketmanagern, Versionsverwaltern und Distributions-Paketen. Wer blind der Anleitung einer App folgt, landet schnell in einem Zustand, in dem Node per dnf, n und npm --global parallel installiert ist.

Begriffe

Corepack

Mit Node 16.10 ausgeliefertes Werkzeug, das Package-Manager-Binaries (yarn, pnpm) je nach Projekt-Angabe bereitstellt, ohne dass sie global per npm install --global eingerichtet werden müssen. Projekte können per packageManager-Feld in package.json eine konkrete Manager-Version festschreiben.

n

Einfacher Version-Switcher für Node.js. Installiert Node-Binaries nach /usr/local/n/versions/node/<version>/ und legt Symlinks in PATH an. Systemweit (nicht per User). Sinnvoll auf Servern, auf denen die Node-Version gezielt über n gemanagt werden soll.

Node.js

Die Runtime selbst. Wird im CLI als node aufgerufen. Red-Hat-basierte Distributionen legen auf einigen Systemen zusätzlich den Symlink /bin/nodejs /bin/node an, damit Apps, die nach nodejs suchen, fündig werden.

node-gyp

Build-Werkzeug für native Node-Addons (C/C++-Module). Viele npm-Pakete ziehen es als Build-Abhängigkeit; auf dem Host braucht es dafür python3 und die passenden Compiler (gcc-c++, make).

NodeSource

Drittanbieter-Repository für RHEL-/Fedora-/Debian-basierte Distros, das aktuelle Node-Major-Versionen als native Pakete bereitstellt, meist zeitnah zum Upstream-Release.

npm

Node Package Manager. Wird zusammen mit Node.js installiert. Legt Abhängigkeiten nach node_modules/ und schreibt sie nach package.json und package-lock.json. npm install installiert alles aus package.json, npm ci installiert reproduzierbar aus package-lock.json (der richtige Befehl für CI/CD).

npx

Package-Runner, mit Node/npm mitgeliefert. npx <tool> führt ein Paket aus, ohne es global zu installieren; nimmt die Version aus dem Projekt, wenn das Tool in node_modules/.bin/ liegt.

nvm

Node Version Manager. Per-User-Version-Switcher, der Node-Installationen nach ~/.nvm/versions/node/ legt. Auf Entwickler-Workstations sehr verbreitet, auf Produktions-Servern weniger, weil er an die Shell-Session des Users gebunden ist.

pnpm

Alternativer Paketmanager. Legt Pakete in einen content-addressierbaren Store und setzt per Hard-Link auf node_modules - spart Plattenplatz, ist oft schneller als npm, und erzwingt eine strengere Trennung der Abhängigkeiten (keine „Phantom-Deps“).

Yarn

Alternativer Paketmanager. Existiert in zwei Linien: Yarn Classic (1.x, seit Jahren „frozen“, nur noch vereinzelt Bugfixes) und Yarn Berry (2.x/3.x/4.x, komplette Neuimplementierung mit Plug’n’Play, Zero-Installs). Yarn Classic installiert man üblicherweise per RPM-Repo, Yarn Berry per Corepack pro Projekt.

Release-Zyklus

Node.js veröffentlicht alle sechs Monate eine neue Major-Version. Das Muster:

  • Gerade Majors (v20, v22, v24, v26 …) erscheinen im April. Sie werden im Oktober zu Active LTS und laufen 30 Monate: zwölf Monate aktiver Support, danach 18 Monate Maintenance.

  • Ungerade Majors (v21, v23, v25 …) erscheinen im Oktober. Sie bleiben Current-only und laufen aus, sobald die nächste gerade Version Active LTS wird. In Produktion eher nicht einsetzen.

Installationsvarianten

Welcher Installationsweg sinnvoll ist, entscheidet sich entlang zweier Achsen: Wie eng man sich an den OS-Lebenszyklus binden muss, und wie viele parallele Node-Versionen der Host benötigt.

Distributions-Pakete (RHEL 9)

Auf RHEL 9 liefert AppStream nodejs als DNF-Module-Stream. Verfügbar sind Stand 2026-04 die Streams nodejs:18, nodejs:20 und nodejs:22, jeweils mit den Profilen common (Default), development, minimal und s2i. RHEL 9 hat keinen Default-Stream vordefiniert, der gewünschte Stream muss explizit aktiviert werden. Das ist der Weg, den die LFOps-Rolle nodejs geht (Variable nodejs__dnf_module_stream):

dnf module list nodejs
dnf module --assumeyes enable nodejs:22
dnf module --assumeyes install nodejs:22/common

Für ein Wechsel auf einen anderen Stream muss der alte zuerst zurückgesetzt werden:

dnf module --assumeyes reset nodejs
dnf module --assumeyes enable nodejs:24
dnf distro-sync --assumeyes

Vorteil: Integration in den RHEL-Patch-Zyklus, Security-Updates kommen per dnf upgrade mit. Nachteil: Minor- und Patch-Versionen bleiben hinter dem Upstream-Release zurück; exakte Versionen wie „24.13.0“ sind mit Modulen in der Regel nicht erreichbar.

Distributions-Pakete (RHEL 10)

In RHEL 10 hat Red Hat Modularity eingestampft. nodejs kommt als gewöhnliches RPM, Default ist Node.js 22. Alternative Versionen liegen als versionsbehaftete Pakete vor (Muster wie bei postgresql16), zum Beispiel nodejs22, nodejs24:

dnf --assumeyes install nodejs
# bzw. eine spezifische Version aus den alternativen Streams:
dnf --assumeyes install nodejs24

dnf module-Kommandos funktionieren unter RHEL 10 für Node.js nicht mehr. Die Compatibility-Matrix in den Red-Hat-Release-Notes zeigt, welche nodejsNN-Varianten aktuell verfügbar sind.

NodeSource (aktuelle Versionen via Vendor-Repo)

Wer eine aktuellere Node-Version braucht, als die Distro bietet, und trotzdem beim RPM-Mechanismus bleiben will, nimmt das NodeSource-Repo. Seit 2023 läuft die Einrichtung über ein Setup-Skript, die alten nodesource-release-el$OS-RPMs sind abgeschaltet:

curl --fail --silent --show-error --location \
    https://rpm.nodesource.com/setup_24.x --output nodesource_setup.sh
bash nodesource_setup.sh
dnf --assumeyes install nodejs

Das Skript legt /etc/yum.repos.d/nodesource-nodejs.repo an, importiert den GPG-Key und setzt die Repo-Priorität. Für eine andere Major-Version setup_22.x, setup_24.x, setup_25.x aufrufen. Für RHEL 10 dokumentiert NodeSource aktuell keinen offiziellen Support; die RHEL-9-Pakete funktionieren in vielen Fällen, sind aber nicht offiziell getestet.

n (systemweite Versionsverwaltung)

n ist der passende Weg, wenn auf einem Host eine exakte Node-Version laufen soll, die nicht per Distribution oder NodeSource bereitsteht, und wenn mehrere Apps verschiedene Versionen brauchen. n installiert Node-Binaries nach /usr/local/n/versions/node/<version>/ und setzt Symlinks in /usr/local/bin/.

n selbst ist ein npm-Paket und braucht für die erste Installation ein beliebiges bereits vorhandenes node/npm. Danach übernimmt n die Versions-Verwaltung und die ursprüngliche Distro-Version darf wahlweise stehen bleiben oder wird später durch n überschrieben:

dnf --assumeyes install nodejs
npm install --global n

Gezielte Version installieren und aktivieren:

n 24.13.0              # installiert und aktiviert diese exakte Version
n lts                  # aktiviert die neueste LTS
n ls-remote --all      # listet verfügbare Versionen im Upstream
n ls                   # listet lokal installierte Versionen
n rm 22.11.0           # entfernt eine lokale Version

Vorteil: exakte Patch-Versionen, schneller Wechsel. Nachteil: Security-Updates kommen nicht mehr per dnf, die Versionen müssen bewusst gepflegt werden.

nvm (per-User-Versionsverwaltung)

nvm liegt im Home-Verzeichnis des Users (~/.nvm/) und wird per Shell-Funktion aktiviert. Auf Servern taugt das nur bedingt, weil Systemd-Units und Cron-Jobs die Shell-Funktion nicht sehen. Auf Entwickler-Workstations ist es der de-facto-Standard, um pro Projekt eine andere Node-Version zu fahren.

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
# neue Shell oeffnen
nvm install 24.13.0
nvm use 24.13.0
nvm alias default 24

Binary-Tarball (gesperrte Deployments)

Für Umgebungen, in denen jede Laufzeit-Version eingefroren wird (Regulatorik, Air-Gapped, Container-Base-Images), zieht man das fertige Tarball direkt von nodejs.org:

VER=24.13.0
curl --location --output node.tar.xz \
    https://nodejs.org/dist/v${VER}/node-v${VER}-linux-x64.tar.xz
tar --extract --file=node.tar.xz --directory=/opt
ln --symbolic --force /opt/node-v${VER}-linux-x64/bin/node /usr/local/bin/node
ln --symbolic --force /opt/node-v${VER}-linux-x64/bin/npm  /usr/local/bin/npm
ln --symbolic --force /opt/node-v${VER}-linux-x64/bin/npx  /usr/local/bin/npx

Entscheidungshilfe

Szenario

Empfehlung

Ein RHEL-9-Host, eine Node-App, LTS reicht

dnf module install nodejs:22 (bzw. LFOps-Rolle nodejs).

RHEL-10-Host, eine Node-App

dnf install nodejs (Base) bzw. nodejs24 für eine andere Major.

App braucht Node neuer als die Distro bietet

NodeSource-Setup-Skript für die gewünschte Major.

Exakte Patch-Version erforderlich (24.13.0)

n systemweit oder Binary-Tarball.

Mehrere Apps, verschiedene Versionen auf demselben Host

n mit Start-Skripten, die pro App die richtige Version aktivieren, oder je App einen eigenen Container.

Entwickler-Workstation

nvm per User.

Paketmanager

npm

Wird mit Node.js mitgeliefert. Die wichtigsten Kommandos:

npm install                     # installiert alles aus package.json, schreibt package-lock.json
npm ci                          # reproduzierbarer Install aus package-lock.json (CI/CD-Weg)
npm install --save <paket>      # Abhaengigkeit hinzufuegen
npm install --save-dev <paket>  # Dev-Abhaengigkeit hinzufuegen
npm install --global <paket>    # systemweit installieren (selten sinnvoll)
npm outdated                    # zeigt veraltete Pakete
npm audit                       # prueft auf bekannte Schwachstellen
npm update                      # aktualisiert auf die neueste passende Version gemaess package.json

npm ci ist der Befehl, der für Deployments und CI-Pipelines gehört: er löscht node_modules/, installiert exakt so, wie package-lock.json es sagt, und lehnt die Installation ab, wenn package.json und Lock-File auseinanderlaufen. npm install hingegen schreibt bei Bedarf package-lock.json um und ist für die lokale Entwicklung gedacht.

npx ist der zugehörige Runner. npx eslint . nimmt die projektlokale ESLint-Version aus node_modules/.bin/, wenn vorhanden, sonst lädt sie die Laufzeitversion temporär.

Yarn

Yarn existiert in zwei getrennten Linien, die sich in CLI und Konzepten unterscheiden.

Yarn Classic (1.x) wird per RPM-Repo installiert:

curl --output /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo
dnf --assumeyes install yarn
yarn --version       # 1.22.x

Classic ist seit Jahren „frozen“. Das Yarn-Projekt rät bei Bugs zur Migration auf Yarn Berry.

Yarn Berry (2.x, 3.x, 4.x) richtet man nicht mehr global ein, sondern pro Projekt über Corepack:

corepack enable
cd /path/to/project
yarn init -2                    # Projekt auf Berry umstellen
yarn set version stable         # konkrete Berry-Version waehlen

Corepack liegt Node.js seit v16.10 bei und liefert die Manager-Binary in der Version, die das Projekt verlangt (Feld packageManager in package.json). Wer Yarn Berry systemweit installiert, umgeht Corepack und riskiert Version-Mismatches zwischen Projekten.

pnpm

Alternative zu npm und Yarn. Legt Pakete in einen content-addressierbaren Store unter ~/.local/share/pnpm/store und verlinkt von dort in node_modules. Spart Plattenplatz (jedes Paket nur einmal auf der Platte, auch wenn hundert Projekte es verwenden), ist meist schneller als npm und verhindert durch strikten node_modules-Aufbau sogenannte Phantom-Dependencies.

corepack enable
corepack prepare pnpm@latest --activate
pnpm --version
pnpm install       # im Projekt

Szenario: Testserver auf Node 24.13.0 bringen

Der erste Schritt ist nie, irgendwo etwas zu installieren, sondern rauszufinden, was bereits läuft. which node zeigt den Pfad der aktuell in PATH aktiven Binary, node --version die Version, und rpm --query --whatprovides $(which node) klärt, ob das Binary aus einem RPM kommt oder aus einem Fremdwerkzeug:

which node
node --version
rpm --query --whatprovides "$(which node)" 2>/dev/null || echo "nicht aus einem RPM"
command -v n nvm

Damit lässt sich das Setup einer der folgenden Klassen zuordnen:

Kommt Node aus /usr/bin/node und einem RPM wie nodejs-22.x

Entweder RHEL-Module (RHEL 9) oder NodeSource. Die genaue Quelle verrät dnf repoquery --installed nodejs. Upgrade auf 24.x:

  • RHEL 9 mit Modul-Stream nodejs:22: dnf module reset nodejs; dnf module enable nodejs:24; dnf module install nodejs:24/common. Die exakte Patchlevel 24.13.0 gibt es dabei nur, wenn der Stream sie aktuell führt. Alternativ auf NodeSource oder n wechseln.

  • NodeSource: curl --fail --silent --show-error --location https://rpm.nodesource.com/setup_24.x -o setup.sh && bash setup.sh && dnf --assumeyes install nodejs. Der Setup-Skript-Schritt ersetzt das Repo-File auf Major 24.

  • RHEL 10: dnf --assumeyes install nodejs24 (wenn das Paket im AppStream geführt wird).

Kommt Node aus /usr/local/bin/node und zeigt /usr/local/n/versions/node/...

n verwaltet den Host. Upgrade ist ein Einzeiler: n 24.13.0. Danach node --version gegenprüfen und systemd-Units, Cron-Jobs und Shell-Start-Skripte kontrollieren, ob sie die Binary aus /usr/local/bin/node nehmen (typisch ja).

Kommt Node aus ~/.nvm/versions/node/...

nvm im User-Kontext. Upgrade nur für diesen User: nvm install 24.13.0, danach mit nvm alias default 24 als Default-Version festschreiben. Systemd-Units, die als anderer User laufen, sehen die Änderung nicht - dort den Node-Pfad explizit referenzieren oder einen anderen Verteilweg wählen.

Kommt Node aus /opt/node-v...

Binary-Tarball. Neues Tarball in /opt entpacken, die /usr/local/bin/node-Symlinks auf das neue Verzeichnis zeigen lassen, alten Ordner stehen lassen, bis der Dienst sauber läuft - im Problemfall Symlinks zurückschwenken und Re-Start.

In allen Varianten am Ende:

node --version
npm --version
systemctl restart <app>.service
journalctl --unit=<app>.service --since "2 min ago"

Wenn die App ihre Abhängigkeiten gegen eine bestimmte Node-Major gebaut hat, kann ein Wechsel der Major-Version native Module zum Neubau zwingen: rm -rf node_modules && npm ci im App-Verzeichnis reicht dafür in der Regel.

Troubleshooting

node weist auf eine andere Version als erwartet

PATH-Problem. Eine manuelle Installation (n, nvm, Tarball-Symlinks in /usr/local/bin/) hat Vorrang vor dem Distributions-Paket in /usr/bin/. type -a node zeigt alle Treffer in der Reihenfolge, in der die Shell sie findet.

Kein nodejs-Kommando, obwohl node da ist

Manche Apps rufen nodejs statt node auf (historischer Debian-Konflikt mit einem gleichnamigen Amateurfunk-Paket). Abhilfe: Symlink /usr/bin/nodejs/usr/bin/node setzen (legt die LFOps-Rolle nodejs ebenfalls an).

npm install schlägt mit gyp ERR! find Python fehl

Ein natives Addon soll aus Sourcen gebaut werden, es fehlen Build-Tools. Auf RHEL: dnf --assumeyes install gcc-c++ make python3.

Error: EACCES: permission denied bei npm install --global

npm --global will nach /usr/lib/node_modules/ oder /usr/local/lib/node_modules/ schreiben. Nicht mit sudo npm umgehen (führt zu Permissions-Chaos im Cache), sondern entweder in ein User-eigenes Prefix umlenken (npm config set prefix ~/.npm-global, PATH entsprechend anpassen) oder globale Tools per npx projektlokal laufen lassen.

engines-Warnung beim npm install: „unsupported engine“

Das Projekt verlangt eine andere Node-Major, als auf dem Host läuft. Entweder Node-Version anheben (siehe oben), oder - nur falls bewusst in Kauf genommen - per npm install --engine-strict=false umgehen.

Yarn-Kommando existiert nach corepack enable nicht

Corepack legt Shims in $(dirname $(which node)). Wird Node über n installiert, wandert das Verzeichnis beim Versionswechsel. corepack enable nach jedem n <version> neu ausführen oder im App-Deployment-Skript vorsehen.