- Neuer Auswahlschritt: Apple-Server (Download) vs. lokale downloads/library (Docker-Tool) -- letzteres komplett offline nutzbar. - InstallAssistant.pkg (Big Sur+) wird per installer -pkg -target / zur vollstaendigen Install-App entpackt, danach normaler createinstallmedia-Weg. - BaseSystem.dmg/InstallESD.dmg (bis Catalina) ist bereits ein fertiges bootfaehiges Volume -- kein createinstallmedia noetig, stattdessen diskutil eraseDisk + asr restore --erase (etablierte Community-Technik). - Flat-JSON-Parser (sed) fuer meta.json ohne jq/python3-Abhaengigkeit. - Auswahl-/Verzweigungslogik unter Linux mit simulierter Bibliothek end-to-end durchgetestet (beide Modi laufen korrekt bis zum jeweils ersten macOS-only-Befehl).
macOS USB Installer Tool
Lokale Web-GUI (Docker Compose) die macOS-Installer direkt von Apples Servern laedt und einen bootfaehigen USB-Stick daraus baut — ohne Mac.
Start
docker compose up --build
Dann im Browser: http://127.0.0.1:8080
Der Port bindet bewusst NUR an 127.0.0.1 (nicht 0.0.0.0) — von aussen
im Netzwerk nicht erreichbar.
Wie es funktioniert
1. Versions-Liste (automatisch aktuell)
Beim Container-Start wird gegen Apples echten Software-Update-Katalog
(swscan.apple.com) geprobt, welche macOS-Installer aktuell verfuegbar
sind. Das Namensschema der Katalog-URLs ist bekannt und wurde live
verifiziert (Stand: Erstellung dieses Tools). Wenn Apple eine neue
macOS-Hauptversion veroeffentlicht, taucht sie automatisch beim naechsten
Container-Start in der Liste auf — ohne Code-Aenderung, solange Apple
das Namensschema beibehaelt (das ist seit vielen Jahren stabil, aber keine
100%-Garantie fuer alle Zeit).
Per "neu laden"-Button in der GUI kann der Katalog auch ohne Neustart aktualisiert werden.
2. Zwei Installations-Pfade
| macOS-Version | Pfad | Status |
|---|---|---|
| bis Catalina (10.15) | legacy_dmg: BaseSystem.dmg direkt per dd auf den Stick |
robust, gut etabliert |
| ab Big Sur (11) aufwaerts | recovery: InstallAssistant.pkg wird entpackt (xar → pbzx → cpio), das darin enthaltene SharedSupport.dmg/BaseSystem.dmg wird dann per dd geschrieben |
experimentell |
Warum der Unterschied: Ab macOS Big Sur liefert Apple keinen fertigen
Installer-Datentraeger mehr, sondern ein Programm-Paket. Das eigentliche
Tool das daraus einen vollstaendigen Multi-Volume-Installer-Stick baut
(createinstallmedia) laeuft nur unter echtem macOS. Dieses Tool geht
stattdessen den Community-erprobten Weg: das darin enthaltene
Recovery-/BaseSystem-Image direkt extrahieren und schreiben. Der Stick
bootet damit in ein Internet-Recovery-System, das den Rest der
Installation von Apples Servern nachlaedt.
Das ist der fragilste Teil des ganzen Tools. Apple hat den internen
Aufbau von InstallAssistant.pkg in der Vergangenheit leicht veraendert.
Wenn die Extraktion fehlschlaegt (Fehlermeldung im Log-Fenster), ist das
kein Bug im eigentlichen Sinn, sondern ein Zeichen dass sich intern was
geaendert hat — dann muss backend/installer.py (_extract_recovery_dmg)
angepasst werden.
3. Offline-Bibliothek / "nur herunterladen"-Modus
Oben in der GUI laesst sich per Umschalter zwischen drei Modi waehlen:
- "Auf USB-Stick schreiben" (Standard) — wie bisher, eine Version, ein kompletter Stick.
- "Multiboot-Stick (mehrere Versionen)" — siehe Abschnitt 4 unten.
- "Nur herunterladen (Offline-Bibliothek)" — laedt ausschliesslich das
Original-Image (
BaseSystem.dmg/InstallESD.dmgbzw.InstallAssistant.pkg, je nach Version) und legt es dauerhaft unter./downloads/library/<name>/ab (inkl.meta.jsonmit Titel/Version/Groesse/Download-Zeitpunkt). Kein Geraet noetig, nichts wird geloescht.
Damit kannst du dir vorab — solange Internet da ist — eine komplette
Offline-Sammlung aller verfuegbaren macOS-Versionen aufbauen. Weil die
Downloads im Bind-Mount ./downloads liegen (siehe oben, kein Docker-Volume),
reicht es, den kompletten Projektordner (inkl. downloads/library/) auf eine
externe Platte zu kopieren — dort ist dann alles fuer den Stick-Bau parat,
auch ganz ohne Internetzugang.
Wichtig: ein "Stick erstellen"-Job prueft VOR jedem Download automatisch,
ob das Image schon in der Bibliothek liegt (installer.get_cached_payload),
und ueberspringt den Download dann komplett — das gilt fuer beide Modi.
Jeder normale Stick-Bau traegt also nebenbei zur Bibliothek bei, und ein
spaeterer Stick-Bau aus derselben Bibliothek (z.B. von der externen Platte)
laedt nichts erneut herunter.
Die GUI zeigt oben die Gesamtgroesse + Anzahl bereits heruntergeladener Installer an, und markiert bereits vorhandene Versionen in der Auswahlliste mit "bereits offline vorhanden".
4. Multiboot-Stick (mehrere macOS-Versionen auf einem Stick)
Im Modus "Multiboot-Stick" waehlst du in Schritt 1 statt einer Version per Checkbox 2 bis 8 Versionen gleichzeitig aus. Das Tool baut daraus einen einzigen Stick mit einer eigenen GPT-Partition pro Version.
Warum das funktioniert: Macs EFI-Bootmanager (beim Start Alt/Option
gedrueckt halten) scannt beim Boot-Picker alle Partitionen eines
angeschlossenen Datentraegers nach bootfaehigen Volumes, nicht nur die
erste. Legt man also mehrere Apple_HFS-Partitionen an und schreibt in
jede das vollstaendige, fuer sich bootfaehige Installer-Image, zeigt der
Boot-Picker automatisch alle als eigene Wahlmoeglichkeiten an. Das ist eine
in der Mac-Community seit Jahren dokumentierte Technik, kein Neuland dieses
Tools.
Ablauf im Backend (backend/installer.py, _run_multiboot_job):
- Alle gewaehlten Images werden (aus der Bibliothek oder frisch) geladen und wie im Einzel-Stick-Modus konvertiert -- ERST wenn alle fertig konvertiert sind, geht's weiter (kein Halb-Zustand auf dem Stick).
- Anhand der tatsaechlichen Image-Groessen + Puffer (
PARTITION_PADDING_MB) wird geprueft, ob der ausgewaehlte Stick ueberhaupt gross genug ist -- bevor irgendetwas geschrieben wird. Ist er zu klein, bricht der Job mit einer klaren Fehlermeldung (benoetigt vs. vorhanden in GB) ab, ohne den Stick anzuruehren. wipefs -a+sgdisk --zap-allloeschen den Stick komplett, dann legtsgdiskin einem Rutsch N Partitionen an (TypAF00= Apple HFS/HFS+, mit Label = Titel/Version der jeweiligen macOS-Version, sichtbar im Boot-Picker).- Jedes Image wird per
ddin seine eigene Partition geschrieben (/dev/sdb1,/dev/sdb2, ...), nicht auf das gesamte Geraet.
Ehrliche Einschraenkung -- als experimentell markiert:
- Fuer den
legacy_dmg-Pfad (bis Catalina) ist die Technik gut etabliert und robust. - Fuer den
recovery-Pfad (Big Sur+) erbt Multiboot dieselbe Unsicherheit wie der normale Einzel-Stick-Modus (siehe Abschnitt 2) -- kommt on top zur Multiboot-Partitionierung selbst dazu. Mischungen aus alten + neuen Versionen auf einem Stick sind technisch kein Problem, aber jede Big-Sur+-Version im Mix bleibt der fragilste Teil. - Groessenbedarf: 3 Versionen macOS koennen leicht 30-50GB+ zusammen ergeben, ein Stick mit 64GB+ ist fuer sinnvolle Kombinationen realistisch.
- Es gab noch keinen echten Boot-Test auf echter Mac-Hardware durch dieses Projekt selbst -- die Partitionierungs-/Schreib-Logik ist gegen einen echten Docker-Host verifiziert (Build + Job-Ablauf), das tatsaechliche "zeigt der Boot-Picker alle Partitionen an und bootet jede" muss beim ersten echten Einsatz am Mac verifiziert werden.
5. USB-Geraete-Erkennung
Der Container laeuft mit privileged: true und mountet /dev sowie
/run/udev vom Host durch — noetig, um Sticks direkt zu partitionieren
und zu beschreiben. Das ist bewusst so gebaut, bedeutet aber: der Container
hat vollen Zugriff auf alle Block-Devices des Rechners. Deshalb:
- Port ist NUR auf
127.0.0.1gebunden (kein Netzwerk-Zugriff von aussen). - Die System-Platte (auf der
/liegt) wird automatisch als Ziel gesperrt. - Nur Geraete mit USB-Transport werden als Ziel akzeptiert.
- Vor dem Schreiben muss der exakte Geraetepfad (z.B.
/dev/sdb) nochmal von Hand eingetippt werden — kein versehentliches Ein-Klick-Loeschen.
Trotzdem gilt: das Tool schreibt mit dd und wipefs direkt auf ein
Block-Device. Wenn du das falsche Geraet auswaehlst, sind die Daten weg.
Vor dem Start immer pruefen, welcher Stick tatsaechlich gemeint ist (Groesse
und Modell in der GUI vergleichen).
Build-Hinweis (hfsprogs / xar / pbzx)
Alles unten wurde am 2026-07-18 live gegen einen echten docker compose build
upauf einem echten Docker-Host getestet (nicht nur behauptet):
hfsprogsliegt in Debians non-free-Bereich. WICHTIG:bookworm-slimnutzt das neue deb822-Sourcen-Format (/etc/apt/sources.list.d/ debian.sourcesstatt der altensources.list). Eine zusaetzliche separatesources.list-Datei fuer dieselbedeb.debian.org-URI OHNESigned-Byfuehrt zuConflicting values set for option Signed-Byund brichtapt-get updatekomplett ab. Der Dockerfile patcht deshalb die bestehendedebian.sourcespersed(Components-Zeile umcontrib non-free non-free-firmwareerweitert) statt eine zweite Quelle anzulegen.xargibt es inbookwormueberhaupt nicht als Paket, wird aus dem Upstream-Repomackyle/xargebaut. Dessenconfigure.acprueft OpenSSL ueberAC_CHECK_LIB([crypto], [OpenSSL_add_all_ciphers])-- diese Funktion ist in OpenSSL 3.x (Debian bookworm) nur noch ein no-op-Praeprozessor-Makro inevp.h, kein linkbares Symbol mehr. Der Autoconf-Test schlaegt deshalb fehl ("Cannot build without libcrypto"), obwohllibssl-devkorrekt installiert ist. Fix: der Dockerfile biegt den Probe-Funktionsnamen persedaufEVP_EncryptInitum (gegenlibcrypto.so.3pernmverifiziert, seit jeher stabil exportiert).xarMUSS vorpbzxgebaut werden --pbzxlinkt gegen-lxarundxar/xar.h.pbzx: das Repomackyle/pbzxexistiert nicht (mehr) auf GitHub (404). Git meldet das irrefuehrend alscould not read Username for 'https://github.com', weil GitHub beigit-upload-pack-Requests gegen nichtexistente/private Repos aus Anti-Enumeration-Gruenden 401 statt 404 zurueckgibt. Fix: Community-Standard-ForkNiklasRosenstein/pbzx(u.a. in OSX-KVM genutzt) wird stattdessen geklont.
Macht den ersten Build minimal langsamer, aber zuverlaessiger als ein Distro-Wechsel.
Katalog-Bugs (gefunden + gefixt, 2026-07-18)
Zwei echte Bugs in backend/catalog.py, beide live gegen den echten
Apple-Katalog (swscan.apple.com) reproduziert und verifiziert:
- Doppeltes Entpacken: Apples Server schickt den Katalog mit
Content-Encoding: x-gzip.requests/urllib3dekomprimiert das bereits TRANSPARENT -- der Code rief zusaetzlichgzip.decompress()drauf auf, was mitBadGzipFile: Not a gzipped filecrashte (die Gzip-Magic-Bytes waren durch die automatische Dekompression laengst weg). Fix: nur noch entpacken wenn die Bytes wirklich noch mit der Gzip-Magic (\x1f\x8b) anfangen. - Big Sur+ wurde komplett ausgefiltert:
_is_macos_installer()prüfte nur auf das klassische Schema (ExtendedMetaInfo.InstallAssistantPackageIdentifiers.OSInstall == "com.apple.mpkg.OSInstall", gueltig bis Catalina). Ab Big Sur nutzt Apple stattdessen einenSharedSupport-Key (com.apple.pkg.InstallAssistant.macOSBigSur,...macOSTahoe, etc.) -- ohne den alten Key. Der Filter hat dadurch STILLSCHWEIGEND alle Big-Sur-bis-Tahoe-Installer verworfen, obwohl sie im selben Katalog laengst enthalten waren (live verifiziert: 24 InstallAssistant.pkg- Eintraege im Katalog, 0 davon trafen den alten Filter). Genau derrecovery-Pfad, den dieses Tool eigentlich anbieten soll. Fix:_is_macos_installererkennt jetzt beide Schemata;_fetch_product_ metadatafaellt bei fehlendemServerMetadataURL(Big Sur+ hat keins) auf den Namen aus demSharedSupport-Identifier zurueck. Nach dem Fix: 37 statt 13 Installer gefunden, inkl. macOS Tahoe.
Beide Fixes wurden nicht nur im Code geaendert, sondern gegen den echten,
frisch gebauten Container end-to-end verifiziert (/api/versions liefert
jetzt tatsaechlich Big Sur bis Tahoe zurueck).
Voraussetzungen auf dem Host
- Docker + Docker Compose
- Linux (getestet gegen die Grundannahmen von
lsblk//dev/udev; auf macOS/Windows-Docker-Desktop funktioniert das Device-Passthrough so nicht)
Alternative: nativer Mac-Weg (createinstallmedia)
Wenn zufaellig ein echter Mac zur Verfuegung steht (macOS 10.15+), gibt es
unter native-macos/ ein eigenstaendiges Terminal-Script
(create-stick.sh), das statt des Recovery-Extraktions-Workarounds die
echte createinstallmedia nutzt — ueber Apples eigenen
softwareupdate --fetch-full-installer-Befehl. Kein Docker noetig, keine
Abhaengigkeiten ausser macOS-Bordmitteln. Details siehe dortiges README;
wichtig: die beiden Wege sind bewusst unabhaengig, weil createinstallmedia
ein anderes Installer-Format braucht als die rohen Katalog-Images, die das
Docker-Tool hier im Root verwendet.
Bekannte Grenzen (ehrlich, nicht schoengeredet)
- Der
recovery-Pfad (Big Sur+) ist nicht production-hardened getestet worden, sondern nach dokumentiertem, in der Hackintosh-/Recovery-Community etabliertem Verfahren gebaut. Rechne bei sehr neuen macOS-Versionen mit Nacharbeit. - Die Katalog-Zukunftssicherheit haengt an Apples URL-Namensschema. Bricht
Apple das Schema, muss
backend/catalog.pyangepasst werden (kurzer Fix, kein Rewrite). - Kein Windows/macOS-Docker-Host-Support fuer das Device-Passthrough — nur natives Linux.
- Der Multiboot-Modus (Abschnitt 4) wurde bislang nur end-to-end bis zur fertig geschriebenen Partitionstabelle/den Images verifiziert, NICHT durch einen echten Boot-Test auf Mac-Hardware. Die zugrundeliegende Multi-Partition-Bootpicker-Technik ist etabliertes Community-Wissen, aber "funktioniert bei diesem Tool nachweislich" != "wurde von uns am Mac gebootet".