5 Min. Lesezeit

Wie ich einmal mit Claude Code ein altes iPhone zum Server-Monitor gemacht habe

In der Schublade lag ein altes iPhone, auf dem Server lief Beszel. An einem Abend wurde daraus ein Dauer-Monitor für den Schreibtisch, in Bernstein auf Schwarz. Programmiert hat Claude Code, ich habe nur geredet. Ein Protokoll des Gesprächs.
Ich betreibe eine Handvoll Server, und seit einiger Zeit überwache ich sie mit Beszel. Das ist ein schlankes Monitoring mit einer hübschen Web-Oberfläche, bei mir unter einer eigenen Subdomain erreichbar, sagen wir health.example.org. Was mir fehlte, war ein Blick auf alle Server, ohne jedes Mal den Rechner aufzuklappen. In der Schublade lag ein altes iPhone, das für nichts mehr gut war. Genau das sollte zum Dauer-Monitor auf dem Schreibtisch werden.
Das Problem: Das Gerät läuft mit iOS 9. Moderne Web-Oberflächen wie die von Beszel funktionieren dort nicht mehr, HTTPS mit aktuellen Zertifikaten auch nicht. Also brauchte ich etwas Eigenes. Statt das selbst zu programmieren, habe ich es an einem Abend mit Claude Code gemacht und dabei fast nur geredet. Dieser Artikel ist ein Protokoll dieses Gesprächs.
Der Auftrag
Meine erste Nachricht war ein ziemlich ungeordneter Absatz. Sinngemäß:
Ich habe verschiedene Server, alle laufen in Beszel unter health.example.org. Nun möchte ich ein altes iPhone nutzen, um den Status abzurufen. Auf meinem Büroserver, einem Debian-System, soll ein einfacher HTTP-Server laufen, ohne HTTPS, nur im LAN, auf einem exotischen Port. Der soll die Beszel-API abfragen und alle paar Sekunden den Status aller Server anzeigen. Terminal-Bernstein-Optik, monospaced, schwarzer Hintergrund, tabellarisch mit System, CPU, Arbeitsspeicher, Festplatte, Systemlast, Netzwerk, Temperatur, Betriebszeit und Agent. Bitte in Rust.
Mehr Spezifikation gab es nicht. Claude hat zuerst selbständig nachgeschaut, wie die Beszel-API überhaupt aussieht, und sich dazu den Quellcode von Beszel auf GitHub angesehen. Dann kamen drei Rückfragen, alle als Auswahl mit einer empfohlenen Option:
  1. Wie kommt das Programm auf den Server? Direkt dort bauen, auf dem Mac cross-kompilieren oder nur den Quellcode liefern. Ich habe "auf dem Server bauen" genommen.
  2. Mit welchem Benutzer soll bei Beszel angefragt werden? Ein normaler Benutzer oder ein Superuser. Normaler Benutzer, am besten ein eigener mit Leserechten.
  3. Wie alt ist das iPhone? Diese Frage fand ich klug, denn sie entscheidet darüber, ob die Seite JavaScript benutzen darf. Bei iOS 9 lautete die Antwort: lieber nicht. Die Seite lädt sich seitdem per klassischem Meta-Refresh alle fünf Sekunden neu, wie 1998.
Dann kam noch eine vierte Frage, die ich nicht erwartet hatte: Neun Spalten passen in Monospace nicht nebeneinander auf 320 Pixel Breite. Claude schlug vor, pro Server zwei Zeilen zu verwenden. Das habe ich genommen.
Anschließend bekam ich einen Plan zum Absegnen. Ich habe ihn überflogen, er klang vernünftig, ich habe auf "Ja" geklickt. Was danach im Hintergrund passierte, habe ich nicht verfolgt. Nach ein paar Minuten gab es ein fertiges Projekt, Tests, ein Installationsskript und eine README. Die erste Version sah so aus, noch mit deutschen Spaltenköpfen und ohne Zugangsdaten:
Deployment: "wie bekomme ich das nun auf den Büroserver?"
Genau so habe ich die nächste Frage gestellt, mit dem Hostnamen und der LAN-Adresse des Servers. Claude hat sich per SSH verbunden, festgestellt, dass Rust dort schon installiert war, das Projekt kopiert, gebaut, einen Systembenutzer angelegt und den Dienst in systemd eingerichtet. Dann hat es den Dienst testweise gestartet, gesehen, dass der Login am Hub mit Platzhalter-Daten erwartungsgemäß scheitert, und mir gesagt, was ich selbst tun muss.
Das war auch der einzige Moment, in dem ich tatsächlich etwas eintippen musste. Claude hat das Passwort ausdrücklich nicht selbst eingetragen, sondern mir die Datei genannt:
ssh -t bueroserver sudo nano /etc/beszel-simple-http.env

E-Mail und Passwort eintragen, speichern, und den Dienst neu starten:
ssh bueroserver 'sudo systemctl restart beszel-simple-http'

Das war es. Im iPhone-Safari die LAN-Adresse mit Port eingeben, und die Seite lief. So sieht sie heute im Querformat aus, mit Beispieldaten:
Feinschliff am iPhone, Nachricht für Nachricht
Ab hier wurde es ein Gespräch, wie man es mit einem Kollegen führt, der nebenan sitzt und die Sachen sofort einbaut. Jede Änderung wurde getestet, eingecheckt und auf den Server gespielt, ohne dass ich darum bitten musste.
"Bei jedem Reload wird die URL-Leiste und unten die Buttonleiste angezeigt." Auch nachdem ich die Seite zum Home-Screen hinzugefügt hatte. Die Antwort: Safari blendet seine Leisten nur bei Seiten aus, die sich per Meta-Tag als Web-App deklarieren. Drei Zeilen im HTML, dann das Icon einmal löschen und neu anlegen. Seitdem läuft die Seite im Vollbild.
"Ja, mach bitte ein Bernstein-Icon." Claude hat ein kleines PNG erzeugt, schwarz mit drei Bernstein-Zeilen, passend zur Tabelle, und es direkt mit ausgeliefert.
Spaltenköpfe umbenennen, Agent-Spalte raus, größere Schrift. Aus "Arbeitsspeicher" wurde "Ram", aus "Festplatte" "HD", aus "Temperatur" "C°". Ich betreibe das Gerät im Querformat, da war Platz für größere Schrift. Später habe ich sie dann doch wieder etwas kleiner gewünscht, zweimal hintereinander mit konkreten Pixelwerten. Beides war in unter einer Minute live.
"Wann immer ein Wert 80 % oder höher erreicht, soll die gesamte Zeile orange sein." Und natürlich auch, wenn ein Rechner sich nicht mehr meldet. Eingebaut, mit Screenshot als Beleg.
"Würde es auch gehen, dass die roten Werte blinken?" Ja, per CSS-Animation, die auch das alte Safari kann. Seitdem blinken Alarme im Sekundentakt, hart und ohne Überblendung, wie ein Terminal-Cursor.
Der Test: Agent abschalten
Ob die Alarmanzeige wirklich funktioniert, wollte ich mit echten Daten sehen. Also: "Schalte den Beszel-Agent auf dem Büroserver mal für 20 Sekunden ab." Claude hat das gemacht und dabei die Statusseite beobachtet. Ergebnis: nichts. Der Hub braucht länger als 20 Sekunden, um einen Server als ausgefallen zu markieren. Das hat Claude auch so erklärt, statt mir ein Ergebnis vorzuspielen.
Zweiter Versuch mit drei Minuten. Diesmal sprang die Zeile nach 15 Sekunden auf das rote Kreuz, alle Werte wurden zu Strichen, die Zeile blinkte orange. Nach dem Neustart des Agents war der Server innerhalb einer Viertelminute wieder grün, pardon, bernstein. Ich bekam das als kleine Tabelle mit Zeitstempeln zurück.
Was nicht ging
Zum Schluss wollte ich noch die iOS-Statusleiste loswerden, also Uhrzeit, WLAN-Symbol, Akku und das ewige "SIM fehlt". Die ehrliche Antwort: Das geht bei einer Web-App nicht, das ist Sache des Betriebssystems. Als Annäherung gibt es eine durchscheinende Variante, bei der die Symbole direkt auf dem schwarzen Hintergrund liegen. Ich habe sie ausprobiert, fand sie nicht besser, und eine Nachricht später war sie wieder zurückgebaut.
Fazit
Ich habe an diesem Abend keine Zeile Rust gelesen. Ich habe auch nichts kompiliert, nichts kopiert und keinen Dienst eingerichtet. Ich habe beschrieben, was ich will, vier Fragen beantwortet, einmal ein Passwort in eine Datei geschrieben und danach Wünsche geäußert, wie man sie einem Kollegen zuruft.
Drei Dinge haben mir dabei besonders gefallen:
  • Die Rückfragen waren wenige, aber die richtigen. Das Alter des iPhones zu erfragen, bevor eine Zeile Code entstand, hat die ganze Richtung bestimmt.
  • Grenzen wurden klar benannt. Das Passwort wollte Claude nicht selbst eintragen. Die Statusleiste ließ sich nicht abschalten, und das wurde gesagt, statt irgendetwas zu versuchen. Der 20-Sekunden-Test brachte kein Ergebnis, und auch das wurde so berichtet.
  • Jede Änderung war sofort live. Testen, einchecken, auf den Server spielen, prüfen. Ich habe mich um nichts davon gekümmert.
Das iPhone liegt jetzt im Querformat auf dem Schreibtisch, in Bernstein auf Schwarz, und zeigt mir alle fünf Sekunden, ob meine Server noch leben. Falls einer das nicht mehr tut, blinkt es.

Alle Artikel

Rufen Sie einfach an.

Ein unverbindliches Erstgespräch reicht, um zu klären, ob und wie ich Ihnen helfen kann. Kein Formular, kein Verkaufsdruck.

Oder per E-Mail an rene.fuerstenberg@gmail.com

Ich rufe zurück, wenn ich gerade im Termin bin.