Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shared-hosting-deploy-kit

Deployment auf Shared-PHP-Hosting ohne SSH, ohne curl, ohne exec, ohne Composer. Pfad-isolierte Schreib-API mit SHA-256-Optimistic-Locking, Single-File-Snapshots, content-adressierter Deduplikation und Ein-Klick-Rollback.

Lizenz: MIT PHP 7.4+ Keine Abhängigkeiten


Status

v0.1.0. Im produktiven Einsatz unter netzhandwerker.de seit April 2026. Verarbeitet rund 500 Deploys pro Woche aus einer Mischung aus menschlichen Commits, agent-getriebenen Edits und geplanten Batch-Syncs. Spitzen-Speicher: 0,6 MB. Bisher kein Datenverlust.

Für regulierte Produktion (Behörden, Gesundheit) ohne eigene Sicherheitsprüfung nicht empfohlen.

Was funktioniert

  • Single-File-PHP-Gateway, in jeden Webroot droppbar
  • Pfad-Traversal-Schutz: validate_path() blockiert .., ., Null-Bytes, gefährliche Endungen (.phar, .phtml, .php[3-7])
  • Endungs-Whitelist: konfigurierbare Liste schreibbarer Endungen, alles andere wird abgewiesen
  • Optimistic Locking via If-Match: <sha256>-Header — Write bricht mit 409 Conflict ab, wenn die Datei sich geändert hat
  • Snapshots bei jedem Write, Rollback per Snapshot-ID
  • Content-adressierte Deduplikation: gleiche Dateien über mehrere Snapshots werden einmal gespeichert (SHA-256-keyed)
  • Rate-Limiting: global (30/min) + pro IP (10/min), file-basiert, kein Redis nötig
  • Audit-Log: append-only mit Zeitstempel, Key-Fingerprint, IP, Pfad, Byte-Anzahl
  • Atomare Batch-Deploys: deploy_batch schreibt N Dateien unter einem Snapshot
  • Memory-Decke: streamt Dateien via copy(), Peak-Memory unter 1 MB selbst bei vollen Site-Snapshots
  • Binary-Upload-Helfer: separater bin-upload.php für Dateien über 800 KB (umgeht ARG_MAX und POST-Size-Limits)

Bekannte Grenzen

  • API-Key hat vollen Schreibzugriff auf das Deploy-Verzeichnis — wie ein SSH-Key behandeln
  • Kein Multi-Tenant-Setup: ein Key, ein Webroot
  • Snapshots werden nach max_snaps Stück automatisch verworfen (Standard: 20)
  • Rate-Limit-State liegt im Filesystem — bei sehr hoher Last (>100 req/s) wird das eng
  • Kein OAuth, kein User-Management — Authentifizierung ist API-Key-only
  • Keine Audit-Log-Rotation eingebaut, manuelles Trimmen nötig
  • Kein eingebautes Backup der Snapshots — falls Hoster die Webroot verliert, sind auch Snapshots weg

Wofür es da ist

Die meisten „Deploy zu Shared Hosting"-Tools setzen voraus:

  • SSH-Zugang
  • git auf dem Server
  • composer installiert
  • Funktionierendes curl / openssl / shell_exec

Günstige deutsche und EU-Shared-Hoster (All-Inkl, Strato, IONOS, df.eu, host.de) deaktivieren das typisch alles. Was bleibt: FTP, ein Webroot, PHP 8.x mit minimalem Extension-Set — das war's.

Dieses Kit deployt in genau diese Umgebung. Das Gateway ist eine einzelne PHP-Datei, die in den Webroot gelegt wird. Ab dann kann jeder Client (Python, Node, Bash, GitHub Actions, ein KI-Agent) Dateien per HTTPS lesen, schreiben, auflisten und zurückrollen — ohne Shell, ohne FTP, ohne git.

Was das Kit NICHT ist

  • Keine CI/CD-Plattform. Es ist die Plumbing darunter.
  • Keine Datei-Manager-UI. Nur API.
  • Kein Ersatz für git. Es ergänzt git: Push zu git → CI ruft diese API → Dateien landen.
  • Kein Zero-Trust. Der API-Key hat vollen Schreibzugriff. Wie SSH-Key behandeln.

Schnellstart

1. Gateway in den Webroot legen

scp src/deploy-gateway.php dein-host:~/public_html/

Oder per FTP hochladen. Das ist die komplette Server-Installation.

2. API-Key konfigurieren

deploy-gateway.php editieren und $API_KEY auf eine lange Zufalls-Zeichenkette setzen, oder eine Geschwister-Datei gateway.config.php anlegen:

<?php
return [
    'api_key'   => 'hier-32-zufalls-bytes',
    'base_path' => __DIR__,           // Wurzel des Deploy-Jails
    'snap_dir'  => __DIR__ . '/_snapshots',
    'max_snaps' => 20,
];

3. Verifizieren, dass es läuft

curl -X POST https://example.com/deploy-gateway.php \
     -d "key=YOUR_KEY" \
     -d "action=ping"

Erwartete Antwort:

{"status":"ok","version":3,"snapshots":0,"memory_peak_mb":0.5}

4. Datei deployen

curl -X POST https://example.com/deploy-gateway.php \
     -d "key=YOUR_KEY" \
     -d "action=write" \
     -d "path=index.html" \
     --data-urlencode "content@./local-index.html"

5. Lesen, editieren, schreiben mit Optimistic Locking

# examples/python_client.py
from deploy_client import Gateway
gw = Gateway("https://example.com/deploy-gateway.php", api_key="...")

current = gw.read("index.html")
new_content = current["content"].replace("alt", "neu")
gw.write("index.html", new_content, if_match=current["sha256"])
# Wirft ConflictError, wenn die Datei zwischen Read und Write geändert wurde

API-Überblick

Action Methode Zweck
ping POST Health-Check, Snapshot-Anzahl, Memory-Stats
read POST Datei-Inhalt + SHA-256 + mtime lesen
list POST Verzeichnis listen (rekursiv optional)
write / deploy POST Datei schreiben (optional mit If-Match)
write_b64 POST Base64-codierte Binär-Datei schreiben
deploy_batch POST N Dateien atomar unter einem Snapshot schreiben
delete POST Datei löschen (Snapshot wird vorher erstellt)
snapshot POST Manuell Voll-Site-Snapshot erstellen
snapshots POST Alle Snapshots auflisten
rollback POST Snapshot per ID wiederherstellen

Vollständige Referenz: docs/api.md

Architektur

                            HTTPS POST
   ┌─────────────┐         (form-encoded)         ┌──────────────────────┐
   │   Client    │ ─────────────────────────────▶ │  deploy-gateway.php  │
   │ (beliebig)  │                                │  (Webroot)           │
   └─────────────┘ ◀───────  JSON-Antwort  ────── └──────────┬───────────┘
                                                              │
                                                              │ write/read/copy
                                                              ▼
   ┌──────────────────────────────────────────────────────────────────┐
   │                   Webroot (pfad-isoliert)                        │
   │  ├── index.html                                                   │
   │  ├── style.css                                                    │
   │  └── _snapshots/                                                  │
   │      ├── snap_20260519_104530/                                    │
   │      │   └── manifest.json   ← {Pfad → SHA-256}                   │
   │      ├── snap_20260519_104612/                                    │
   │      │   └── manifest.json                                        │
   │      └── _objects/           ← content-adressierter Speicher     │
   │          ├── 1a/2b3c4d...    ← per SHA-256 dedupliziert           │
   │          └── ef/01234567...                                       │
   └──────────────────────────────────────────────────────────────────┘

Ein Snapshot ist nur ein JSON-Manifest, das relative Pfade auf SHA-256-Hashes mappt. Die eigentlichen Datei-Blobs liegen einmal in _objects/. Wenn 50 Snapshots dieselbe style.css referenzieren, ist sie einmal gespeichert.

Bedrohungsmodell

Siehe docs/threat-model.md. Kurzfassung:

  • Schützt gegen: Pfad-Traversal, gefährliche Endungen, parallele Überschreibungen, versehentliches Löschen
  • Mildert: Brute-Force auf Key-Erraten (Rate-Limit), einfache Replays (Audit-Log)
  • Schützt nicht gegen: gestohlenen API-Key, server-seitige RCE in eigenen PHP-Dateien, Supply-Chain-Angriffe
  • Key wie SSH-Key behandeln. Quartalsweise rotieren.

Einsatzfelder

  • Continuous Deployment zu All-Inkl / Strato / IONOS — GitHub Action, die diese API bei jedem Push aufruft
  • KI-Agent-Code-Edit-Loops — Claude / GPT schreibt Code → liest Server-Datei mit If-Match → wendet Patch an → schreibt zurück. Konflikt-sicher.
  • Multi-Umgebungs-Promotion — derselbe Client deployt Staging → Produktion durch Tausch der Base-URL
  • Eingeschränkte PHP-Umgebungen — funktioniert auf Hostern, wo curl, openssl_streams, shell_exec, mbstring, iconv deaktiviert sind
  • Air-Gapped Einweg-Deploys — Server hat keine ausgehende Konnektivität, nimmt nur Pushes über dieses Gateway entgegen

Beispiele

Roadmap

  • v0.2: Pro-Pfad-Zugriffsrechte (mehrere Keys mit unterschiedlichen Schreibbereichen), Audit-Log-Rotation, Webhook-Notifications bei Rollback
  • v0.3: OpenTelemetry-kompatibles Metric-Export, Snapshot-Sync zu externem Storage (S3/B2)
  • v0.4: Web-UI-Companion (separate Repo) für Snapshot-Browsing und manuellen Rollback

Lizenz

MIT — siehe LICENSE

Autor

Gebaut von Daniel Wesseling — IT-Manufaktur „Die Netzhandwerker", Gronau (Westfalen), Deutschland.

Siehe auch

About

Deploy to shared PHP hosting without SSH, without curl, without exec. Path-jailed write API with sha256 optimistic locking, snapshots, and rollback. Single-file gateway, zero dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages