Start, Stop & Autostart
Day-to-day lifecycle commands for the entire lerd stack: DNS, nginx, PHP-FPM containers, services, workers, the Web UI, the watcher, and the system tray.
You don't need to run lerd start after installing
lerd install already starts everything for you on first run: it boots lerd-dns, lerd-nginx, the lerd-watcher, and the system tray. Services like MySQL or Redis are started on demand the first time something needs them (lerd service start, lerd init, or lerd env). Reach for lerd start only after a lerd stop, a reboot without autostart enabled, or after you've manually killed containers.
Commands at a glance
| Command | Stops | Starts |
|---|---|---|
lerd start | nothing | DNS, nginx, watcher, tray, all PHP-FPM containers in use, services that were running before stop, queue / schedule / reverb / messenger workers, stripe listeners, Web UI |
lerd stop | All containers and workers above except lerd-dns. Leaves the watcher, Web UI, and the DNS forwarder alone. | nothing |
lerd quit | Everything lerd stop does, plus the DNS forwarder, Web UI, watcher, and tray. macOS: also stops the Podman Machine VM. | nothing |
lerd stop is the everyday "give my laptop back its CPU" command. lerd quit is a full shutdown: use it before a reinstall, a system reboot without autostart, or when you really want lerd out of the way.
lerd start
lerd startWalks the install in dependency order:
- Pre-flight: checks for port conflicts on 53, 80, and 443; refuses to start if another process is bound.
- Rebuilds or pulls any missing container images (e.g. after a
podman rmior a podman cleanup). - Boots core:
lerd-dns,lerd-nginx,lerd-watcher. - Boots every PHP-FPM container that has at least one site referencing its version. Unused PHP versions stay stopped.
- Boots all installed services that are not marked as manually paused (see Manually stopped services for the pause-state contract).
- Restores per-site workers (
lerd-queue-*,lerd-schedule-*,lerd-reverb-*,lerd-messenger-*, custom workers) and stripe listeners (lerd-stripe-*) from theworkerslist saved in each site's.lerd.yaml. - Starts the Web UI (
lerd-ui) and the system tray.
A live spinner shows the per-unit progress. If a single SSL vhost references a missing certificate file, lerd switches that site back to HTTP automatically and continues; one broken cert no longer blocks the whole nginx start.
After a reinstall
If you ran lerd uninstall and then reinstalled, worker units and service quadlets are recreated by lerd start from each site's .lerd.yaml. Sites with a committed .lerd.yaml come back fully wired up. Sites without one need their workers restarted manually.
Deleted project directories are auto-cleaned
lerd-watcher removes sites from sites.yaml whenever their project directory disappears on disk. Two paths do this:
- Instant: fsnotify on every parked directory (configured via
lerd park). When a direct subdirectory gets deleted, the corresponding site is unlinked within milliseconds. - Periodic: every 30 seconds the watcher sweeps the full site registry (parked and non-parked) and removes any site whose path no longer exists. The UI refreshes via the sites eventbus so the dashboard reflects the removal without a manual page reload.
Both paths skip Ignored: true sites, those are explicitly parked by the user (e.g. via lerd unpark leaving a tombstone) and must not be reaped.
lerd stop
lerd stopStops everything lerd start started except the Web UI, watcher, tray, and the lerd-dns forwarder; those keep running so the dashboard stays reachable to bring lerd back up.
A few important details:
- The DNS forwarder stays up.
lerd-dnsis treated as install-level plumbing: the system resolver keeps pointing.testat it untillerd uninstall, so stopping it would leave the resolver aimed at a dead port and make.testlookups stall. It is only torn down bylerd quitorlerd uninstall. - Manually paused services are remembered. If you stopped Mailpit earlier with
lerd service stop mailpit, thenlerd stop+lerd startwill not bring Mailpit back. The pause flag survives the cycle. - Pinned services start anyway. A
lerd service pin <name>overrides auto-stop logic; pinned services are always started bylerd startregardless of which sites are active. - Worker state is preserved. Workers running before
lerd stopare restarted by the nextlerd start; workers you manually stopped stay stopped.
lerd quit
lerd quitThe full off-switch:
- Runs everything
lerd stopdoes. - Stops
lerd-ui(Web UI). - Stops
lerd-watcher. - Kills the system tray process.
- Stops the
lerd-dnsforwarder. Unlikelerd stop, quit is a full teardown, so it takes DNS down too. The watcher is stopped first (step 3) because it is the only thing that would restartlerd-dns. - macOS only: stops the Podman Machine VM.
After lerd quit there are no lerd processes left running. On macOS the Podman Machine VM is also shut down, so lerd start will bring it back up on the next run. This is the right command before a reinstall, a system reboot, or before pulling a major update.
The system tray's Quit Lerd menu item calls lerd quit.
lerd machine reset (macOS)
lerd machine reset # asks for confirmation first
lerd machine reset --yes # skip the promptRecreates the Podman Machine VM. Reach for it only when lerd start reports a container-storage error such as getting graph driver info ... overlay: invalid argument, which happens after the macOS host is shut down ungracefully while the VM is still running and leaves the VM's container storage corrupt. See Troubleshooting → Podman Machine overlay-storage error.
The command stops the VM, removes it (podman machine rm -f), and re-initialises it. Your data is preserved: lerd bind-mounts every database and site directory to the host, not into the VM, so only the VM's container storage and images are discarded. Images are rebuilt automatically on the next lerd start.
lerd start already tries to self-heal
On macOS, lerd start detects this exact error and attempts an automatic recovery first (remount the VM's storage, rebuild the stale containers, retry once). lerd machine reset is the manual fallback for when that recovery isn't enough. This command is macOS-only; Linux runs podman natively with no VM.
Autostart on login
Lerd can boot itself every time you log in. Autostart is a single switch over every lerd-owned systemd user unit on the machine:
- the dashboard (
lerd-ui.service), project watcher (lerd-watcher.service) and system tray (lerd-tray.service) - every container quadlet (
lerd-mysql,lerd-nginx,lerd-redis,lerd-postgres,lerd-dns,lerd-php*-fpm,lerd-mailpit,lerd-meilisearch,lerd-minio,lerd-rustfs) - every per-site worker, queue, schedule, horizon, reverb, and stripe-listen unit
lerd autostart enable # boot lerd on every login
lerd autostart disable # stop booting on loginlerd autostart enable runs systemctl --user enable on the full set; lerd autostart disable runs the matching disable. The dashboard's enabled state is the canonical "is autostart on" indicator surfaced by the UI and tray.
The same toggle also appears in the System Tray menu under Autostart; see System Tray.
The tray unit (lerd-tray.service) is wired to graphical-session.target and so requires a desktop environment that reaches that target on login: GNOME, KDE Plasma, and any compositor launched through uwsm (Omarchy's Hyprland setup included). Bare Hyprland / Sway / i3 launched without uwsm won't autostart the tray; see System Tray, Autostart for the workaround. Every other lerd unit uses default.target and is unaffected.
From the Web UI
The dashboard at http://127.0.0.1:7073 has Start and Stop buttons in the header:
- Start appears only when one or more core services (DNS, nginx, PHP-FPM) are not running. Clicking it calls
lerd startvia the API. - Stop is always visible while lerd is running. Clicking it calls
lerd stop. - The tray's Quit Lerd menu item calls
lerd quit(full shutdown including the UI).
These map one-to-one to the CLI commands above, no special UI-only behaviour.
Status & verification
lerd statusShows a live snapshot: DNS reachability, nginx, PHP-FPM containers, watcher, host tools, services, certificate expiry, and LAN exposure. Run it after every lerd start to confirm everything is healthy. See Troubleshooting if anything is reported as down.
The [Tools] section lists the host binaries lerd manages (Composer, fnm, mkcert) with their installed versions, and flags any that differ from the versions lerd currently pins. The same information appears in the web UI under System > Tools, where the pending version on a tool's card is a button that updates that one tool. Apply pending updates from the terminal with:
lerd tools:updateThe pins are read from a manifest that is cached for a day, so a newly published pin can take that long to show up on its own. "Check for updates" on the Tools page re-reads it immediately, and a tool that falls behind also raises an update_available notification.
Tools that are already at their pinned version are left untouched, and tools that are deliberately absent (fnm on an nvm-managed setup) are skipped. A tool whose version shows as unknown, for example Composer after a composer self-update, is re-downloaded at the pinned version.
Each tool is an independent download, so one that cannot be updated does not stop the others. The run carries on and closes with a count of what failed.
Where the pins come from
The pinned versions live in internal/tools/tools.yaml. A copy is embedded in the binary as the offline fallback, and the published one is fetched before a download so a bad pin can be fixed without a release.
Because that file reaches every install without going through a release, a published pin is only honoured when its URL points at a host lerd downloads tools from: getcomposer.org, github.com, and GitHub's asset hosts. Anything else falls back to the embedded pin. Set LERD_TOOLS_HOSTS to a comma-separated list to allow additional hosts, and LERD_TOOLS_URL to fetch the manifest from somewhere other than GitHub.
A pin may also carry a digests map alongside assets, giving the sha256 of each platform's asset:
tools:
mkcert:
version: v1.4.4
url: https://github.com/FiloSottile/mkcert/releases/download/{version}/{asset}
assets:
linux/amd64: mkcert-{version}-linux-amd64
digests:
linux/amd64: 6d31c65b03972c6dc4a14ab429f2928300518b26503f58723e532d1b0a3bbb52Where a digest is given the download is checked against it and rejected on a mismatch. The field is optional, so a manifest without it installs exactly as before, and binaries that predate the field ignore it. Either way a download is written to a temporary file and moved into place only once it is complete, so a failed or rejected download never replaces a working binary.
Cheat sheet
| Situation | Command |
|---|---|
| Just installed lerd | Nothing, lerd install already started everything |
Coming back to your laptop after lerd stop | lerd start |
| Reboot, autostart disabled | lerd start |
| Reboot, autostart enabled | Nothing, happens automatically |
| Free up CPU / RAM during a heavy build | lerd stop |
| Full shutdown before a reinstall | lerd quit |
lerd start fails with an overlay / graph-driver storage error (macOS) | lerd machine reset |
| Verify everything's healthy | lerd status |
| Update Composer / fnm / mkcert to their pinned versions | lerd tools:update |
| Uninstall a service entirely (data preserved) | lerd service remove <name> |
| Uninstall and wipe data | lerd service remove <name> --purge |
| Reinstall a service in place | lerd service reinstall <name> |
| Reinstall with fresh data + reprovision linked sites | lerd service reinstall <name> --reset-data |