Homebrew auf dem Mehrbenutzer-Mac

Zwei Personen nutzen denselben Mac. Beide sind Administratoren. Eine von beiden hat Homebrew installiert, und die andere kann jetzt nichts mehr installieren:

Error: /opt/homebrew is not writable. You should change the ownership
and permissions of /opt/homebrew back to your user account:
  sudo chown -R $(whoami) /opt/homebrew

Der vorgeschlagene Befehl ist in dieser Situation falsch. Er verschiebt das Problem nur auf das andere Konto, und nächste Woche stehen Sie wieder hier, nur mit vertauschten Namen.

Im Folgenden heißen die beiden Menschen alice (uid 501) und bob (uid 502), beide in der Gruppe admin. Homebrew 6.0.20, Apple Silicon, Installationsverzeichnis /opt/homebrew (in Homebrews Dokumentation „prefix“, abfragbar mit brew --prefix).

Was der Installer tatsächlich hinterlässt

Die Rechtestruktur ist nicht kaputt, sondern genau das, was der offizielle Installer erzeugt. Er führt chmod ug=rwx über eine Liste von Unterverzeichnissen aus, macht also aus 755 ein 775, lässt aber das Installationsverzeichnis selbst und das Git-Checkout auf 755:

Pfad Modus Eigentümer:Gruppe Zweiter Admin darf schreiben?

/opt/homebrew

755

bob:admin

Nein

/opt/homebrew/.git

755

bob:admin

Nein

/opt/homebrew/Library

755

bob:admin

Nein

/opt/homebrew/docs, completions, manpages, package

755

bob:admin

Nein

/opt/homebrew/bin

775

bob:admin

Ja

/opt/homebrew/Cellar, Caskroom

775

bob:admin

Ja

/opt/homebrew/{etc,lib,opt,share,var,include,sbin,Frameworks}

775

bob:admin

Ja

Ein zweiter Admin kann über die Gruppe admin in den Cellar und nach bin schreiben, aber nicht ins Installationsverzeichnis selbst und nicht ins Git-Checkout: Die stehen auf 755, und dort hilft Gruppenmitgliedschaft nicht. Deshalb scheitert es nicht sauber, sondern halb und verwirrend.

Die Dokumentation beschreibt dabei eine Einheitlichkeit, die der Installer gar nicht herstellt. docs/FAQ.md behauptet, die Rechte seien durchgehend 0755, unter macOS wie unter Linux; die 775-Zeilen oben sagen etwas anderes.

Homebrew unterstützt das nicht

Bei gemeinsam genutzten Installationen hilft Ihnen das Projekt nicht. docs/Support-Tiers.md führt sie unter Unsupported configurations auf, in einer Liste mit Beowulf-Clustern und Toastern, und die FAQ nennt Homebrew an zwei Stellen „primarily designed for single-user use“. Früher stand dort noch ein Ausweg:

If you need to run Homebrew in a multi-user environment, consider creating a separate user account specifically for use of Homebrew.

Dieser Satz stand wirklich einmal in der offiziellen Dokumentation. Und er ist verschwunden. Commit db70c09e1a vom 01.01.2026, „docs: clarify Homebrew is not recommended for multi-user environments“, hat beide Sätze gestrichen, in denen die Empfehlung stand, und sie durch eine reine Feststellung der Einschränkung ersetzt. Das war eine Rücknahme und keine Umformulierung: Für Mehrbenutzer-Setups empfiehlt das Projekt jetzt gar nichts mehr.

Wer heute nach dieser Empfehlung sucht, bekommt sie von Suchergebnissen und KI-Zusammenfassungen trotzdem noch als aktuelle Dokumentation. Löschungen sind in zwischengespeicherten Kopien unsichtbar. Verlässlich ist nur, was mit Ihrer Installation ausgeliefert wird: /opt/homebrew/docs und die vollständige Historie in /opt/homebrew/.git.

Der eigene Service-Account ist damit undokumentiert, aber unwidersprochen. Er hält genau die Form ein, für die Homebrew gebaut und getestet ist: einen einzigen Benutzer, dem alles gehört.

Warum nicht die naheliegenden Alternativen

group-write plus vererbbare ACLs. Wirklich bequem, und es funktioniert. chmod -R g+w allein reicht nicht: Das nächste brew install legt Dateien unter umask 022 an, und der andere Benutzer ist binnen Tagen wieder ausgesperrt. Sie brauchen macOS-ACLs mit file_inherit und directory_inherit, dazu git config --system --add safe.directory /opt/homebrew, weil das Repository jemand anderem gehört. Das ist exakt die Konfiguration, die Support-Tiers.md als nicht unterstützt führt, und Homebrews eigener Code, der Rechte geradezieht, setzt chmod 755. Jede künftige brew-Version kann Ihre Arbeit also wieder einreißen.

Ein eigenes Installationsverzeichnis pro Benutzer unter ~/homebrew. Auf Apple Silicon fatal. Bottles werden ausschließlich für /opt/homebrew gebaut, bei einem abweichenden Pfad wird daher alles aus dem Quelltext kompiliert. Die FAQ formuliert es als „Pick another prefix at your peril!“

Nichts tun. Ein Mensch besitzt Homebrew, die andere Person führt die installierten Programme aus (die sind für alle les- und ausführbar) und bittet um Installationen. Kein Risiko, voll unterstützt, mäßig lästig.

Der Service-Account kostet ein sudo pro Installation und hält die Maschine dauerhaft in einer Konfiguration, die Homebrew unterstützt. Prüfen Sie vor der Entscheidung, wie groß der Umzug überhaupt ist: Die Installation, aus der dieser Text stammt, enthielt drei Formulae und ein Cask, womit der gesamte Umzug aus zwei chown-Befehlen bestand. Genau das gab den Ausschlag gegen die ACL-Variante.

Die Lösung: ein eigener Service-Account

Vorher: bob gehört /opt/homebrew, alice darf deshalb in bin und Cellar schreiben, aber nicht ins Installationsverzeichnis selbst und nicht ins Git-Checkout. Nachher: ein versteckter Service-Account besitzt das gesamte Verzeichnis, und beide Menschen installieren über sudo.
Figure 1. Besitzverhältnisse vorher und nachher: ein Mensch besitzt das Installationsverzeichnis, gegenüber einem Service-Account, durch den beide Menschen hindurchgehen

Ein einziges Konto, _homebrew, hinter dem kein Mensch steht, besitzt das gesamte Installationsverzeichnis. Menschen rufen brew über sudo -u auf. Keine ACLs, kein group-write, kein safe.directory, kein Ärger mit der umask, und die Besitzverhältnisse verschieben sich nie.

Der führende Unterstrich ist Apples Konvention für Service-Accounts (www, _mysql). Der praktische Nutzen: Die übliche Methode, menschliche Benutzer aufzulisten, dscl . -list /Users | grep -v '^', filtert das Konto automatisch heraus. Homebrew hat den Kontonamen nirgends fest verdrahtet, Sie können ihn also frei wählen.

„Kein Login“ sind vier unabhängige Stellschrauben

Hier geht es am häufigsten schief.

Stellschraube Wirkung

IsHidden 1 und HiddenUsersList

Blenden das Konto aus Anmeldefenster und schnellem Benutzerwechsel aus, wirken aber erst ab der nächsten Abmeldung. Rein kosmetisch; das Konto bleibt voll nutzbar.

Nie ein Passwort gesetzt

Keine Anmeldung möglich. sudo -u braucht das Passwort des Zielkontos nicht, das kostet also nichts.

UserShell /usr/bin/false

Keine interaktive Shell. Bricht sudo -u …​ -i.

uid < 500

Wird automatisch aus dem Anmeldefenster ausgeblendet.

Die Falle: sudo -u X -i startet ausdrücklich die Login-Shell von X. Ausgerechnet der naheliegendste Weg, ein Konto für Logins zu sperren, nämlich die Shell auf /usr/bin/false zu setzen, zerstört genau den Aufruf, auf dem diese Lösung beruht.

Dieser Text nimmt deshalb eine echte Shell (/bin/zsh), kein Passwort und IsHidden 1. Anmelden kann sich trotzdem niemand, weil es gar keine Credentials gibt, und sudo -u _homebrew -i liefert ein korrektes HOME und PATH. Wer stattdessen bei /usr/bin/false bleiben will, muss -i durch -H ersetzen: Sonst zeigt HOME auf das Home-Verzeichnis des Aufrufers, und brew schreibt seinen Cache dorthin statt nach /Users/_homebrew.

Wählen Sie eine uid oberhalb von 500

Der Bereich unter 500 ist nicht für Dritte reserviert, sondern gehört Apple, und er füllt sich. Auf einer aktuellen Darwin-25.6-Installation liegen Apples Service-Accounts dicht zwischen 1 und 308, dazu _oahd, der Rosetta-2-Daemon, allein auf 441. Auf den dichten Block beschränkt Apple sich also nicht.

Eine uid-Kollision erzeugt keinen sauberen Fehler, denn der Kernel sieht immer nur die Zahl. Zwei Directory-Einträge mit derselben uid gelten für jede Rechteprüfung als dieselbe Identität, und ls -l zeigt den Namen an, der zuerst aufgelöst wird. Ein künftiges macOS-Update könnte damit irgendeinem Systemdienst Schreibrechte auf Ihr gesamtes Installationsverzeichnis von Homebrew geben, mit einem völlig rätselhaften Symptom. Geringe Wahrscheinlichkeit, unangenehme Folgen.

Der einzige Vorteil von unter 500 ist das automatische Ausblenden aus dem Anmeldefenster, und das erledigt IsHidden 1 ohnehin. Nehmen Sie 700 oder irgendeinen anderen Wert über 500, der von Ihren menschlichen Konten frei ist.

Zwei weitere Voraussetzungen

Wenn Sie Casks installieren, muss das Konto in der Gruppe admin sein. /Applications gehört root:admin bei drwxrwxr-x, ein Service-Account mit der Primärgruppe staff kann dort also kein App-Bundle anlegen oder ersetzen. Der Preis dafür: admin gewährt über Apples %admin ALL=(ALL) ALL nominell sudo-Rechte. Entschärft wird das dadurch, dass sich das Konto mangels Passwort gar nicht authentifizieren kann. Es sind außerdem dieselben Rechte, die der Mensch, der den Installer ausgeführt hat, ohnehin schon hatte.

Das Konto braucht außerdem ein echtes Home-Verzeichnis. Apples Daemons bekommen oft /var/empty, Homebrew dagegen braucht ein beschreibbares $HOME für ~/Library/Caches/Homebrew. Daran scheitert, wer das Konto besonders minimal halten will.

Umsetzung

Vorab prüfen. Alle drei Befehle sollten nichts ausgeben:

dscacheutil -q user  -a name _homebrew
dscacheutil -q group -a name _homebrew
dscacheutil -q user  -a uid  700

Konto anlegen und einrichten. Ohne -password wird nie ein Passwort gesetzt, das Konto kann sich also nicht authentifizieren:

sudo sysadminctl -addUser _homebrew -fullName "Homebrew" -UID 700 \
     -shell /bin/zsh -home /Users/_homebrew

sudo mkdir -p /Users/_homebrew
sudo chown -R _homebrew:staff /Users/_homebrew
sudo chmod 755 /Users/_homebrew

# uid 700 liegt über der Grenze von 500, ab der automatisch ausgeblendet wird
sudo dscl . -create /Users/_homebrew IsHidden 1
sudo defaults write /Library/Preferences/com.apple.loginwindow \
     HiddenUsersList -array-add _homebrew

# Gruppe admin, damit Casks nach /Applications schreiben dürfen
sudo dseditgroup -o edit -a _homebrew -t user admin

sysadminctl ersetzt die achtteilige dscl . -create-Folge, die dafür sonst herumgereicht wird. Dass kein Passwort gesetzt wurde, bestätigt dscl . -read /Users/_homebrew AuthenticationAuthority: Dort darf kein ShadowHash auftauchen.

Note

Die verbreitete Anleitung nennt nur IsHidden. Auf Darwin 25.6 verschwand _homebrew aus dem Anmeldefenster erst, nachdem IsHidden 1, der Eintrag in HiddenUsersList und eine Abmeldung zusammengekommen waren. Ob einer der beiden Schalter allein genügt, wurde nicht getrennt geprüft; ohne die Abmeldung wirkte keiner von beiden. Wer gleich nach den Befehlen ins Anmeldefenster schaut, hält sie deshalb für wirkungslos.

Installationsverzeichnis übergeben, dazu alle App-Bundles bereits installierter Casks:

sudo chown -R _homebrew:admin /opt/homebrew

# eine Zeile je bereits installiertem Cask
sudo chown -R _homebrew:admin /Applications/Obsidian.app

Dann der Alias, für jeden menschlichen Benutzer:

echo "alias brewer='sudo -u _homebrew -i /opt/homebrew/bin/brew'" >> ~/.zshrc

Bewusst nicht brew genannt, damit lesende Befehle unprivilegiert bleiben. Absoluter Pfad statt PATH-Auflösung, weil /etc/paths.d/homebrew von path_helper angehängt wird und hinter /usr/bin landen kann.

Note

Für das neue Konto müssen Sie vermutlich kein PATH einrichten: Legt der Installer /etc/paths.d/homebrew an, findet jede Login-Shell brew über path_helper bereits, auch die aus sudo -u _homebrew -i. Prüfen Sie das, bevor Sie dem Service-Account eine .zprofile verpassen.

Prüfen

id _homebrew              # uid=700(_homebrew) ... 80(admin)
sudo dscl . -read /Users/_homebrew IsHidden   # 1
defaults read /Library/Preferences/com.apple.loginwindow HiddenUsersList   # (_homebrew)
ls -ld /opt/homebrew      # _homebrew  admin
brewer --version          # fragt nach IHREM Passwort, nicht dem von _homebrew
brewer update             # kein "dubious ownership" mehr
brewer doctor             # sauber
brew list                 # funktioniert weiterhin ohne sudo
su - _homebrew            # abgelehnt: es gibt keine Credentials

brewer install wget && wget --version | head -1 && brewer uninstall wget

Zwei Mechanismen sollte man nachprüfen statt voraussetzen. Homebrews Schutz gegen root-Aufrufe in Library/Homebrew/brew.sh greift wirklich nur bei root:

check-run-command-as-root() {
  [[ "${EUID}" == 0 || "${UID}" == 0 ]] || return

sudo -u _homebrew setzt reale und effektive uid auf 700 und nicht auf 0, kommt also durch. sudo brew wird rundheraus abgelehnt.

Und Dateien, die unter sudo -u _homebrew entstehen, gehören _homebrew und nicht root. sudo setzt beide uids auf das Zielkonto; root ist nur die kurze Zwischenstation, die den Wechsel vollzieht. Da nur _homebrew schreibt, bleiben die Besitzverhältnisse einheitlich, ganz ohne group-write und ohne ACLs.

Zuletzt sind die Caches in den beiden Home-Verzeichnissen nur noch Ballast:

rm -rf ~/Library/Caches/Homebrew

Der Alltag damit

brewer installiert, das nackte brew liest. Nehmen Sie brewer für install, uninstall, upgrade, update, cleanup, tap und doctor. Nehmen Sie das nackte brew für list, search, info, outdated, deps und --prefix. Die brauchen keine Rechte: Das Installationsverzeichnis ist für alle lesbar und der Cache jedes Benutzers liegt in dessen eigenem Home. Das erspart die Passwortabfrage bei genau den Befehlen, die Sie am häufigsten ausführen. Dass brew doctor als Mensch jetzt /opt/homebrew als nicht beschreibbar meldet, ist dabei so gewollt; die aussagekräftige Antwort gibt brewer doctor.

Führen Sie installierte Programme niemals über brewer aus. Das Programm läuft dann als _homebrew und schreibt seinen Zustand nach /Users/_homebrew. brewer gpg --gen-key legt einen privaten Schlüssel an einer Stelle ab, die Sie später mühsam suchen. brewer colima start legt die VM und ihren Socket unter /Users/_homebrew/.colima an, wo Ihr eigenes docker sie nicht findet.

sudo fragt nach Ihrem eigenen Passwort, nicht nach dem des Zielkontos. An dieser Asymmetrie stolpern die meisten, und genau sie macht ein Konto ganz ohne Passwort möglich. sudo merkt sich die Authentifizierung rund fünf Minuten, eine Serie von Befehlen fragt also nur einmal.

Einen weiteren Admin aufzunehmen kostet nichts. Jedes Mitglied von admin ist über %admin ALL=(ALL) ALL bereits berechtigt. Tragen Sie den Alias in dessen Shell-Konfiguration ein, mehr nicht.