<p>There's a particular kind of friday-evening restlessness where you don't want to finish anything — you just want to tinker. That's how Grove started. Not as a grand plan, but as a small itch: every time I set up a new Mac, I'd lose an afternoon to Homebrew, Composer, dnsmasq, a PHP version dance, and a <code>*.test</code> domain that worked on one machine and sulked on another.</p><p>I love Laravel Valet. I've paid for Herd. But I kept bumping into the same three walls:</p><ul><li><p>Valet is elegant and feather-light — and macOS-only, leaning on a pile of Homebrew packages.</p></li><li><p>Herd ships clean static binaries — but it's closed, won't let me load my own PHP extensions, and tucks databases and mail behind a Pro license.</p></li><li><p>Docker is wonderful and also way too much machinery just to open <code>blog.test</code>.</p></li></ul><p>So one evening I asked the dangerous question: how hard could it be?</p><p>The answer, pleasantly, was: hard enough to be fun, easy enough to finish.</p><h2>The why: own the whole stack, depend on nothing</h2><p>The guiding rule for Grove became almost stubborn:</p><blockquote><p>Zero external dependencies. If Grove needs it, Grove ships it.</p></blockquote><p>No Homebrew. No system dnsmasq. No OpenSSL. Not even PHP needs to be on your machine. That sounds extreme until you realize it's also kind — to your future self on a fresh laptop, and to teammates on Linux and Windows who just want the same thing to work.</p><p>In practice that meant building the boring-but-load-bearing pieces directly into a Rust core:</p><ul><li><p>an embedded DNS resolver that answers <code>*.test</code> with loopback (and politely refuses everything else),</p></li><li><p>an HTTP/HTTPS reverse proxy that routes by Host header,</p></li><li><p>a tiny FastCGI client to talk to PHP-FPM,</p></li><li><p>a local certificate authority that mints per-site HTTPS certs on demand.</p></li></ul><p>No nginx, no mkcert, no vendor of system tools. Just one daemon.</p><h2>The how: one daemon, two thin clients</h2><p>The shape is simple. A single long-running daemon binds the privileged ports (53, 80, 443) and supervises everything. The CLI and the GUI are both thin clients that talk to it over a local socket. They're always in parity because they speak the exact same JSON-RPC.</p><p>From a clean machine to a running site looks like this:</p><pre><code class="language-bash">sudo grove init        # config, root CA, a static PHP build, resolver + trust
grove start            # the daemon binds 53/80/443
grove park ~/Code      # every subfolder becomes &lt;name&gt;.test
</code></pre><p>That's it. Open <code>https://blog.test</code> and it's there — HTTPS padlock and all — without ever editing <code>/etc/hosts</code>.</p><pre><code class="language-text">$ grove list
SITE                     DRIVER     PHP   NODE  HTTPS  URL
blog.test                static     8.4   —     no     http://blog.test
inside-next.test         laravel    8.4   22    yes    https://inside-next.test
frontend.test            proxy      —     —     no     http://frontend.test
</code></pre><p>Want HTTPS and a pinned PHP version for one project? One line each:</p><pre><code class="language-bash">grove secure inside-next
grove isolate inside-next 8.3
</code></pre><hr><h2>The part that surprised me: it grew</h2><p>Here's where the project stopped being "a router" and started being a little ecosystem.</p><p><strong>PHP, plural.</strong> Grove downloads self-contained static PHP-FPM builds — not one, but as many as you like:</p><pre><code class="language-text">$ grove php install 8.5
  resolving latest 8.5 for macos-aarch64…
  downloading php-8.5.7-fpm-macos-aarch64.tar.gz…
  installed: PHP 8.5.7 (fpm-fcgi)
</code></pre><p><code>otool -L</code> on that binary shows only macOS's own system libraries. Nothing from Homebrew. It just runs.</p><p><strong>Databases that install themselves.</strong> This was the line I didn't want to cross — and then crossed happily. You shouldn't have to <code>brew install mysql</code> to use Grove. So Grove fetches and supervises them itself:</p><pre><code class="language-text">$ grove service install postgres &amp;&amp; grove service start postgres
$ grove service install redis    &amp;&amp; grove service start redis
$ grove service list
SERVICE      CATEGORY       INSTALLED  RUNNING   PORT
PostgreSQL   Database       yes        yes       5432
MySQL        Database       no         no        3306
Redis        Cache &amp; Queue  yes        yes       6379
</code></pre><p>PostgreSQL and MySQL come as portable binaries; Redis is compiled from source on install (it's famously dependency-light). Then — my favorite small touch — Grove writes the <code>.env</code> for you:</p><pre><code class="language-bash">$ grove env shop
# Generated by `grove env` — Grove's bundled services
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=shop
DB_USERNAME=root
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
</code></pre><p><strong>New projects, from scratch.</strong> And because we're already here:</p><pre><code class="language-text">$ grove new shop --kind laravel
  preparing PHP CLI…
  preparing Composer…
  creating Laravel project (composer)…
  ✓ created shop at ~/Code/shop
</code></pre><p>Bundled PHP CLI, bundled Composer, a fresh Laravel app, auto-detected and served at <code>shop.test</code>. No global installs.</p><h2>A face for it</h2><p>The CLI is the engine, but a good dev tool should also be nice to look at. So Grove has a Tauri + Svelte GUI sharing the Tokyo Night palette of the rest of my toolkit — a dashboard of sites, one-click HTTPS toggles, per-site PHP/Node dropdowns, a Mailpit-style mail viewer, a log reader, and panels to install PHP/Node and start databases.</p><p>It lives in the macOS menu bar, too. Close the window and Grove tucks itself up by the clock; click the little orange node-graph and it's back. And from the first proper release onward, it quietly checks for updates and offers a one-click Install &amp; restart — cryptographically signed, of course.</p><h2>What I learned</h2><p>Three small lessons stuck with me:</p><ol><li><p><strong>"Zero dependencies" is a feature you feel.</strong> The moment <code>grove init</code> set up a working <code>.test</code> site with HTTPS on a machine with nothing installed, the whole project justified itself.</p></li><li><p><strong>Bundling is mostly logistics.</strong> Downloading a portable Postgres or compiling Redis isn't magic — it's a catalog, a tarball, an <code>initdb</code>, and a supervised child process. The trick is doing it consistently.</p></li><li><p><strong>The blank white screen will humble you.</strong> (Ask me how long I stared at an empty Tauri window before realizing the webview was politely trying to reach a dev server that didn't exist.)</p></li></ol><p>Grove is v0.1.1 today — macOS-first, Linux and Windows on the way. It's not trying to replace Docker for your microservice opera. It's the small, warm thing that gets a <code>*.test</code> site running in under five minutes and then gets out of your way.</p><p>If that sounds like your kind of friday evening, the grove is open. 🌳</p><pre><code class="language-text">$ grove gui
✓ Grove GUI launched
</code></pre>