99

I have a Mac that is shared between two engineers. Both have separate user accounts. Both need to run brew update and brew install... occasionally.

How do I set this up without getting errors like: /usr/local must be writable!?

Yeah, I could have UserA take over the permissions of /usr/local every time he wants to use brew (and same with UserB), but that seems like a lot of unnecessary trouble.

Harald Nordgren
  • 11,693
  • 6
  • 41
  • 65
Jon Gunter
  • 1,864
  • 2
  • 15
  • 21
  • 10
    The answer marked as accepted is ill-advised and poor security practice. @user4815162342 answer below is much more sensible. – Wes Modes Mar 06 '18 at 17:31
  • 4
    Please accept a different answer, or at least un-accept the accepted answer, so that it can be deleted. – Greenonline Jul 27 '21 at 15:46

9 Answers9

120

You can also change the group permissions to admin or another group that both of your users are in:

chgrp -R admin /usr/local
chmod -R g+w /usr/local

Original source: https://gist.github.com/jaibeee/9a4ea6aa9d428bc77925

UPDATE:

In macOS High Sierra you can't change the owner, group or permissions of /usr/local. So you have to change the group and permissions of the subfolders:

chgrp -R admin /usr/local/*
chmod -R g+w /usr/local/*

UPDATE September 2018, High Sierra 10.13.6

  1. Determine the path of the brew prefix, ie. the path that will be used to store files related to working with homebrew
  2. Check that all users on the system who need access to brew are in the admin group
  3. Optional Add a user to the admin group if a user needs access to brew

    Will require access / privileges to use the sudo command

  4. Set the brew prefix path to be recursively owned by the admin group
  5. Set the brew prefix path to be recursively writable by all users who are in the admin group
  6. Verify the permissions of the brew prefix
  7. brew

echo $(brew --prefix)
echo $(groups $(whoami))
sudo dseditgroup -o edit -a $(whoami) -t user admin
sudo chgrp -R admin $(brew --prefix) 
sudo chmod -R g+rwX $(brew --prefix)
ls -lah $(brew --prefix)
deizel.
  • 11,042
  • 1
  • 39
  • 50
user4815162342
  • 1,532
  • 2
  • 13
  • 15
  • If you are viewing this in the deep future, or on some weird configuration, and the updated solution doesn't work, check if `$(brew --prefix)` returns `/usr/local`, and if not - use that value instead. – maniexx Sep 02 '18 at 22:35
  • 1
    I had to add `sudo` otherwise I would get `Operation not permitted` error messages – FooBar Sep 10 '18 at 10:19
  • The second line should be `echo $(groups $(whoami))`. – Antonin Décimo Oct 14 '18 at 09:36
  • 15
    Do not add `sudo` to avoid `Operation not permitted`. add `/*` to the command, ie: `sudo chgrp -R admin $(brew --prefix)/*`. [source](https://github.com/Homebrew/brew/issues/3228) – Juan José Ramírez Nov 05 '18 at 17:10
  • 4
    This solution is sound, however some packages might refuse to work with such permissions. Postgres, for example, throws: `FATAL: data directory "/usr/local/var/postgres" has group or world access DETAIL: Permissions should be u=rwx (0700).` – Leonel Galán Nov 14 '18 at 20:03
  • 2
    This answer could use some cleaning up... What is the code block at the end? Another update? – n1000 Feb 11 '19 at 17:26
  • 3
    zsh also complains when owner and perms are tweaked like this; compaudit errors every new shell. – jerryb Mar 06 '19 at 11:02
  • 1
    Alternatively, you could give the group the same privileges that the user has: `chmod -R g=u /usr/local/*` (as long as you have already set the group to admin). – Suragch May 12 '19 at 02:04
  • While group permissions look like a viable option, there are several details where they will break: Without sticky bits, subdirectories created by `brew install` runs may result in sub-sub-directories unwritable for the shared group, or the wrong group altogether. Conflicting installtions within Homebrew (they do exist) may break the others installation, and selective versioning may cause dependency lockups. If no curation is available or desired, I'm afraid to each user his own instance might be the ugly answer. – Tatjana Heuser Jul 24 '21 at 18:20
  • When trying to update with another user than the one that initially installed it, i get an error, that there are no git directories found. Is there a way to fix this (i.e. git init)? – Julian Dec 08 '22 at 10:27
  • @JuanJoséRamírez I don't think adding `/*` is going to help if some of the files under your `$(brew --prefix)` were created and are owned by another user (likely the case on a multiple-user system where different users have run `brew install …`). You can't make changes to a file that has owner-only-write and is owned by someone else… but that's exactly what we need to do in order to set the group permissions. So in most cases, `sudo` is absolutely the correct thing to do here, and the only solution (save completely wiping your brew prefix dir and starting over, but that would also req `sudo`). – Slipp D. Thompson May 01 '23 at 20:04
  • Downvoted because the answer suggests making all users who need to use `brew` admins. See the docs-supported answer from @Val [below](https://stackoverflow.com/a/70012833/3042770). – Evgenii Jun 16 '23 at 16:05
105

Every answer that tries to hack permissions, or use sudo is wrong.

Do not use sudo and do not share a single brew installation across user accounts.

The correct answer per the Homebrew docs is to use zero or one global brew installation on a machine, and for all other users install a local version of brew.

This is especially important on Mac, but works on Linux too.

This can be done by one of the following approaches

  1. Git approach: doing a git checkout of the source repo
  2. Untar-anywhere approach: expanding a tarball into some directory – owned by your user

Git approach

For the git approach you'll need to clone brew.

Arbitrarily choosing my user home directory for my checkout:

cd $HOME
git clone https://github.com/Homebrew/brew.git
./brew/bin/brew tap homebrew/core

Untar-Anywhere Approach

As documented at docs.brew.sh, run this command in your home directory, which will create ~/brew.

cd $HOME
mkdir brew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C brew

Finishing up

For either installation method, you'll need to change your PATH to prefer the new brew bin directory, adding something like this to your shell's dot file.

export PATH=$HOME/brew/bin:$PATH >> ~/.zshrc # or ~/.bashrc

Then running this to reload and test

exec $SHELL
which brew # see that brew is found in your path

Since this is a new installation, you have to install all your desired brew packages (again).

jerryb
  • 1,425
  • 1
  • 9
  • 11
  • 2
    This worked for me, but the repo must be cloned with https in my case. `cd $HOME; git clone https://github.com/Homebrew/homebrew-core.git; git clone https://github.com/Homebrew/brew.git` – Carlos Pinzón Nov 14 '19 at 11:38
  • thanks @CarlosPinzón ! the https URLs instead of the ssh URLs are much easier to use for most. I have updated my answer. – jerryb Dec 08 '19 at 10:32
  • @jerryb Hi, `~/brew/bin/brew --version` outputs `Homebrew 2.5.2-65-gfc6ef72 Homebrew/linuxbrew-core N/A`. Shouldn't `homebrew-core` be installed inside the `~/brew/Library/Taps/homebrew/` directory ? – SebMa Oct 01 '20 at 08:23
  • @SebMa yes i think you are right and there was a change, I'll update my answer. For "brew --version", my working system which I created recently returns `Homebrew 2.5.4\nHomebrew/homebrew-core (git revision 647782; last commit 2020-10-08` – jerryb Oct 08 '20 at 11:01
  • @jerryb Why did you remove the `Homebrew/homebrew-core` component ? I believe you should this command : `git clone https://github.com/homebrew/homebrew-core $HOME/brew/Library/Taps/homebrew/homebrew-core` to you procedure – SebMa Oct 08 '20 at 13:29
  • @sebma after your feedback which reported issues with the homebrew-core checkout, i could not directly reproduce the problem problem report, but i re-tested my steps with a new home directory on Catalina, excluding the the homebrew-core checkout. Everything seems to work correctly, and brew checked out the homebrew-core itself into the correct location on first operation. I concluded that something changed in the internals so the extra checkout is not required. I am open to the fact that this is incorrect: do you have a reproduce-able set of steps that demonstrates the problem you suspect? – jerryb Oct 11 '20 at 05:26
  • @jerryb I use Linux. Have you tested it on Linux ? – SebMa Oct 11 '20 at 06:47
  • @SebMa i'm confused, isn't brew specific to Mac? – jerryb Oct 17 '20 at 06:59
  • @jerryb It's also compatible with Linux since 2019 – SebMa Oct 17 '20 at 11:43
  • @SebMa I've updated my answer based on your feedback. I did test this on Ubuntu 16 and homebrew-core now appears to be automatically checked out first time running brew. – jerryb Nov 04 '20 at 08:14
  • @jerryb Here, I'm using Ubuntu 18.04 LTS. I needed to run a `./brew/bin/brew update` (before running `./brew/bin/brew -v`) for homebrew to tap the homebrew/core. But actually, it does not work every time. I just removed the `./brew/` directory and re-done the `git clone ...` and the `./brew/bin/brew update` but this time it didn't tap the homebrew/core. I think this step has to be manually after the git clone : `./brew/bin/brew tap homebrew/core`. Can you please add the `brew tap ...` command to your procedure ? – SebMa Nov 04 '20 at 15:30
  • 1
    @SebMa done, let me know if I got it right – jerryb Dec 24 '20 at 22:21
  • 4
    from the docs `Pick another prefix at your peril!` – Clintm Jan 22 '21 at 16:12
  • 5
    I finally found a use case where my solution does not work well: nvm hates to be outside of /usr/local/bin but its been years with this solution with zero trouble otherwise. – jerryb Apr 04 '21 at 02:48
  • @jerryb Really good answer, but it mixes up folders, sometimes it's `brew` and sometimes `homebrew`, so maybe you can update the answer a bit to remove any confusion ;) Thanks Jerry! – Sliq Nov 04 '21 at 11:00
  • 1
    @Sliq thanks so much for the feedback. You are right and I believe I have edited and fixed the issue you mention. – jerryb Nov 14 '21 at 23:08
  • 2
    One should however mention that this approach is unsupported and you can never raise any concern in their bug tracker, they will be closed without even looking at the issue, says the documentation https://docs.brew.sh/Installation#untar-anywhere-unsupported, https://docs.brew.sh/Installation#multiple-installations-unsupported and it comes with one downside, that everything that you install will be compiled and no standard bottles can be used, because the bottles assume the standard brew location /usr/local. – user637338 Mar 20 '23 at 08:41
46

Install homebrew for each user

According to the brew documentation you can install it inside each User Home folder

That way all packages are going to stay inside your user folder, and will not be visible or affect other users. As a good side effect if you delete that user, no trash is left behind on your system. So system wide pollution is minimised.

This comes at the cost of more storage being used, if you install the same package for multiple users. Just something to be aware if you have a very small SSD.

Instructions

  1. If you currently have brew installed on your system globally, I recommend uninstalling brew first. (You can see where brew is installed running which brew)

  2. If you don't have Command Line Tools installed, you have to run this first:

    xcode-select --install
    
  3. Open terminal and Run:

    • MacOS Catalina 10.15 or newer:
      cd $HOME
      mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew
      echo 'export PATH="$HOME/homebrew/bin:$PATH"' >> .zprofile
      
    • MacOS Mojave 10.14 or older:
      cd $HOME
      mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew
      echo 'export PATH="$HOME/homebrew/bin:$PATH"' >> .bash_profile
      
  4. Close the Terminal window

  5. Open Terminal again, and run this to ensure your installation is correct:

    brew doctor
    
  6. Done!


Disabling auto update

This is not required I also find useful to disable brew to update all packages before every time you install something.

  • MacOS Catalina 10.15 or newer
    echo 'HOMEBREW_NO_AUTO_UPDATE=1' >> $HOME/.zprofile
  • MacOS Mojave 10.14 or older
    echo 'HOMEBREW_NO_AUTO_UPDATE=1' >> $HOME/.bash_profile
Vitim.us
  • 20,746
  • 15
  • 92
  • 109
  • 4
    That is the only answer that actually 1. installs brew only for this current user and 2. correctly sets the PATH so it's useable also after reboot! Thanks Vitim! – Sliq Dec 17 '20 at 02:58
  • As noted on the Homebrew installation documentation: "_do yourself a favour and install to /usr/local on macOS Intel, /opt/homebrew on macOS ARM, and /home/linuxbrew/.linuxbrew on Linux_" and goes on to say "_Pick another prefix at your peril!_" so I'm not sure this method would be advisable. – Benji Apr 13 '21 at 14:42
  • 2
    I like this answer as it keeps brew local to the user (not shared). But `brew doctor` returns the following. Is this expected? `Warning: Your Homebrew's prefix is not /usr/local. Some of Homebrew's bottles (binary packages) can only be used with the default prefix (/usr/local). You will encounter build failures with some formulae. Please create pull requests instead of asking for help on Homebrew's GitHub, Twitter or any other official channels. You are responsible for resolving any issues you experience while you are running this unsupported configuration.` – hdsenevi Jul 04 '21 at 05:20
  • as great as this answer is, it does have its limitations. 1. if using a multi user homebrew install isolated within a $HOME dir for particular install, and one wants to use such install with github actions, ie. homebrew's `test-bot` will be unable to perform actions with the standard setup. this can be seen as a limitation of the actions runner provided by homebrew, but using a vanilla github actions with test-bot brew needs to be installed in `/usr/local` – ipatch Aug 17 '21 at 19:27
  • 1
    I like that you include the xcode step for git, and the brew doctor. – jerryb Dec 12 '21 at 23:17
15

EDIT: Please use the answer by Vitim, it's the correct one :)

Hacky workaround solution for macOS Mojave 10.14

This is a edited version of user4815162342's answer, which didn't work for me out-of-the-box.

  1. In System Preferences, go to Users & Groups, click the lock symbol in the bottom left corner to unlock user/group creation, then create a new group called brew-usergroup. Add all users who work with brew to the group (like in the attached screenshot from a german macOS).

enter image description here

  1. In terminal, do this:

     echo $(brew --prefix)
     echo $(groups $(whoami))
     sudo dseditgroup -o edit -a $(whoami) -t user brew-usergroup
     sudo chgrp -R brew-usergroup $(brew --prefix)/*
     sudo chmod -R g+rwX $(brew --prefix)/*
     ls -lah $(brew --prefix)
    

Note that this doesn't change rights of brew folders anymore (like in other answers), it changes subfolders/files of brew folders. brew install should now work fine without errors.

Sliq
  • 15,937
  • 27
  • 110
  • 143
  • 3
    this looks like as an elegant solution, but unfortunately it's not better than simply doing the same for admin (without creating an extra group). either way, i'm getting these error messages: cp: utimes: /usr/local/Cellar/readline/.: Operation not permitted cp: chmod: /usr/local/Cellar/readline/.: Operation not permitted – Tamas Kalman Mar 13 '19 at 05:50
  • 1
    I agree, I think the best would be to push the brew developers to fix this entire issue at the core! – Sliq Mar 13 '19 at 10:26
  • I just now had the same `cp: utimes: /usr/local/Cellar/XXX/.: Operation not permitted` error, found that it was caused by a folder with group "staff" instead of "admin", although I ran `chgrp -R admin /usr/local/`... strange, but fixed :) `find /usr/local/ -not -group admin -ls` may be of help... – DrPsychick Sep 04 '19 at 20:13
11

The above works fine, but if you want new files to automatically inherit those permissions, set an ACL which gets inherited (otherwise only the user that pours a bottle can remove it). Found hints how to do this here: https://gist.github.com/nelstrom/4988643

As root run once (assuming all users of group "admin" should have access):

cd /usr/local
/bin/chmod -R +a "group:admin allow list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,directory_inherit" Homebrew Caskroom Cellar bin
/usr/bin/chgrp -R admin Homebrew Caskroom Cellar bin
/bin/chmod -R g+rwX Homebrew Caskroom Cellar bin
ls -lae .

the -e on ls shows ACLs.

Update: now I use specific directories (see above) as it failed (sth. like out of memory)

DrPsychick
  • 384
  • 4
  • 7
  • might want to prepend `/bin/chmod` for those of us who installed GNU coreutils for macOS – ipatch Nov 07 '19 at 03:09
  • This is great! I'm trying it out for a bit. Curious why you may not have included some of the other ACLs, like `writesecurity`(which appears to be required to, say, make a script executable). I ended up doing `chmod -R +a 'group:admin allow readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,list,search,add_file,add_subdirectory,delete_child,read,write,append,execute,file_inherit,directory_inherit' *` against all `/usr/local` directories after a fresh Homebrew install. – Mattie Sep 05 '21 at 03:21
10

Homebrew is not designed to be used by different Unix users. From the FAQ:

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

The chmod solution is not viable unless you ensure that every newly created file in the Homebrew prefix also has the group write permission, which is not the case with the default umask – or unless you keep running that chmod command every time a program writes to the Homebrew prefix.

Maintaining separate Homebrew installations for each user do sort the permissions issues but will create a number of other issues, which is why it's not recommended by Homebrew:

However do yourself a favour and use the installer to install to the default prefix. Some things may not build when installed elsewhere. One of the reasons Homebrew just works relative to the competition is because we recommend installing here. Pick another prefix at your peril!


To ease the official recommendation of using a dedicated account for Homebrew, you can use sudo to easily impersonate that user account. Assuming you named that user homebrew:

sudo -H -u homebrew brew update
  • -H makes sure HOME is set to the homebrew user home (e.g. /Users/homebrew) so that Homebrew can do its housekeeping there.
  • -u homebrew tells sudo to impersonate the homebrew user account instead of the default of root.
Val
  • 323
  • 3
  • 8
  • 1
    I need the `-i` flag as well. Setting an alias helps for regular use: `alias brew='sudo -Hiu $HOMEBREW_MAIN_USER brew'` – dijonkitchen Apr 01 '22 at 15:04
  • Could not use `-i` flag to [sudo without password](https://stackoverflow.com/a/52484243/456536). – Míng Sep 22 '22 at 11:49
  • 1
    @Val Curious as to why you haven't linked your https://www.codejam.info/2021/11/homebrew-multi-user.html article. – P i Nov 16 '22 at 16:25
4

Here is the official answer of one of the Homebrew maintainers.

Create a third admin user (e.g. homebrew), then:

sudo chown -R homebrew:admin /usr/local/*

Then all further write operations (i.e. install, update, upgrade, etc.) should be done by everyone else as that user, by the power of su or sudo, depending on your preference:

su homebrew -c 'brew update'

In this respect, there's only one difference between Homebrew and a system package manager: the former lets you decide which user to grant ownerships to, while the latter fixes it as root.

My own suggestion

Suppose you already have an admin user niki who owns the /usr/local/* dir and you are logged in as another admin user niki_at_work. In this case you don't necessarily need to create a new account for homebrew.

  1. Create ~/brew.sh with these contents:
#!/bin/bash
comm="brew $@"
su niki -c "$comm"
  1. chmod +x ~/brew.sh
  2. Add this alias to .zshrc or equivalent: alias brew="~/brew.sh"

Now you can brew from niki_at_work like always (it will ask for niki's password):

brew update
brew install swiftlint

If you do want to use a dedicated admin user for brew ex. brewadmin you should first chown brew dirs: sudo chown -R brewadmin:admin /usr/local/*

Ville
  • 1,182
  • 10
  • 16
pokidyshev
  • 53
  • 2
  • 1
    I don't see evidence that the person who replied to you is an official maintainer. But this strategy is also similar to a tool I used to maintain: https://github.com/brewdo/brewdo It worked well for most cases, but I stopped maintaining it some years back due to occasional incompatibilities and the fact that Homebrew itself uses OS sandboxing to stop changes outside the Homebrew installation—an early reason why I started this tool. In any event, based on experience, I think this answer is overly simplistic and may work most of the time, but may be problematic down the road. – Mattie Sep 04 '21 at 13:10
  • Regarding the comment "I don't see evidence that the person who replied to you is an official maintainer" by @Mattie: the commentor on the externally linked GitHub issue is in fact listed as part of the Homebrew org on GitHub as of August 2023: https://github.com/orgs/Homebrew/people – Ville Aug 21 '23 at 11:22
1

The best solution is to add a sudoers record to allow unprivileged user 'joe' to execute any 'brew' related command as the administrative user.

Create a file at /etc/sudoers.d/joe with following content:

joe ALL=(administrator) NOPASSWD: /usr/local/bin/brew

Then you can run brew like this:

sudo -Hu administrator brew install <smth>
Sergey Papyan
  • 400
  • 2
  • 4
  • That sounds dangerous. What if 'joe' creates a Homebrew package that does bad things? – Suragch May 12 '19 at 02:19
  • 4
    @suragch I guess you can't avoid that danger if you're allowing joe to install any system wide packages not only this way, but in any way. – Sergey Papyan May 12 '19 at 02:26
-3

The above solutions didn't work for me. But running the command below worked for me.

sudo chown -R $(whoami) $(brew --prefix)/*

Source: https://github.com/Homebrew/brew/issues/3228#issuecomment-333858695

ernestkamara
  • 75
  • 1
  • 9