Zurück zu Learnings

Learnings / Mit MinIO entwickeln

S3-Speicher auf dem eigenen NAS.

Wie wir MinIO auf unserem NAS für Dokumente und Backups betreiben, wie wir die vollständige Admin-Konsole zurückgeholt haben und wie jede App einen Schlüssel erhält, der nur ihren eigenen Bucket erreicht.

Der Grund

Eigener Speicher kann trotzdem S3 sprechen.

Unsere Apps speichern Dateien über die S3-API, genau wie in der Cloud. Der Bucket steht nur auf einem NAS in unserem Büro. Jede App erhält ihren eigenen Bucket und einen Schlüssel, der nichts anderes sieht.

2025 hat MinIO die Verwaltung von Benutzern, Richtlinien und Schlüsseln aus seiner kostenlosen Konsole entfernt. Wir betreiben jetzt die letzte vollständige Version dieser Konsole aus einem Community-Fork, direkt neben dem Server. Für den Build braucht es zwei kleine Korrekturen, die wir beide weiter unten zeigen.

01 / Das Konzept

Eine Speicherschicht für Dokumente, Backups und Modelle

Unsere Dokumenten-App verarbeitet Scans und Rechnungen auf einem Mac. Fertige Dokumente sollen auf das NAS wandern, statt die Festplatte des Macs zu füllen. Ihre nächtlichen Backups brauchen einen Ort mit eigenen Aufbewahrungsregeln. Ausserdem bewahren wir mit Model Library, unserem quelloffenen Modellarchiv, Kopien der Sprachmodelle auf, die wir lokal betreiben. Das verdient einen eigenen Beitrag.

Der Archiv-Bucket von Model Library in der wiederhergestellten Konsole: 2,8 TiB in 2186 Objekten, ein Ordner pro Modellanbieter. Wählen Sie das Bild aus, um es zu vergrössern.

Alles läuft über MinIO, einen S3-kompatiblen Objektspeicher. Die App kennt nur einen Endpunkt, einen Bucket und einen Schlüssel. Ob der Bucket auf unserem NAS oder bei einem Cloud-Anbieter liegt, spielt für sie keine Rolle, und genau darum geht es. Ist MinIO eines Tages nicht mehr die richtige Wahl, ändern wir einen Endpunkt, nicht die App.

Auf dem Mac
Dokumenten-AppVerarbeitet Scans lokal und archiviert sie nach 7 Tagen in ihrem Bucket.Archivierung geplant
Nächtliche BackupsDatenbank-Dump und Dateiarchive.
Model LibraryBewahrt unsere Kopien lokaler Sprachmodelle auf.
macOS-SchlüsselbundEnthält den Schlüssel jeder App. Der Startbefehl übergibt ihn an die App.geplant
S3-API-Anfragen, signiert mit dem eigenen Schlüssel der App
Browser zur Admin-Konsole
Nur im privaten Netzwerk
Auf dem NAS
Docker
MinIO-ServerBeantwortet die S3-API und prüft jede Anfrage gegen die Richtlinie des Schlüssels.
documentsNur der Schlüssel der Dokumenten-App.Versioniert, alte Versionen werden nach 30 Tagen entfernt.
documents-backupsNur für Admins, der App-Schlüssel erreicht ihn nicht.Objekte werden 30 Tage nach dem Hochladen entfernt.
Modell-BucketsDas Archiv der Modelldateien von Model Library.Ein Bucket pro Modell-Laufzeit.
↑ Admin-API im internen Docker-Netzwerk
OpenMaxIO-Konsole v1.7.6Benutzer, Richtlinien und Zugriffsschlüssel. Meldet sich mit einem eigenen Admin-Benutzer an, nie als Root.
Die Festplatten des NAS halten die Objekte. MinIO legt die S3-API und die Zugriffsregeln darüber.
Offsite-KopieWasabi in der Cloud, gespeist aus dem Dokumenten-Bucket.geplant

02 / Das Problem

Die Admin-Seiten verschwanden aus der kostenlosen Konsole

Im März 2025 übernahm MinIO eine Änderung, die die Community-Konsole auf einen Objekt-Browser reduzierte. Benutzer, Richtlinien und Zugriffsschlüssel wanderten auf die Kommandozeile mc. Unsere Konsole zeigte Buckets und Dateien. Sonst nichts.

Ein Community-Fork, OpenMaxIO, wollte die vollständige Konsole erhalten. Unterwegs sind wir in zwei Fallen getappt.

Der Hauptzweig des Forks enthält die Änderung von MinIO bereits. Wir haben ihn zuerst gebaut und bekamen denselben reduzierten Objekt-Browser, nur mit anderem Logo. Die letzte Version mit den Admin-Seiten ist der Tag v1.7.6 vom Februar 2025.

Dieser Tag lässt sich so nicht mehr bauen. Sein Frontend lädt die Designbibliothek von MinIO aus github.com/minio/mds, und dieses Repository gibt es nicht mehr. OpenMaxIO hält unter github.com/openmaxio/mds eine Kopie mit genau dem Commit, den v1.7.6 erwartet. Eine Zeile im Build leitet die Abhängigkeit dorthin um.

Eine kleinere Falle kostete uns ebenfalls einen Build. Yarn 4 konnte diese Abhängigkeit im Alpine-basierten Node-Image nicht klonen und brach mit invalid key: core.autocrlf ab. Das Debian-basierte Image funktioniert.

03 / Wie es funktioniert

Eine Konsole, ein Schlüssel pro App, nichts ungeprüft gelöscht

Die vollständige Konsole aus v1.7.6

Wir bauen die Konsole aus dem Quellcode in einem Container. Die beiden Korrekturen sind das Basis-Image und die umgeleitete Abhängigkeit.

FROM node:20-bookworm-slim AS web
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates
WORKDIR /src
RUN git clone https://github.com/OpenMaxIO/openmaxio-object-browser . && git checkout v1.7.6
WORKDIR /src/web-app
RUN sed -i 's#github.com/minio/mds.git#github.com/openmaxio/mds.git#g' package.json yarn.lock
RUN corepack enable && yarn install && yarn build

FROM golang:1.23-alpine AS go
COPY --from=web /src /src
WORKDIR /src
RUN CGO_ENABLED=0 go build -trimpath --tags=kqueue -o /console ./cmd/console

FROM alpine:3.20
COPY --from=go /console /usr/local/bin/console
ENTRYPOINT ["console", "server", "--port", "9090"]

Die Konsole läuft als eigener Container im Docker-Netzwerk von MinIO und spricht intern mit der S3-API. MinIO selbst bleibt unverändert. Wir melden uns mit einem separaten Admin-Benutzer an, nicht mit dem Root-Konto. So laufen die Root-Zugangsdaten nie durch die Konsole.

Die Konsole aus v1.7.6 mit dem zurückgekehrten Administratormenü: Buckets, Richtlinien, Identitäten, Zugriffsschlüssel und Konfiguration. Wählen Sie das Bild aus, um es zu vergrössern.

Ein Bucket, ein Benutzer, ein Schlüssel pro App

Für die Dokumenten-App haben wir eine Richtlinie geschrieben, die das Auflisten eines Buckets sowie das Lesen, Schreiben und Löschen von Objekten darin erlaubt.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket", "s3:GetBucketLocation"],
      "Resource": ["arn:aws:s3:::documents"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": ["arn:aws:s3:::documents/*"]
    }
  ]
}

Ein Benutzer erhält diese Richtlinie, und die App bekommt einen Zugriffsschlüssel dieses Benutzers. Bevor wir den Schlüssel weitergaben, haben wir ihn in beide Richtungen getestet. In seinem Bucket kann er auflisten, schreiben, lesen und löschen. Einen anderen Bucket auflisten, die Admin-API aufrufen oder einen Bucket anlegen, all das endet mit Access Denied.

Testen Sie auch die Verbote. Ein Schlüssel, der alles darf, besteht den positiven Test ebenfalls.

Versionierung statt Aufräumskript

Mit aktivierter Versionierung behält MinIO die vorherige Version, wenn die App eine Datei überschreibt oder löscht. Eine Lifecycle-Regel entfernt diese alten Versionen nach 30 Tagen, damit der Bucket nicht endlos wächst.

Backups landen in einem zweiten Bucket, den der App-Schlüssel nicht erreicht. Dort löscht eine Regel Objekte 30 Tage nach dem Hochladen. Ein Fehler in der App oder ein geleakter App-Schlüssel kann die eigenen Backups nicht löschen.

mc version enable nas/documents
mc ilm rule add nas/documents --noncurrent-expire-days 30
mc ilm rule add nas/documents-backups --expire-days 30

Schlüssel in einer Datei, die niemand liest

Beim Einrichten fanden wir die Schlüssel für das Offsite-Backup der App zu Wasabi. Sie lagen seit Juni in .env.local. Docker Compose liest nur .env, und die Compose-Datei hat sie nie an die Container weitergegeben. Der Backup-Job existierte und sah konfiguriert aus, und er hatte nie ein einziges Dokument hochgeladen.

Deshalb liegt der MinIO-Schlüssel im macOS-Schlüsselbund statt in einer Datei. Container können den Schlüsselbund nicht lesen. Der nächste Schritt ist darum ein Startbefehl, der den Schlüssel ausliest und den Containern als Umgebungsvariablen übergibt. Dieser Teil ist noch nicht gebaut.

Zurücklesen, bevor Sie löschen

Wir haben 17 GB Backups der App in den Backup-Bucket verschoben. Bevor wir eine lokale Kopie löschten, haben wir jede Datei erneut heruntergeladen und die SHA-256-Prüfsummen verglichen. Alle 42 Dateien stimmten überein.

Bei einer Abkürzung lauert eine Falle. Bei Dateien, die in Teilen hochgeladen wurden, ist das ETag von MinIO nicht der MD5-Wert der Datei. Wer ETags mit lokalen MD5-Summen vergleicht, hält diese Dateien für verschieden, obwohl sie identisch sind.

Das Risiko, das wir eingehen

v1.7.6 stammt vom Februar 2025, und der Fork hat sich seit Juni 2025 nicht mehr bewegt. Neue Funktionen für die Konsole bekommen wir nicht. Deshalb bleibt sie in unserem privaten Netzwerk und ist nie aus dem Internet erreichbar.

Beim Server sieht es nicht anders aus. MinIO hat sein Open-Source-Repository im April 2026 archiviert. Das letzte Release vom Oktober 2025 behebt eine schwerwiegende Rechteausweitung bei Zugriffsschlüsseln, und weitere Korrekturen wird es nicht geben. Betreiben Sie dieses Release, kein älteres.

Das letzte Server-Release selbst bauen

MinIO veröffentlicht keine Images mehr, deshalb bauen wir dieses Release aus seinem Quell-Tag, genau wie die Konsole. Übernehmen Sie die Umgebungsvorgaben aus MinIOs eigenem Dockerfile.release an diesem Tag, damit sich der Server wie bisher verhält. Sichern Sie vorher .minio.sys im Datenverzeichnis. Dort liegen Benutzer, Richtlinien und Schlüssel.

FROM golang:1.24-alpine AS build
RUN apk add --no-cache git
WORKDIR /src
RUN git clone --depth 1 --branch RELEASE.2025-10-15T17-29-55Z https://github.com/minio/minio .
RUN CGO_ENABLED=0 go build -tags kqueue -trimpath -ldflags "$(go run buildscripts/gen-ldflags.go)" -o /minio

FROM alpine:3.20
RUN apk add --no-cache ca-certificates
COPY --from=build /minio /usr/bin/minio
COPY --from=build /src/dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
CMD ["minio"]

Unterwegs gab es noch eine Falle. Wir hatten auf dem Server eine eigene Region gesetzt, und die Konsole konnte sich nicht mehr anmelden. Der Server antwortete mit the region is wrong; expecting 'us-east-1', obwohl er unsere eigene Region erwartete. Ist eine Region gesetzt, akzeptiert MinIO nur Anfragen, die für diese Region signiert sind. Lassen Sie das Feld leer, solange Sie es nicht brauchen, oder setzen Sie CONSOLE_MINIO_REGION in der Konsole auf denselben Wert.

Wir nehmen das vorerst in Kauf, weil unsere Apps nur die S3-API nutzen. Müssen wir wechseln, sprechen Garage und SeaweedFS dieselbe API, und die Apps behalten ihren Code.

04 / Installation

Die Konsole neben Ihrem MinIO betreiben

Sie brauchen MinIO in Docker, den Client mc und für den ersten Build 10 bis 15 Minuten.

  1. Legen Sie für die Konsole einen Admin-Benutzer mit einer Richtlinie an, die admin:* und s3:* erlaubt.
  2. Bauen Sie das Image aus dem Dockerfile oben und starten Sie es im Docker-Netzwerk von MinIO, mit gesetzten Werten für CONSOLE_MINIO_SERVER, CONSOLE_PBKDF_PASSPHRASE und CONSOLE_PBKDF_SALT.
  3. Legen Sie für jede App eine Richtlinie für ihren Bucket an, einen Benutzer mit dieser Richtlinie und einen Zugriffsschlüssel. Testen Sie, was der Schlüssel darf und was nicht.
  4. Aktivieren Sie die Versionierung und fügen Sie Lifecycle-Regeln hinzu.
services:
  console:
    build: .
    environment:
      CONSOLE_MINIO_SERVER: http://minio:9000
      CONSOLE_PBKDF_PASSPHRASE: ${CONSOLE_PBKDF_PASSPHRASE}
      CONSOLE_PBKDF_SALT: ${CONSOLE_PBKDF_SALT}
    ports: ["9102:9090"]
    networks: [minio]
networks:
  minio: { external: true, name: minio_default }
mc admin policy create nas consoleAdmin console-admin.json
mc admin user add nas console-admin "$CONSOLE_ADMIN_PASSWORD"
mc admin policy attach nas consoleAdmin --user console-admin

Diesen Leitfaden delegieren

Geben Sie dies Ihrem Agenten

Kopieren Sie diese Eingabeaufforderung in Ihren Codierungsagenten. Es sollte die Voraussetzungen prüfen, diese Anleitung durchführen und berichten, was es überprüft hat.

Help me run the OpenMaxIO admin console next to my existing MinIO and give one app its own bucket and key, as described in this article.

First check that MinIO already runs in Docker, find its Docker network and confirm that the mc client reaches it with an admin account. If there is no MinIO yet, stop and tell me. This guide does not cover a fresh install, because MinIO's open-source project is archived. If the server is older than RELEASE.2025-10-15T17-29-55Z, tell me before going further. Do not change the MinIO server or its data.

Build OpenMaxIO from the tag v1.7.6 with the two fixes from the article: a Debian-based Node image, and the mds dependency redirected to github.com/openmaxio/mds. Do not build the main branch, it lacks the admin pages. Generate CONSOLE_PBKDF_PASSPHRASE and CONSOLE_PBKDF_SALT, keep them in a local .env that stays out of git, and start the console on MinIO's Docker network. Create a separate console admin user instead of using the root account.

Then ask me which app and bucket to set up. Create a policy limited to that bucket, a user with that policy and an access key for the user. Test the key both ways. It must list, write, read and delete a test object in its bucket, and it must be denied on another bucket, on the admin API and when creating a bucket. Remove the test object afterwards.

Ask before enabling versioning, adding lifecycle rules or deleting anything. Never print secrets in full, and store them where I tell you. Report the console URL, what passed, what failed and how to stop the console.

05 / Was bleibt

Warum Sie das interessieren könnte

Wenn Sie MinIO bereits betreiben

Die Admin-Seiten sind nicht für immer verloren. OpenMaxIO v1.7.6 bringt Benutzer, Richtlinien und Zugriffsschlüssel zurück, sobald Sie die beiden Korrekturen von oben anwenden. Bringen Sie ausserdem Ihren Server auf das letzte MinIO-Release vom Oktober 2025. Etwas Neueres wird es nicht geben.

Wenn Sie Systeme bauen, die viele Daten erzeugen

Sie kennen das. Erzeugte Dateien stapeln sich auf dem Laptop, bis die Festplatte voll ist, und jedes Projekt erfindet seinen eigenen Weg, sie irgendwohin zu kopieren. Ein S3-Speicher auf Ihrem NAS gibt jedem Projekt dieselbe Schnittstelle. Der Code spricht mit einem Bucket und einem Schlüssel, und Versionierung und Ablauf werden zu Einstellungen statt zu Skripten.

Für eine neue Installation würden wir heute zuerst Garage oder SeaweedFS ansehen, weil das Open-Source-Projekt von MinIO archiviert ist. Der Code, den Sie gegen die S3-API schreiben, bleibt in jedem Fall derselbe.