reeve
_ __ ___ _____ _____
| '__/ _ \/ _ \ \ / / _ \
| | | __/ __/\ V / __/
|_| \___|\___| \_/ \___|
RunCloud, scaled down — for localhost.
A local web development stack manager for macOS. Think RunCloud, scaled down, localhost-only, open source: provision and manage web servers, per-vhost PHP versions, SSL, and DNS — from one CLI and TUI.
Written in Rust. It does not bundle servers or PHP; it orchestrates Homebrew-installed ones and manages them as your-user launchd services (no sudo).

Why
The classic macOS + Homebrew + Apache + mod_php setup links exactly one
PHP version at a time. reeve drops mod_php for PHP-FPM, one master per
version, so two vhosts can run two different PHP versions simultaneously —
the thing the old switcher-script approach can't do.
Highlights
- Per-vhost PHP version — each vhost picks its PHP; versions run side by side.
- Per-version PHP tuning —
memory_limit, upload sizes, OPcache, FPM pool, timezone, and a one-click Xdebug toggle (off/debug/profile), all without hand-editingphp.ini. - Multiple backends behind one abstraction: Caddy, Apache, nginx (OpenLiteSpeed is wired but unsupported on macOS — see below).
- Run several servers at once, on different ports, managed independently.
- Background services — install/start/stop MySQL, MariaDB, PostgreSQL, Redis, memcached, Mailpit via Homebrew + launchd, alongside the web stack.
- Framework presets —
laravel,wordpress,symfony,grav,drupalset the right docroot + rewrites automatically; or point a vhost at an upstream dev server as a reverse proxy (Vite, Node, …). - Directory parking (Valet-style) — park
~/Sitesand every subfolder auto-serves as<folder>.test, framework auto-detected, no per-project setup. Odd folder names are slugified to valid hostnames automatically. - Trusted local SSL via a shared mkcert CA —
https://app.testwith no warnings. - Wildcard DNS for one or more TLDs (
.test,.localhost,.lan, …) via a user-run dnsmasq (no root daemon). - Default site — optionally serve a catch-all from your sites root (with an
optional framework preset), so
http(s)://localhostworks without a vhost. Each server can override its default root, or share the global sites root. logs+doctor— tail any service's log, and a one-shot health check of the whole stack (Homebrew, servers, FPM, services, DNS, certs, ports).- Honest, port-aware status —
runningonly when the port is actually bound; otherwiseloaded, not bound,:<port> held by <process>, orcrashed.start/restartpreflight the ports and name any foreign process holding them. - TUI dashboard with live status — mouse-clickable, scrollable panels (a dedicated Parked panel for parked sites) — plus a scriptable CLI on the same engine.
- No sudo for day-to-day use; servers bind 80/443 as your user via launchd.
Requirements
- macOS (built and tested on macOS 26 "Tahoe", Apple Silicon)
- Homebrew — reeve will offer to install it if missing
Installation
Homebrew (recommended)
From crates.io
(The crate is published as reeve-cli because reeve is already taken on
crates.io; the installed binary is still reeve.)
From source
Pre-built binaries
Download from GitHub Releases.
Updating
update detects how reeve was installed. Homebrew and cargo installs print the
matching upgrade command (brew upgrade reeve / cargo install --force reeve-cli); a plain binary (e.g. under ~/.local/bin) is downloaded and
replaced in place. Quit and relaunch reeve afterwards to pick up the new binary.
Quick start
Add a database and a mail catcher, tune PHP, or use a framework preset:
&& &&
Or park a directory so every project in it just works, no per-site setup:
One-time DNS + trust setup so *.test resolves system-wide and certs are trusted:
dns setup writes the root-owned /etc/resolver/<tld> files itself via the
native macOS admin dialog — no manual sudo needed. In the TUI, press D.
Then https://app.test just works in the browser.
TUI
Run with no arguments to open the dashboard:
reeve
reeve [.test ✓ resolving] ● health (L logs)
┌ Servers ──────────────────────────────────────────────┐
│ › caddy caddy :80/:443 ● running │
│ apache apache :8080/:8543 ● running │
│ nginx nginx :9090/:9443 ○ stopped │
├ Vhosts ───────────────────────────────────────────────┤
│ https://app.test caddy 8.3 ~/Sites/app │
├ Parked (37) [1–4 of 37] ──────────────────────────────┤
│ › https://blog.test caddy 8.3 ~/Sites/blog │
│ https://shop.test caddy 8.3 ~/Sites/shop │
├ PHP ──────────────────────────────────────────────────┤
│ 8.3★ ● running 🐛debug 8.4 ● running │
├ Services ─────────────────────────────────────────────┤
│ › mysql :3306 ● running │
│ mailpit :8025 ● running │
└───────────────────────────────────────────────────────┘
enter start · x stop · r restart · n new · s settings · L log · q quit
Navigation is shared across panels; the key bar is context-aware (it shows the keys for the focused panel).
| Key | Action |
|---|---|
↑ ↓ ← → / hjkl |
Move selection within the focused panel |
PgUp PgDn / Home End |
Page / jump through a long list (e.g. Parked) |
| mouse | Click a row to focus + select it; wheel scrolls the panel under the cursor |
Tab / Shift-Tab |
Switch panel (Servers → Vhosts → Parked → PHP → Services) |
n |
New — server / vhost / PHP install / service (per focused panel) |
e |
Edit — server (ports, backend, default site) / vhost / PHP extensions |
Enter |
Start server or service / restart FPM master |
x · r |
Stop · restart (Servers, Services) |
s |
Per-backend settings (Servers) / per-version PHP settings (PHP) |
X |
Cycle Xdebug off→debug→profile (PHP panel) |
d |
Set default PHP version (PHP panel) |
p |
Park a directory / manage parks (Vhosts or Parked panel) |
L |
View the focused item's log |
? |
Full doctor health report |
T |
Install the mkcert CA into your trust store (ssl trust) |
Del / Backspace |
Remove the focused item (with confirm) |
a · v |
Apply · validate all configs |
c |
Preferences (TLDs, sites root, default backend) |
D |
Set up wildcard DNS (admin prompt) |
q / Esc |
Quit |
The new-vhost wizard (n on Vhosts) covers framework presets and a
reverse-proxy target, so everything the CLI does is reachable from the TUI.
Commands
| Command | Description |
|---|---|
init |
Detect Homebrew, scaffold config/state |
php install <ver> |
Install (or adopt) a PHP version + FPM master |
php list / php use <ver> |
List versions / set the default for new vhosts |
php cli [ver] |
Switch the terminal php (via the ~/.reeve/bin shim); omit to show current |
php ext add|remove|list <ver> [name] |
Manage extensions per version (pecl) |
php settings <ver> / php set <ver> <key> <value> |
Show / tune php.ini, OPcache, FPM pool |
php xdebug <ver> off|debug|profile |
Toggle Xdebug for a version |
server add <backend> [--http N --https N] [--default-site] [--root <dir>] [--preset <fw>] |
Add caddy|apache|nginx (optionally a catch-all default site; --root overrides its docroot, else the global sites root) |
server start|stop|restart|list|remove <name> |
Manage a server (independent) |
vhost add <host> --root <dir> --php <ver> --server <name> [--ssl] [--preset <fw>] [--proxy <url>] |
Add a vhost |
vhost list|remove <host> |
Manage vhosts |
service add|start|stop|restart|remove|list <kind> |
Manage databases / redis / memcached / mailpit |
park add <dir> --server <name> --php <ver> [--tld T] [--ssl] |
Auto-serve every subfolder as <folder>.<tld> |
park list|remove <dir> |
Manage parked directories |
apply |
Render generated configs + reconcile running services |
validate |
Run every backend's native config test |
logs [<target>] [-n N] [--follow] |
View or tail a service's log |
doctor |
Diagnose the whole stack (brew, servers, FPM, services, DNS, certs, ports) |
update [--check] |
Self-update to the latest GitHub release (--check only reports) |
ssl mint <host> / ssl trust / ssl untrust / ssl status / ssl ca |
Local certificates: mint one, install/remove the mkcert CA in the trust store, or show its state |
dns setup / dns status |
Wildcard *.test DNS |
CLI PHP version
php cli <ver> switches the php on your terminal — the modern replacement for
the old sphp script. Instead of running brew link (which mutates Homebrew's
global state and fights keg-only versions), reeve keeps a shim directory of
symlinks at ~/.reeve/bin (php, pecl, phpize, php-config, phar) and
just repoints them. Switching is instant and Homebrew is never touched.
The shim needs to be on the front of your PATH once. reeve init and
reeve php cli offer to add it to your shell profile automatically — or add it
by hand:
# ~/.zshrc (or ~/.bash_profile)
doctor warns if ~/.reeve/bin isn't ahead of Homebrew on your PATH. To revert
entirely, remove that line from your profile — nothing else changes.
How it works
state.toml is the single source of truth (servers, PHP versions, vhosts).
reeve renders native configs (Caddyfile, httpd vhosts, nginx server
blocks, FPM pools) into generated/, then reconciles launchd services to match.
You never hand-edit generated files — you edit state via the CLI/TUI and apply.
~/Library/Application Support/reeve/
config.toml · state.toml · generated/ · certs/ · logs/
~/.reeve/run/ # sockets (kept space-free, short)
OpenLiteSpeed
OLS has no official macOS build, and the only community Homebrew tap fails to
compile its (2022-deprecated) admin_php dependency against the current macOS
SDK. The backend is wired in and will activate if a working OLS install appears,
but it is not usable on macOS today. Use Caddy, Apache, or nginx.
Development
The repo is a Cargo workspace; the crate lives in crates/reeve. CI runs
fmt + clippy + tests on macOS and Linux; tagged v* pushes build release
binaries, publish reeve-cli to crates.io, and update the Homebrew tap.
License
MIT © 2026 Andy Miller