08_PROTOCOL.md 5.0 KB

Protokoll v1

Überblick

Die Schnittstelle zwischen Client und Manage-Server. Wer den mitgelieferten Client verwendet, braucht dieses Dokument nicht – es ist für eigene Clients, für Debugging und für die Fehlersuche mit curl gedacht.

Basis-URL: <MANAGE_SERVER_URL>/api/v1/

Authentifizierung

Jede Anfrage trägt zwei Header:

X-Manage-Instance: meinprojekt-prod
X-Manage-Token:    e4032c4dc51e9100…

Der Server speichert nur den SHA-256-Hash des Tokens und vergleicht in konstanter Zeit. Es gibt keine Sitzung, kein Cookie und kein gemeinsames Passwort.

Fehlerantworten:

Status Bedeutung
401 Header fehlen, Instanz unbekannt oder Token falsch – bewusst nicht unterscheidbar
403 Instanz existiert, ist aber deaktiviert
405 Falsche HTTP-Methode
429 Zu viele fehlgeschlagene Authentifizierungen von dieser IP

Fehlgeschlagene Anmeldungen sind pro IP begrenzt, damit Instanz-Kennungen nicht durchprobiert werden können. Eine erfolgreiche Anmeldung setzt den Zähler zurück.

Alle Fehlerantworten haben denselben Aufbau:

{
    "success": false,
    "error": "Authentifizierung fehlgeschlagen."
}

GET manifest.php

Liefert das Release, das die Instanz installieren soll.

curl -s https://manage.example.org/api/v1/manifest.php \
  -H "X-Manage-Instance: meinprojekt-prod" \
  -H "X-Manage-Token: $TOKEN"
{
    "success": true,
    "latest": "v1.3.0",
    "version": "v1.3.0",
    "package_url": "https://manage.example.org/api/v1/package.php?version=v1.3.0",
    "sha256": "70f17aae44a9afdd948de1767daa61f936bbecb52096753757791e230a22f024",
    "size": 2199,
    "published_at": "2026-08-20T09:20:43+00:00"
}

404, wenn kein gültiges Release veröffentlicht ist.

package_url wird aus der Serverkonfiguration (MANAGE_PUBLIC_URL) gebildet, nicht aus dem Host-Header der Anfrage. Ein gefälschter Header kann einen Client daher nicht auf einen fremden Server umlenken.

GET package.php

Liefert das Release-ZIP.

curl -s -o release.zip \
  "https://manage.example.org/api/v1/package.php?version=v1.3.0" \
  -H "X-Manage-Instance: meinprojekt-prod" \
  -H "X-Manage-Token: $TOKEN"

Antwort: application/zip mit Content-Length und Cache-Control: private, no-store. Bei Erfolg kein JSON.

400 bei ungültigem Versionsformat, 404, wenn das Release nicht existiert.

Der Client vergleicht Größe und SHA-256 mit dem Manifest und löscht die Datei bei Abweichung. Ein eigener Client muss das ebenso tun – ohne diese Prüfung wird beliebiger Code ausgerollt.

POST backup.php

Nimmt ein Backup-Archiv entgegen. multipart/form-data:

Feld Pflicht Bedeutung
backup ja die ZIP-Datei
filename nein backup-YYYYmmdd-HHMMSS[-N].zip; ohne Angabe vergibt der Server einen Namen
sha256 nein Prüfsumme; wird serverseitig neu berechnet und verglichen
meta nein JSON mit trigger, file_count, source_bytes, app_version
curl -s https://manage.example.org/api/v1/backup.php \
  -H "X-Manage-Instance: meinprojekt-prod" \
  -H "X-Manage-Token: $TOKEN" \
  -F "filename=backup-20260820-092104.zip" \
  -F "sha256=824f3f80…" \
  -F 'meta={"trigger":"cron","file_count":3}' \
  -F "backup=@backup-20260820-092104.zip"
{
    "success": true,
    "instance": "meinprojekt-prod",
    "filename": "backup-20260820-092104.zip",
    "size": 427,
    "sha256": "824f3f80…",
    "retention": 30,
    "s3": { "enabled": false, "uploaded": false, "pending": 0 }
}

Der Server prüft in dieser Reihenfolge: Upload-Fehlercode, is_uploaded_file, Größenlimit, ZIP-Signatur, Dateinamensmuster, Prüfsumme nach dem Speichern. Weicht die Prüfsumme ab, wird die Datei wieder gelöscht und 400 gemeldet.

Ein vorhandener Dateiname wird nie überschrieben: Der Server hängt -2, -3 an.

Fehler beim S3-Archivieren lassen den Upload nicht fehlschlagen – die lokale Kopie ist gespeichert und wird später nachgezogen.

POST heartbeat.php

Statusmeldung. application/json:

{
    "version": "v1.3.0",
    "php_version": "8.3.6",
    "disk_free": 12884901888,
    "pending_migrations": 0,
    "last_backup_at": "2026-08-20T09:21:04+00:00"
}
{
    "success": true,
    "instance": "meinprojekt-prod",
    "latest": "v1.3.0",
    "update_available": false,
    "server_time": "2026-08-20T09:23:11+00:00"
}

Alle Felder der Anfrage sind optional; fehlende Felder lassen den bisherigen Wert auf dem Server unverändert. Die Antwort ersetzt für einfache Überwachung einen eigenen Aufruf von manifest.php.

Nebenwirkung jeder Anfrage

Jede erfolgreich authentifizierte Anfrage aktualisiert last_seen_at und die letzte IP der Instanz. Die Übersicht im Manage-Server bleibt dadurch aktuell, auch wenn nur Backups laufen und nie ein Heartbeat gesendet wird.

Weiter