Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

Was fehlt?

Es liegt in der Natur der Sache: Ein Wiki ist niemals fertig. Wir geben uns große Mühe, mit der Entwicklung Schritt zu halten; lassen Supportanfragen direkt in neue Artikel einfließen … aber auch wir sind nicht perfekt. Wenn du hier nicht fündig wirst: Nicht schmollen - Bescheid sagen! Unter hallo@uberspace.de steht dir unser Team gerne bereit. Hand drauf!

development:nodejs

node.js

Wir bieten auf unseren System auch node.js als serverbasierten JavaScript-Interpreter an. Mit node.js lassen sich serverbasierte Dienste entwickeln, d.h. die darunter laufenden Scripts binden sich typischerweise an einen Netzwerkport, statt wie andere Programmiersprachen unter CGI oder FastCGI zu laufen. Das macht ihre Einbindung etwas schwieriger, aber natürlich ist auch das bei Uberspace.de kein Problem.

node.js-Projekte gehören nicht in den DocumentRoot sondern in dein Home-Verzeichnis!

Versionen

Je nachdem auf welchem Host du dich befindest, stehen dir mehrere node.js-Versionen zur Verfügung, da wir bei Updates die vorherigen Versionen parallel dazu immer noch installiert lassen. Welche Version die Standardversion ist, erfährst du durch Eingabe von node -v:

[mareike@neon ~]$ node -v
v0.10.41

Verwendest du einfach nur node, so steht dahinter jeweils die Default-Version. Du kannst eine bestimmte von dir festgelegte node.js-Version als Standard verwenden, in dem du die Umgebungsvariable PATH über eine Zeile in deiner .bash_profile anpasst. Der source-Aufruf stellt sicher, dass die neue Version auch direkt in deiner laufenden Shell zur Anwendung kommt. Um herauszufinden, welche Versionen auf dem Host vorhanden sind, kannst du wie folgt vorgehen:

[mareike@neon ~]# ls -ld /package/host/localhost/nodejs-*
lrwxrwxrwx 1 root        root          35 Oct 13 14:55 /package/host/localhost/nodejs -> /package/host/localhost/nodejs-0.10
lrwxrwxrwx 1 root        root          38 Dec  4 16:11 /package/host/localhost/nodejs-0.10 -> /package/host/localhost/nodejs-0.10.41
drwxr-xr-x 6 packagesync packagesync 4096 Dec  4 16:02 /package/host/localhost/nodejs-0.10.41
lrwxrwxrwx 1 root        root          36 Dec  4 17:44 /package/host/localhost/nodejs-4 -> /package/host/localhost/nodejs-4.2.3
drwxr-xr-x 6 packagesync packagesync 4096 Dec  4 17:28 /package/host/localhost/nodejs-4.2.3
lrwxrwxrwx 1 root        root          36 Dec  4 17:44 /package/host/localhost/nodejs-5 -> /package/host/localhost/nodejs-5.1.1
drwxr-xr-x 6 packagesync packagesync 4096 Dec  4 16:02 /package/host/localhost/nodejs-5.1.1

Um dann z.B. Version 4 einzustellen, reichen die folgenden Befehle aus:

[mareike@neon ~] echo 'export PATH=/package/host/localhost/nodejs-4/bin:$PATH' >> ~/.bash_profile
[mareike@neon ~] source ~/.bash_profile

Zur Kontrolle kannst du einmal node -v aufrufen, was nun die Version v4.2.3 ergeben sollte:

[mareike@neon ~]$ node -v
v4.2.3

Einrichtung als Dienst

Damit der Serverdienst gestartet wird und auch noch weiterlaufen kann, nachdem du dich bereits wieder ausgeloggt hast, kannst du ihn am einfachsten unter den daemontools laufen lassen, die nicht nur für den automatischen Start nach einem Reboot des Servers sorgen, sondern deine Applikation auch automatisch neu starten, sollte sie aus irgendeinem Grund mal crashen. Solltest du noch kein eigenes ~/service-Verzeichnis haben, kannst du dir flugs eins anlegen:

[mareike@neon ~] test -d ~/service || uberspace-setup-svscan

Wenige Sekunden später ist dein ~/service-Verzeichnis einsatzbereit. Jetzt ist deine Applikation an der Reihe - so geht's:

[mareike@neon ~] uberspace-setup-service exampleservice node ~/example.js

Damit wird automatisch ein Dienst namens exampleservice in deinem ~/service-Verzeichnis angelegt, der deine node.js-Applikation startet. Du kannst ihn wie jeden anderen Dienst auch beliebig steuern.

Solltest Deine Node-Applikation mal in Konflikt mit unserem Prozesskiller kommen, kannst Du versuchen dem beizukommen, indem Du node mit –max-old-space-size=512 mitgibst, um die Speicherbereinigung früher einsetzen zu lassen. In Deinem run-Skript müsste dann so aussehen: exec node –max-old-space-size=512 ~/example.js

Brücke zum Webserver

Was nun noch fehlt, ist die Brücke zum Webserver zu deinem Dienst. Das lässt sich am einfachsten mit einer .htaccess-Datei regeln. Legen wir als Beispiel eine einfache .htaccess-Datei im DocumentRoot an:

[mareike@neon html]$ cat .htaccess
RewriteEngine On
RewriteRule ^nodejs/(.*) http://localhost:61000/$1 [P]

Jetzt werden sämtliche Aufrufe von - in diesem Beispiel - https://mareike.neon.uberspace.de/nodejs/… durch den Apache via Proxy an deinen node.js-Dienst durchgeleitet. Das war's!

(Bitte beachte den „/“ hinter dem Pfad in der URL - ohne den matcht die RewriteRule nicht, so dass der Request dann nicht durchgereicht wird.)

Weitere Hinweise zu den RewriteRules mit Proxy findest du hier.

HTTPS erzwingen

Im Support stoßen wir immer mal wieder darauf, dass es Probleme mit dem Erzwingen von HTTPS in Verbindung mit der Proxy-Anweisung in der .htaccess gibt. Das basiert auf einem Missverständnis, die Proxy-Anweisung [P] wirkt nämlich gleichzeitig noch wie ein [L], alle nachfolgenden Anweisungen in der .htaccess werden dann ignoriert. Die Reihenfolge ist also ausschlaggebend:

[mareike@neon html]$ cat .htaccess
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteCond %{ENV:HTTPS} !=on
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule ^nodejs/(.*) http://localhost:61000/$1 [P]

WebSockets

Es gibt einen Punkt, an dem die Proxy-RewriteRule aus dem vorherigen Abschnitt nicht funktioniert, nämlich dann, wenn zusätzlich zur normalen HTTP-Kommunikation auch WebSockets zum Einsatz kommen. Auch wenn es im ersten Moment so aussieht, als wären WebSockets auch „irgendwie HTTP“, so benutzen sie lediglich HTTP mit einem zusätzlichen Header als Handshake, führen danach aber Kommunikation, die nichts mehr mit HTTP zu tun hat und die in aller Regel auch nicht durch einen Proxy kommen.

In diesem Fall hilft nur eine Möglichkeit: Wir müssen dir dann einen eigenen TCP-Port oberhalb von Port 61000 freischalten. Das kannst du dem Script uberspace-add-port erledigen. Auf diese Weise kannst du dann vom Browser aus direkt (unter Umgehung des Apache-Webservers) mit deiner Node-Instanz kommunizieren - und so funktionieren WebSockets dann auch.

npm

npm ist der „Node Package Manager“. Er ermöglicht die einfache Installation von zusätzlichen Modulen für node.js. Um ihn nutzen zu können, solltest du eine eigene .npmrc anlegen, die wie folgt aussieht:

[mareike@neon ~]$ cat > ~/.npmrc <<__EOF__
prefix = $HOME
umask = 077
__EOF__

Der angegebene prefix ist das Basisverzeichnis, wenn du mit npm -g Module global installieren willst. Die zweite Zeile sorgt dafür, dass npm alle Dateien und Verzeichnisse nur für dich selbst les- und schreibbar anlegt. Das ist wichtig, damit npm, wenn du ein npm install … irrtümlich direkt in deinem Home-Verzeichnis (und nicht im Verzeichnis deiner Applikation) ausführst, nicht dein Home-Verzeichnis mit einem ''chmod 755'' behandelt und es somit für andere lesbar macht.

Bei einigen Versionen vor 1.4.17 wird bei globalen Installationen anscheinend die prefix-Variable ignoriert. Als Workaround wird in dem Bugreport empfohlen, den prefix bei der Installation von npm-Modulen mit anzugeben, z.B. mit…
npm install -g --prefix=$HOME <modulname>

Probleme mit tar

Wenn du auf einem Host liegst, der noch mit CentOS 5 als Distribution arbeitet, kann es sein, dass die Installation einiger beliebter Module wie zum Beispiel socket.io oder express.js mit Fehlern fehlschlägt, die darauf zurückzuführen sind, dass die von uns zentral bereitgestellte Version von tar nicht aktuell genug ist - wobei wir jene aber aufgrund des von unserer Linux-Distribution umgesetzten Backporting-Prinzips auch nicht einfach global aktualisieren können, ohne dass es dabei möglicherweise an anderer, unerwarteter Stelle zu Problemen kommen könnte. Du kannst dir aber einfach selbst ein frischeres tar in deinem Uberspace installieren - das braucht nur einen Befehl und eine Minute Zeit:

[mareike@neon ~]$ toast arm tar

Anschließend ist auch die zuvor fehlgeschlagene Installation der npm-Pakete problemlos möglich. In unserem Artikel zu toast findest du detailliertere Dokumentation für dieses Anwendungsbeispiel von toast.

Auf Hosts, die mit CentOS 6 als Distribution arbeiten, ist die zentrale tar-Version frisch genug; hier sind keinerlei Klimmzüge nötig.

lokal vs. global

Standardmäßig installiert npm Module immer im Unterverzeichnis node_modules im Startverzeichnis deiner Applikation (oder im aktuellen Verzeichnis, wenn es nicht herausfinden kann, was das Startverzeichnis deiner Applikation ist), und ggf. zugehörige Binaries in node_modules/.bin, wo sie außerhalb der Umgebungsvariable $PATH liegen. Das ist das, was mit „lokaler“ Installation gemeint ist: Nicht „lokal auf deinem Uberspace“, sondern „lokal im Applikationsverzeichnis“. Der Begriff „global“ meint demgegenüber hier nicht „systemweit“, sondern eher soviel wie „global für alle Applikationen, die du auf deinem Uberspace hast“.

Applikationen suchen, wenn du ein Modul mittels require('…') lädst, im applikationsspezifischen node_modules-Verzeichnis (das ist ein Feature von Node selbst, nicht von npm).

Benötigst du Module in mehreren Node-Applikationen, so gibt es zwei Möglichkeiten: Zunächst solltest du npm help link aufrufen und dich mit dem Symlink-Mechanismus vertraut machen, den Node für diese Fälle vorsieht. Trifft das nicht deinen Geschmack, so hast du die Möglichkeit, Module global auf deinem Uberspace zu installieren - mach dich hierzu bitte mit der FAQ vertraut, insbesondere mit den Abschnitten „How do I install something everywhere?“ und „No, I really want 0.x style 'everything's global' style.“ - auch wenn das ausdrücklich nicht empfohlen wird.

Detailliertere Informationen zu diesem Thema findest du in den Blogposts npm 1.0: Global vs Local installation und npm 1.0: link des npm-Autors.

Beispiel

Installieren wir doch mal exemplarisch den äußerst empfehlenswerten node-supervisor, und da dieser ein auszuführendes Script mitliefert, ist es eine äußerst gute Idee, ihn mittels -g global zu installieren:

[mareike@neon ~]$ npm install supervisor -g
/home/mareike/bin/node-supervisor -> /home/mareike/lib/node_modules/supervisor/lib/cli-wrapper.js
/home/mareike/bin/supervisor -> /home/mareike/lib/node_modules/supervisor/lib/cli-wrapper.js
supervisor@0.1.2 /home/mareike/lib/node_modules/supervisor

Nutzung mit den daemontools

Möchtest du einen Service anlegen, der zusätzlich den node-supervisor benutzt und somit deinen Code automatisch neu startet, wenn er sich ändert? Nichts leichter als das:

[mareike@neon ~] uberspace-setup-service exampleservice node-supervisor -w ~/example.js ~/example.js

Problemfälle

sqlite3

Bei einem npm install sqlite3 —build-from-source versucht das Installationsscript dieses Moduls zunächst, eine fertig kompilierte binäre Version des Moduls herunterzuladen. Ärgerlicherweise legt es jenes nicht in einem für diesen Zweck generierten temporären Verzeichnis ab, sondern immer im Verzeichnis /tmp/node-sqlite3-Release. Das funktioniert auch, bringt auf Multi-User-Systemen wie Uberspace.de aber ein Problem mit sich: Der erste User, der dies tut, „gewinnt“ - und alle anderen scheitern dann an dieser Stelle, weil deren npm versucht, das Binary ebenfalls an genau diese Stelle zu schreiben, was nun aber nicht geht, weil's das Verzeichnis ja schon gibt - und es einem anderen User gehört. So sieht das dann aus:

[sqlite3]: Checking for http://node-sqlite3.s3.amazonaws.com/Release/node_sqlite3-v2.1.a-v8-3.14-linux-x64.tar.gz
[sqlite3]: Error: EACCES, open '/tmp/node-sqlite3-Release/node_sqlite3-v2.1.a-v8-3.14-linux-x64.tar.gz'

Glücklicherweise ist der Einsatz von /tmp aber nicht hart kodiert, sondern die Umgebungsvariable $TMPDIR wird honoriert. Du solltest sie insofern vor dem npm install sqlite3 \–build-from-source auf ein Verzeichnis setzen, das explizit für dich angelegt wird und dann auch dir gehört:

export TMPDIR=`mktemp -d /tmp/XXXXXX`

Die vielen „X“e sind genau so richtig; mktemp interpretiert sie als Platzhalter für einen Zufallswert und liefert jenen dann zurück, so dass die Variable $TMPDIR anschließend direkt auf jenes frisch angelegte Verzeichnis verweist.

Befindest du dich auf einem Host, der noch mit CentOS 5 läuft? In diesem Fall ist die Default-Version von Python - Version 2.4 - zu alt für den Kompilierungsprozess von sqlite3. Du musst in diesem Fall zuvor noch ausführen:

export PYTHON=python2.7

Auf Hosts, die mit CentOS 6 laufen, ist dieser Schritt nicht nötig; die Default-Version von Python - Version 2.6 - ist hier aktuell genug.

Nun kannst du npm install sqlite3 ausführen.

Nutzung von MongooseJS

Ubernaut Hannes hat ein Tutorial für die Nutzung von MongooseJS und die damit verbundenen Fallstricke geschrieben, vielen Dank dafür! Kurz zusammengefasst:

Mongoose.js ist eine Erweiterung für Node.js, um die MongoDB-Datenbankanbindung und -nutzung für Entwickler noch einfacher zu gestalten. Mongoose verbindet sich zur MongoDB anhand eines Connection-Strings. Dieser muss folgendermaßen angepasst werden:

var mongoose = require("mongoose");
mongoose.connect('mongodb://user:pass@host:27017/db?authSource=databaseName')

Den Usernamen, das Passwort und den Port habt ihr während der Einrichtung erhalten, den Namen der Datenbank, zu der sich Mongoose verbindet, könnt ihr frei wählen.

Mehr Informationen

Felix Geisendörfer hat einen hilfreichen Node.js Guide verfasst, der dir hilft, schnell in die Details von Node.js vorzudringen (inklusive "Convincing the Boss"-Guide!).

development/nodejs.txt · Zuletzt geändert: 2016/09/16 07:02 von uber