API-Beschreibung
Das Panel hat keine offene Programmierschnittstelle für Benutzer. Es gibt zwei Schnittstellen für Maschinen: die Agent-API, über die angebundene Server mit dem Hub sprechen, und die DynDNS-Schnittstelle für Router und Skripte.
Grundlagen
- Transport: HTTPS,
POSTmit JSON-Body. Der Hub nutzt ein eigenes Zertifikat; der Agent prüft den Fingerabdruck (SHA-256) und nicht die Zertifikatskette. - Jede Anfrage ist mit dem Server-Schlüssel per HMAC-SHA-256 signiert, jede Antwort ebenfalls. Der Agent prüft die Antwort und verwirft sie bei falscher Signatur.
- Alle Pfade liegen unter
/agent/. Der Agent-Port (Standard 8444) liefert sonst nichts aus; jede andere Adresse antwortet mit 404. - Ohne gültige Signatur antwortet der Hub mit
401. Zu viele Fehlversuche einer IP führen zur Sperre.
Signatur
Der Schlüssel entsteht beim Anlegen des Servers im Panel und wird nur einmal angezeigt. Er wird als Text (UTF-8) verwendet, nicht als Hex-Folge. Jede Anfrage trägt vier Header:
| Header | Inhalt |
|---|---|
X-Agent | Servername |
X-TS | Unix-Zeit in Sekunden, höchstens 120 Sekunden Abweichung von der Zeit des Hubs |
X-Nonce | zufälliger Hex-Wert mit 16 bis 64 Zeichen, nur einmal gültig |
X-Sig | Signatur als Hex-Text mit 64 Zeichen |
Die Signatur wird über fünf Teile gebildet, die mit einem Zeilenumbruch verbunden werden:
X-Sig = HMAC_SHA256(schluessel, METHODE + "\n" + PFAD + "\n" + X-TS + "\n" + X-Nonce + "\n" + SHA256_HEX(body)) Antwort-Header X-Sig = HMAC_SHA256(schluessel, "resp\n" + X-Nonce + "\n" + SHA256_HEX(antwort_body))
Bei jedem Fehler antwortet der Hub gleich, damit niemand erfährt, welcher Teil nicht stimmte. Die Uhr des Servers sollte per NTP laufen.
Agent-Endpunkte
| Pfad | Zweck |
|---|---|
POST /agent/poll | Lebenszeichen und Aufträge abholen. Body: version, commands (Liste mit name, desc, level), info, wait (bis 25 s Wartezeit), optional results. Antwort: jobs (Liste mit id, cmd, args) und ts. |
POST /agent/result | Ergebnisse melden: results ist eine Liste mit id, ok und text. |
POST /agent/notify | Meldung an den Besitzer des Servers: text mit bis zu 500 Zeichen, höchstens 10 pro Minute. Antwort: {"ok":true}. |
POST /agent/track | Eine versendete Chat-Nachricht zum späteren automatischen Löschen vormerken (höchstens 60 pro Minute). Antwort: {"ok":true,"tracked":…}. Gilt nur, wenn der Agent denselben Bot wie das Panel nutzt. |
POST /agent/health | Lebenszeichen für den Hub-Wächter, der einen Hub-Ausfall meldet. Nur mit eingerichtetem Wächter-Schlüssel (Einstellungen → Matrix), sonst 404. |
POST /agent/dist | Neuere Agent-Version abrufen (Selbst-Update). |
GET /agent/enroll?t=TOKEN | Einmal-Abruf für die Erstinstallation (curl … | sudo bash). Liefert den Agent-Installer samt Zugangsdaten. Der Token stammt aus dem Panel (Server anlegen oder „Installationsbefehl“), gilt 30 Minuten und genau einmal. Ohne gültigen Token antwortet der Hub mit 404, auch wenn der Grund ein abgelaufener Token ist. Den Grund sieht nur das Hub-Protokoll. |
Befehlsstufen
Jeder Befehl, den ein Agent meldet, hat eine Stufe (level), nach der das Panel und der Bot entscheiden, wer ihn auslösen darf. Der Hub führt nie selbst Befehle aus, die der Agent nicht gemeldet hat.
Fehler und Grenzen
| Antwort | Bedeutung |
|---|---|
401 | Signatur, Zeitstempel oder Nonce ungültig, oder der Server ist unbekannt. |
404 | Pfad unbekannt oder ungültiger Token bei enroll. |
429 | Zu viele Anfragen: 120 pro Minute je IP, notify höchstens 10 pro Minute je Server. |
| Sperre | Nach 30 falschen Signaturen sperrt der Hub die IP für eine Weile. |
Befehle für einen Agenten, der nicht antwortet, verfallen nach 2 Minuten, Update-Aufträge nach 3,5 Stunden. Ein Server gilt nach 75 Sekunden ohne Kontakt als offline.
Beispiele
Rohe Anfrage
POST /agent/poll HTTP/1.1
X-Agent: games1
X-TS: 1760000000
X-Nonce: 3f9c1d2e4a5b6c7d8e9f0a1b2c3d4e5f
X-Sig: …
Content-Type: application/json
{"version":"1.0","commands":[{"name":"uptime","desc":"Laufzeit","level":"view"}],"info":{},"wait":20}Aufruf in Python
import hashlib, hmac, json, secrets, time, urllib.request
def call(hub, name, key, path, payload):
body = json.dumps(payload).encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
msg = "\n".join(["POST", path, ts, nonce, hashlib.sha256(body).hexdigest()])
sig = hmac.new(key.encode(), msg.encode(), hashlib.sha256).hexdigest()
rq = urllib.request.Request(hub + path, body, {"X-Agent": name, "X-TS": ts, "X-Nonce": nonce, "X-Sig": sig, "Content-Type": "application/json"})
return json.load(urllib.request.urlopen(rq, timeout=40))Signatur in der Shell
BODY='{"text":"Backup fertig"}'
TS=$(date +%s); NONCE=$(openssl rand -hex 16)
HASH=$(printf %s "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')
SIG=$(printf 'POST\n/agent/notify\n%s\n%s\n%s' "$TS" "$NONCE" "$HASH" | openssl dgst -sha256 -hmac "$KEY" -hex | awk '{print $NF}')
curl -s -H "X-Agent: games1" -H "X-TS: $TS" -H "X-Nonce: $NONCE" -H "X-Sig: $SIG" -d "$BODY" https://hub.example.de:8444/agent/notifyDen Agenten selbst zu schreiben ist nicht nötig: install-nbagent.sh richtet ihn ein. Eigene Befehle ergänzt du als Plugin-Datei in /opt/nbagent/plugins/, und Skripte melden mit nbagent.py notify "Text".
DynDNS-Schnittstelle
Die Schnittstelle folgt dem DynDNS2-Protokoll, das FritzBox und die meisten Router kennen. Sie liegt unter https://ddns.nodebay.de/nic/update (auch erreichbar als /ddns/update). Anmeldung per HTTP-Basic: Benutzername ist die Adresse, Passwort ist der Zugangsschlüssel aus dem Panel.
| Parameter | Bedeutung |
|---|---|
hostname | Vollständiger Name, z. B. name.nodebay.de. Fehlt er, gilt der Benutzername. |
myip (auch ip) | IPv4-Adresse. Fehlt sie, nimmt der Hub die Adresse, von der die Anfrage kommt. Eine IPv6-Adresse hier wird als IPv6 gewertet. |
myipv6 (auch ip6) | IPv6-Adresse. |
token, password | Schlüssel als Parameter, falls dein Gerät kein Basic kann. Besser Basic nutzen, da URLs oft in Protokollen landen. |
curl -u "name.nodebay.de:SCHLÜSSEL" "https://ddns.nodebay.de/nic/update?myip=203.0.113.7"
| Antwort | Bedeutung |
|---|---|
good IP | Eintrag geändert. |
nochg IP | Nichts zu tun, die Adresse war schon eingetragen. |
badauth (401) | Adresse unbekannt oder Schlüssel falsch. |
dnserr | Keine gültige IP übergeben oder der Eintrag ließ sich nicht schreiben (bei Schreibfehlern mit Status 500). |
notfqdn | Kein Name angegeben. |
abuse (429) | Mehr als 20 falsche Versuche von dieser IP. |
Aktualisiere nur, wenn sich die Adresse ändert. Der Hub antwortet bei unveränderter Adresse zwar mit nochg, zählt aber jede Anfrage.
Weitere Adressen
Das Panel selbst ist für Menschen gebaut und hat keine stabile JSON-Schnittstelle. Zwei Adressen liefern Dateien aus, brauchen aber eine angemeldete Sitzung:
| Adresse | Inhalt |
|---|---|
/invoice/ID.pdf | Rechnung als PDF (ZUGFeRD / Factur-X, mit eingebetteter XML). Nur für den Besteller und Administratoren. |
/invoice/ID.xml | Die Rechnungsdaten allein als CII-XML, Profil EN 16931. |
Die Gestaltung der PDF und die Felder der XML stehen im Handbuch.