Node-RED als OpenBSD-Dienst: Eine kleine Lektion in rc.subr-Interna
29.09.2026 3 Min. Lesezeit
Wer OpenBSD länger nutzt, kennt das Muster: Einen neuen Dienst installiert, ein minimalistisches rc.d-Skript geschrieben, rcctl start funktioniert scheinbar, aber rcctl check behauptet hartnäckig:
nodered(failed)
Genau das ist mir bei einer Node-RED-Installation auf OpenBSD 7.9 passiert. Der Weg zur Lösung war lehrreicher als erwartet und liefert einen interessanten Einblick in die Interna von rc.subr.
Ausgangslage
Das erste rc.d-Skript sah so aus:
#!/bin/ksh
daemon="/usr/local/bin/node-red"
daemon_user="_nodered"
daemon_flags="-u /home/_nodered/.node-red"
. /etc/rc.d/rc.subr
rc_bg=YES
rc_cmd $1
Der Start funktionierte:
# rcctl start nodered
nodered(ok)
Der Statuscheck jedoch nicht:
# rcctl check nodered
nodered(failed)
Erste Vermutung: Falscher Prozessname
Ein Blick auf die Prozessliste zeigte:
$ ps -ax -o pid,user,command | grep node
63240 _nodered node: node-red (node)
Interessant war, dass der laufende Prozess eben nicht als /usr/local/bin/node-red erschien, sondern als node: node-red.
Daher lag die Vermutung nahe, dass procname oder pexp angepasst werden müssten. Versuche wie:
procname="/usr/local/bin/node"
oder
pexp="node-red"
brachten jedoch keine Änderung.
Debugging mit rcctl -d
Der eigentliche Durchbruch kam durch:
# rcctl -d start nodered
Die Ausgabe endete mit:
doing _rc_wait_for_start
doing rc_check
...
Alarm clock
doing _rc_write_runfile
(timeout)
Das war die entscheidende Erkenntnis: Node-RED startete erfolgreich. Der Timeout entstand nicht beim Start selbst, sondern weil OpenBSD während der Wartephase nie einen erfolgreichen rc_check() erhielt.
Blick in die Quelle
Also wurde direkt in /etc/rc.d/rc.subr nachgesehen:
grep -n "rc_check()" /etc/rc.d/rc.subr
Das Ergebnis:
rc_check() {
pgrep -T "${daemon_rtable}" -q -xf "${pexp}"
}
Hier steckt die Lösung. OpenBSD verwendet intern pgrep -xf, also:
-f→ volle Kommandozeile-x→ exakte Übereinstimmung
Das bedeutet: pexp="node-red" funktioniert nur dann, wenn die gesamte Kommandozeile exakt node-red lautet.
Wie sieht Node-RED wirklich aus?
Ein paar Tests:
$ pgrep -fl node
902 node: node-red
$ ps -ww -p 902 -o command=
node: node-red (node)
Und schließlich:
$ pgrep -xf "node-red"
Kein Treffer. Aber:
$ pgrep -xf "node: node-red"
902
Treffer. Auch:
$ pgrep -xf "node.*node-red"
902
funktionierte. Damit war bewiesen, welche Zeichenkette rc.subr tatsächlich sehen musste.
Warum passiert das?
Node-RED wird zwar über /usr/local/bin/node-red gestartet. Intern setzt Node.js jedoch den sichtbaren Prozessnamen um zu node: node-red. Dadurch passt die tatsächliche Prozessbezeichnung nicht mehr zu dem Muster, das rc.subr ursprünglich aus
daemon="/usr/local/bin/node-red"
daemon_flags="-u ..."
erzeugt. Das führte zu folgender Kette:
- Node-RED startete.
- Das rc-Framework suchte nach dem Prozess.
- Die Suche scheiterte.
- Nach 30 Sekunden wurde der Timeout ausgelöst.
rcctl checkschlug dauerhaft fehl.
Die Lösung
Das fertige Skript:
#!/bin/ksh
daemon="/usr/local/bin/node-red"
daemon_user="_nodered"
daemon_flags="-u /home/_nodered/.node-red"
. /etc/rc.d/rc.subr
pexp="node: node-red"
rc_bg=YES
rc_cmd $1
Danach:
# rcctl start nodered
nodered(ok)
# rcctl check nodered
nodered(ok)
# rcctl restart nodered
nodered(ok)
Erkenntnisse
1. rcctl start bedeutet nicht automatisch, dass der Dienst erkannt wurde
Ein Dienst kann vollständig laufen und trotzdem später bei check oder restart scheitern.
2. rcctl -d ist Gold wert
Der Schalter
rcctl -d start <dienst>
zeigt sehr präzise, an welcher Stelle des Startvorgangs das Framework scheitert.
3. rc_check() verwendet pgrep -xf
Viele Administratoren gehen davon aus, dass ein pexp lediglich ein Suchbegriff sei. Tatsächlich muss das Muster bei OpenBSD häufig zur vollständigen Kommandozeile bzw. Prozessbezeichnung passen.
4. Ein Blick in rc.subr spart viel Rätselraten
OpenBSDs rc-Framework ist erfreulich transparent. Ein kurzes
grep -n rc_check /etc/rc.d/rc.subr
hat letztlich mehr zur Problemlösung beigetragen als jede Dokumentation.
Fazit
Das Problem lag weder an Node-RED noch an Node.js. Die eigentliche Ursache war die Kombination aus:
rc_bg=YES- der von Node.js veränderten Prozessbezeichnung
- und dem sehr strikt arbeitenden
pgrep -xfin rc.subr.
Sobald das Prozessmuster mit pexp="node: node-red" an die tatsächliche Realität angepasst wurde, funktionierte die Integration in OpenBSDs Service-Framework vollständig.
Eine schöne Erinnerung daran, dass OpenBSD-Probleme oft am schnellsten gelöst werden, wenn man einfach in die Quelle schaut.