Sheets via neuer KeyboardAwareSheet-Composable (in Modal pattern, auto-grow mit Tastatur, paddingBottom-Lift): EditMail, AddDomain, CreateRoom, ConnectMail. GameOverScreen behält Spring-Slide-In, nutzt RN Keyboard.addListener für Lift. - KeyboardAwareSheet.tsx — universal modal with sheet-grow + keyboard-padding - react-native-keyboard-controller installiert + KeyboardProvider in Root - Snake: time + ScoreProgressBar + useSnakeSounds (haptic, audio TODO) - Tetris: title weg, Buttons zentriert, kein Pressable mit style-fn - DPad-Buttons 60→48, more bg, no scale - useMe: pub-sub listener pattern für app-weite avatar/nickname-Updates - dm.tsx: resolveAvatar wrap (iron.png-Warning) - Mail-error-humanizer + locales Recovery-Doc-Update in docs/internal/RECOVERY_LOG_2026-05-10.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
13 KiB
MDM Setup — Phasen
Phase A ✅ Server-Bootstrap
Erledigt vor 2026-05-10.
- apt-update + apt-upgrade
- Pakete installiert: nginx, postgresql, docker.io, certbot, python3-certbot-nginx, ufw, fail2ban
- UFW konfiguriert: 22/tcp, 80/tcp, 443/tcp erlaubt, default-deny
- fail2ban aktiv (SSH-Brute-Force-Schutz)
- DNS: IONOS A-Record
mdm.rebreak.org→ 178.105.101.137
Phase B ✅ TLS-Zertifikat
Erledigt vor 2026-05-10.
certbot --nginx -d mdm.rebreak.orgausgeführt- Cert liegt in
/etc/letsencrypt/live/mdm.rebreak.org/ - certbot.timer (systemd) erneuert automatisch
Phase C ✅ NanoMDM Container + nginx-Vhost
Erledigt 2026-05-10.
Was gemacht wurde:
- PostgreSQL-Datenbank
nanomdmmit Usernanomdmund Passwort aus/root/.nanomdm_db_passangelegt ALTER USER nanomdm WITH PASSWORD '...'explizit gesetzt (scram-sha-256 braucht explizites Passwort)pg_hba.confergänzt für Docker-Netze (172.17.0.0/16, 172.18.0.0/16)listen_addressesinpostgresql.confauflocalhost,172.17.0.1,172.18.0.1erweitert- MDM CA generiert:
ca.key+ca.crtin/opt/nanomdm/certs/ /opt/nanomdm/.envmitNANOMDM_DB_PASSgeschrieben (chmod 600)/opt/nanomdm/docker-compose.ymlmitnetwork_mode: host(kritisch, sonst postgres nicht erreichbar wegen NAT-Masquerade)docker compose up -d— Container läuft,starting server listen=127.0.0.1:9000bestätigt- nginx-Vhost
/etc/nginx/sites-available/mdm.rebreak.orggeschrieben + in sites-enabled symlinkt nginx -t && systemctl reload nginx- Externer Verify:
curl -sI https://mdm.rebreak.org/→HTTP/2 404von nanomdm (korrekt, kein 502)
Bekannte Tücken aus diesem Setup:
micromdm/nanomdmauf Docker Hub existiert nicht. Korrektes Image:ghcr.io/micromdm/nanomdm:latest- nanomdm v0.9 kennt
-storage postgresnicht. Korrekt:-storage pgsql(bzw.NANOMDM_STORAGE=pgsql) - Docker-Compose-Netzwerk (172.18.x) geht via NAT durch Host — Postgres sieht externe IP als Source. Lösung:
network_mode: hostim Compose, dann verbindet nanomdm direkt zu127.0.0.1:5432 - nginx 1.24 kennt
http2 on;nicht (das ist nginx 1.25+). Korrekt:listen 443 ssl http2;
Phase D ✅ Apple Push CSR generiert
Erledigt 2026-05-10.
openssl req -newkey rsa:2048 -nodes \
-keyout /opt/nanomdm/certs/push.key \
-out /opt/nanomdm/certs/push.csr \
-subj '/CN=ReBreak MDM Push/O=Raynis/C=DE'
chmod 600 /opt/nanomdm/certs/push.key
CSR-Content liegt in /opt/nanomdm/certs/push.csr. Der private Key push.key verlässt den Server nie.
Phase D.0.5 ✅ mdmcert.download Signing-Request
Erledigt 2026-05-10.
Warum dieser Schritt notwendig ist:
Apple Push Notification Service (APNS) für MDM akzeptiert keine rohen CSRs von Self-Hostern direkt im Apple Push Portal. Apple verlangt, dass die CSR von einem akkreditierten MDM-Vendor signiert wird. Self-Hoster ohne Apple-MDM-Vendor-Status nutzen mdmcert.download — ein Service des MicroMDM-Teams, der die CSR mit einem akzeptierten Vendor-Key gegen-signiert und encrypted per Email zurückschickt.
Was passiert:
- Wir schicken unseren CSR base64-encoded + eine Encryption-Cert an
https://mdmcert.download/api/v1/signrequest - mdmcert.download signiert ihn mit ihrem Apple-akkreditierten Vendor-Key
- Sie verschlüsseln das Ergebnis mit unserer Encryption-Cert (PKCS7) und senden es per Email an
hello@chahine-brini.com - Das entschlüsselte Ergebnis (nicht der raw CSR, nicht das
.b64.p7) wird im Apple Push Portal hochgeladen
Was gemacht wurde:
-
Encryption-Keypair auf dem MDM-Server generiert:
- Cert:
/opt/nanomdm/certs/mdmcert-encryption.crt(public, wird an mdmcert.download geschickt) - Key:
/opt/nanomdm/certs/mdmcert-encryption.key(chmod 600, verlässt Server nie)
openssl req -new -newkey rsa:2048 -nodes \ -keyout /opt/nanomdm/certs/mdmcert-encryption.key \ -x509 -days 365 \ -out /opt/nanomdm/certs/mdmcert-encryption.crt \ -subj '/CN=ReBreak mdmcert encryption' chmod 600 /opt/nanomdm/certs/mdmcert-encryption.key - Cert:
-
Signing-Request an mdmcert.download abgeschickt (shared public API-Key aus micromdm-Source, öffentlich dokumentiert):
PUSH_CSR_B64=$(base64 -w0 /opt/nanomdm/certs/push.csr) ENC_CRT_B64=$(base64 -w0 /opt/nanomdm/certs/mdmcert-encryption.crt) curl -X POST https://mdmcert.download/api/v1/signrequest \ -H "Content-Type: application/json" \ -H "User-Agent: micromdm/certhelper" \ -d "{\"csr\":\"$PUSH_CSR_B64\",\"email\":\"hello@chahine-brini.com\",\"key\":\"<shared-api-key>\",\"encrypt\":\"$ENC_CRT_B64\"}"Antwort:
{"result":"success"}
Naechster Schritt: Email von mdmcert.download bei hello@chahine-brini.com prüfen. Anhang-Name hat Format mdm_signed_request.YYYYMMDD_HHMMSS_NNN.plist.b64.p7. Dann weiter mit Phase D.0.7.
Technische Details (wichtig fuer Decrypt):
- Der Dateiname endet auf
.b64.p7— irreführend. Der tatsächliche Inhalt ist hex-encoded PKCS7, nicht base64. (Quelle: micromdm/micromdm cmd/mdmctl/mdmcert.download.go, Decrypt-Pfad) - Der Decrypt-Befehl (
openssl cmsoder PKCS7-Tooling) muss zuerst hex→binary decodieren, dann PKCS7 mit dem mdmcert-encryption.key entschlüsseln
Phase D.0.7 ⏳ Signed CSR entschlüsseln
Voraussetzung: Email von mdmcert.download mit Anhang empfangen (Phase D.0.5 abgeschlossen)
Wer: Chahine schickt den Anhang per scp auf den MDM-Server. Oder Backyard entschlüsselt wenn Anhang auf den Server kopiert wurde.
Schritte:
-
Anhang von Email speichern (z.B.
mdm_signed_request.20260510_XXXXXX.plist.b64.p7) -
Datei auf Server kopieren:
scp ~/Downloads/mdm_signed_request.*.plist.b64.p7 rebreak-mdm:/opt/nanomdm/certs/signed_request.p7 -
Hex→Binary dekodieren + PKCS7 entschlüsseln (micromdm-Tooling macht beides intern):
# Hex-String aus der Datei zu Binary konvertieren xxd -r -p /opt/nanomdm/certs/signed_request.p7 > /opt/nanomdm/certs/signed_request.der # PKCS7 mit unserem Encryption-Key entschlüsseln openssl cms -decrypt \ -in /opt/nanomdm/certs/signed_request.der \ -inform DER \ -inkey /opt/nanomdm/certs/mdmcert-encryption.key \ -recip /opt/nanomdm/certs/mdmcert-encryption.crt \ -out /opt/nanomdm/certs/push_request.plist -
Ergebnis
/opt/nanomdm/certs/push_request.plistprüfen — sollte eine Apple Plist-Datei sein.head -5 /opt/nanomdm/certs/push_request.plist # Erwartete Ausgabe: <?xml version="1.0" ... oder PEM-ähnliches Format -
DIESE Datei (
push_request.plist) wird bei https://identity.apple.com hochgeladen (Phase D.1).
Status: Wartet auf Email-Empfang bei hello@chahine-brini.com
Phase D.1 ⏳ Apple Push Cert — Benutzeraktion
Voraussetzung: Phase D.0.7 abgeschlossen (entschlüsseltes Plist push_request.plist auf Server)
Wer: Chahine (muss mit Apple-ID eingeloggt sein, die als MDM-Zertifikats-Owner gelten soll)
WICHTIG: NICHT den raw push.csr oder die .b64.p7-Datei hochladen.
Hochgeladen wird die entschlüsselte push_request.plist aus Phase D.0.7.
Schritte:
- Phase D.0.7 abschliessen —
push_request.plistauf Server entschlüsselt - Datei lokal runterladen:
scp rebreak-mdm:/opt/nanomdm/certs/push_request.plist ~/Downloads/ - Oeffne https://identity.apple.com/pushcert/ im Browser (einloggen mit Apple-ID)
- Klicke "Create a Certificate"
- Lade
push_request.plisthoch (NICHT push.csr, NICHT die.b64.p7-Datei) - Download das ausgestellte Zertifikat (
.pemoder.cer) - Kopiere es auf den Server:
scp ~/Downloads/MDMCertificate.pem rebreak-mdm:/opt/nanomdm/certs/push.pem - Setze Permissions:
ssh rebreak-mdm "chmod 600 /opt/nanomdm/certs/push.pem" - Informiere Backyard-Agent fuer Phase E
Wichtig:
- Das Zertifikat ist an die Apple-ID geknuepft, mit der es erstellt wurde
- Gueltigkeitsdauer: 1 Jahr
- Bei Renewal: GLEICHEN
push.keyverwenden (kein neues keypair generieren) - Wenn push.key verloren geht: alle Geraete muessen re-enrollen
Phase D.2 ✅ NanoMDM mit Push-Cert konfiguriert
Erledigt 2026-05-10.
Was gemacht wurde:
- NanoMDM API-Key generiert (32-char-hex), in
/opt/nanomdm/.env(NANOMDM_API=) +/root/.nanomdm_admin_pass(chmod 600) - Container force-recreated mit neuem env-file
- Postgres-Schema von https://raw.githubusercontent.com/micromdm/nanomdm/main/storage/pgsql/schema.sql geladen + applied (8 tables: devices, push_certs, commands, etc.) — fehlte aus initial-setup
- Push-Cert via
PUT /v1/pushcert(basic-auth) hochgeladen → inpush_certstable - Verify: Topic
com.apple.mgmt.External.816a2d4a-4ce1-4b44-9264-2831b891206a, valid bis 2027-05-10 - External smoke-test:
curl -u nanomdm:<key> https://mdm.rebreak.org/version→{"version":"v0.9.0"}✅
Bekannte Tücke: Initial-setup hat das postgres-schema nicht angewendet. NanoMDM-Container hat keine eingebaute migrate-step. Schema muss manuell via psql -f schema.sql geladen werden bevor erster API-call funktioniert.
Phase E ⏸ Email-Distribution an Ina — geparkt (User-Decision 2026-05-10)
Status: PARKED — alles server-side ready, Versand verschoben.
User-Entscheidung: PIN-Versand an Ina jetzt nicht — wird später nachgeholt. iPhone-Enrollment kann ohne laufen (MASTER-PIN ist Recovery-Backup, nicht Voraussetzung für enrollment).
Server-Status:
- ✅ MASTER-Recovery-PIN auf Server:
/root/.nanomdm_master_pin(chmod 600) - ✅ Ina-Email-Draft auf Server:
/root/INA_EMAIL_DRAFT.md(chmod 600) - ✅ Resend-API-Key auf Server:
/root/.resend_api_key(chmod 600) - ⏸ Resend-Domain-Verify ungetan — Versand würde fehlschlagen ohne
chahine-brini.comoderrebreak.orgverified
Reaktivierung: User sagt „Phase E GO", wir verifizieren Domain in Resend, senden, fertig. Files bleiben bis dahin auf Server.
Phase F ⏳ Device-Enrollment
Wartet auf Phase E.
Was passiert:
- iPhone auf Werkseinstellungen zurücksetzen (Backup vorher!)
- Während Setup: iPhone via USB-C mit Mac verbinden, Apple Configurator 2 öffnen
- In Apple Configurator 2: Gerät preparieren (Supervised Mode aktivieren)
- MDM-Enrollment-Profil von
https://mdm.rebreak.org/enrollauf Gerät installieren - Verifyieren dass Profil als "nicht entfernbar" markiert ist
- Apps installieren (ReBreak, etc.)
Hinweis zum Supervised Mode: Ohne Supervision kann das MDM-Profil vom User entfernt werden. Supervision braucht einmalig USB + Apple Configurator. Danach ist OTA-MDM-Update möglich.
Scope-Constraint (User-bestätigt 2026-05-10): Profil enthält NUR allowAppRemoval=false für Bundle-ID org.rebreak.app + allowMDMProfileRemoval=false. KEIN App-Store-Block, keine weiteren Restrictions. iOS-App-Store hat keine Echtgeld-Casino-Apps (Apple-Policy), Browser-Casinos werden von ReBreak's NEFilter geblockt.
Phase G ⏳ iPad-Enrollment (optional, später)
Identisch zu Phase F, gleicher flow:
- iPad via USB-C mit Mac verbinden
- Apple Configurator 2 → Supervised-Mode → factory-reset
- MDM-enrollment-profile von
https://mdm.rebreak.org/enroll - ReBreak-iOS app installieren (läuft nativ auf iPad)
- Verifyieren: ReBreak nicht entfernbar, MDM-profile nicht entfernbar
Aufwand: ~30min nach Phase F. Apple Push Cert deckt iPad mit ab (kein zusätzlicher cert nötig).
Voraussetzung: Phase F erfolgreich getestet auf iPhone.
Phase H ⏳ MacBook-Enrollment (optional, später)
Anders als iPhone/iPad weil:
- Kein ReBreak-Mac-app existiert → MDM-profile muss eigene Blocking-Mechanik mitbringen
- Lösung: Web-Content-Filter-Payload im profile (DNS/URL-blocklist auf OS-Ebene)
- Mac-Supervised-Mode: factory-reset des MacBook nötig (analog iPad), via Apple Configurator 2 + USB-C
Schritte:
- ReBreak-Blocklist (~208k domains) als Web-Content-Filter-Payload formattieren
- Payload-type:
com.apple.webcontent-filter - oder
com.apple.dnsSettings.managedfür DNS-level-block
- Payload-type:
- MDM-profile assemblen mit:
allowMDMProfileRemoval=false(braucht supervised-mode)- Web-Content-Filter mit Casino-Blocklist
- Optional:
allowSafariAutoFill=false(verhindert auto-login auf bekannten casino-sites)
- MacBook factory-reset → Apple Configurator 2 → supervised-mode → MDM-enrollment
- Verify: Casino-domain im Browser → blocked
Aufwand: ~1 Tag (blocklist-conversion + profile-assembly + test). Plus factory-reset-zeit.
Voraussetzung:
- Phase F+G erfolgreich
- User explizites GO (factory-reset MacBook = großer Schritt)
- Backup von wichtigen MacBook-Daten
Tradeoff: Kein ReBreak-Mac-app = nur URL-blocking, keine SOS-features, kein Lyra, keine Community auf Mac. Wer ReBreak-features auf Mac will, braucht später entweder native Mac-app (s. ops/mac-version-research.md) oder Browser-Extension.