Chapter 2 of 14

Install, and What Needs Root

Installing takes two commands and about a minute. This chapter spends longer than that explaining what they do, because a tool that asks for your administrator password has an obligation to be legible — and because Grove's answer here is unusual.

The problem

Developer tools ask for sudo casually. An installer wants it, a package manager wants it, a helper daemon wants it forever. Each time the justification is something small and true — a port, a system file — and the real cost never appears on the invoice: every bug in that process is now a root bug on your machine.

You should know what you are agreeing to. So here it is, line by line.

The two commands

sudo grove init       # config, root CA, a PHP build, resolver + trust
sudo grove install    # the background service

grove init does four things. It writes config.toml. It creates a local certificate authority and adds it to your system trust store — that is chapter 4, and it is the part that needs your password. It downloads a PHP build. And it writes /etc/resolver/test, a small file that tells macOS to send every .test lookup to Grove instead of to the internet.

grove install writes the launchd unit that keeps the daemon running and restarts it if it dies. On Linux it writes a systemd unit instead.

The daemon that serves your sites is not root

Here is the part worth reading twice, because it is the opposite of what the ports suggest.

Grove serves on 80, 443 and 53, and binding a port below 1024 requires privilege. The obvious conclusion — and the one Grove itself drew for its first several versions — is that the daemon must be root. It does not, because of one distinction: binding a privileged port needs root; serving on one does not.

A socket is a file descriptor. Whoever binds it needs privilege; whoever holds it afterwards needs none. And your machine already has a root process whose entire job is starting other processes. So launchd binds 53, 80 and 443 while it is root, then starts Grove as you and hands the already-listening descriptors over.

grove doctor
✓ privileges     http_port=80, elevated=false, sockets from the
                 service manager: tcp/53, tcp/80, tcp/443, udp/53

elevated=false is your name on that line. From its first instruction, the process handling every request to your sites is running as you — and so is everything it starts: PHP-FPM, PostgreSQL, MySQL, Redis, the Vite server, Composer.

What still needs root is one-off and visible: writing the unit file, writing /etc/resolver, and adding the CA to the trust store. All three happen inside the two commands above, while you are watching, having typed sudo on purpose. Nothing that happens while a request is being served is privileged.

Learn to run doctor

grove doctor is the command to reach for before you start guessing, and it is worth running once now while everything is fresh, so you know what healthy looks like.

It checks the things that are true or false rather than matters of opinion: the daemon is running, the ports are listening, the resolver file exists and points at Grove, the CA is trusted by the system, the Grove home is owned by you and not world-writable, your certificates have not expired. Each line is a claim you could verify by hand; the value is that it verifies all of them in a second.

The one upgrade note. Grove updates its binary without rewriting the launchd unit, so a machine installed before socket activation existed keeps working exactly as it did — the daemon simply binds the ports itself. Running sudo grove install once is the deliberate step that switches a machine over. It also hands the Grove home to you in the same step, which is why it is one command and not a surprise permission error on Monday.

What you learned

  • Two privileged commands, and both are legible. init writes config, CA, resolver; install writes the service unit.
  • Binding a privileged port needs root; serving on one does not. launchd binds and hands the descriptor over.
  • The daemon runs as you — and so does everything it starts. elevated=false in doctor is the proof.
  • What still needs root is one-off and visible, and happens while you are watching.
  • Run doctor once while healthy, so you know what healthy looks like.
Next: in Chapter 3 your first site — and why a folder becoming a URL with no configuration is a different thing from a shortcut.