Skip to content

homebrew

Installs Homebrew (Linuxbrew) into /home/linuxbrew/.linuxbrew, owned by an unprivileged account.

Applied by setup_new_machine.yml and, on its own, by setup-homebrew.yml.

Homebrew refuses to run as root, and this fleet connects as root. So every install step escalates downwards — become_user: {{ homebrew_user }} — which needs no password in that direction. The reverse, connecting as the account and escalating to root, is what the rest of the fleet does; here it is inverted.

That account must already exist. The role checks first and says so rather than failing inside a become:

Homebrew must be installed as an unprivileged account, and unknown224 does not exist on
<host>. Create it first — ansible-playbook playbooks/setup-admin-user.yml --limit <host>

In setup_new_machine.yml that is guaranteed: the first play creates the account before any role runs.

The official installer refuses to run as root, and calls sudo itself for the parts that need privilege — which prompts for a password and hangs an unattended run unless the account has passwordless sudo (admin_user_sudo_nopasswd is false by default, deliberately).

This role sidesteps that: it creates the prefix as root, owned by the account, then clones into it as the account. Nothing inside the install needs privilege, so nothing prompts.

VariableDefaultEffect
homebrew_user{{ admin_user }} → unknown224Account Homebrew is installed as and owned by
homebrew_prefix/home/linuxbrew/.linuxbrewInstall prefix
homebrew_repohttps://github.com/Homebrew/brewSource repository
homebrew_prerequisitesbuild-essential, procps, curl, file, git, aclInstalled with apt, as root
homebrew_updatetruePull the repo on every run
homebrew_configure_shelltrueWrite /etc/profile.d/homebrew.sh
homebrew_profile_script/etc/profile.d/homebrew.shWhere activation is written
homebrew_packages[]Formulae to install once brew works
Terminal window
ansible-playbook ... playbooks/setup-homebrew.yml -e '{"homebrew_packages": ["gh", "fd"]}'
  • acl is in the prerequisites for Ansible, not Homebrew. Without it, a task that becomes an unprivileged user from root cannot hand over its temp files and fails with Failed to set permissions on the temporary files.
  • The clone is not shallow, on purpose. With depth: 1 Homebrew reports its version as Homebrew >=4.3.0 (shallow or no git repository) and brew update will not work against it. The full history costs a few hundred MB and a slower first clone.
  • A non-standard homebrew_prefix forfeits the bottles. Homebrew ships prebuilt binaries only for the standard prefix; anywhere else, every formula compiles from source. The role asserts that brew --prefix matches what was asked for.
  • The first run is slow — it fetches Homebrew’s portable Ruby. Budget minutes and roughly 1 GB free under /home. Later runs are quick, and a converged host reports changed=0.
  • Activation is a login-shell thing. /etc/profile.d is not read by ssh host <cmd>, cron or systemd; call /home/linuxbrew/.linuxbrew/bin/brew directly there, or use bash -lc.

Against test-lxc (Debian 13), connecting as root and installing as unknown224: brew --version reports a real version, brew --prefix matches, su - unknown224 -c brew works through the profile snippet, and a second run is changed=0.