Skip to content

release: v1.17.1 — fresh-install fixes for macOS services, FPM images, certs, shims#228

Merged
geodro merged 13 commits intomainfrom
fix/macos-services-not-started-after-fresh-install
Apr 20, 2026
Merged

release: v1.17.1 — fresh-install fixes for macOS services, FPM images, certs, shims#228
geodro merged 13 commits intomainfrom
fix/macos-services-not-started-after-fresh-install

Conversation

@geodro
Copy link
Copy Markdown
Owner

@geodro geodro commented Apr 20, 2026

Summary

Patch release bundling 12 fixes, mostly around fresh-install reliability on macOS and ARM Linux.

  • Fresh macOS installs now start services and PHP FPM containers correctly: .container files are written for all unit types so pre-pull can find the image, FPM plists register even when builds fail, and image pulls run before the DNS resolver override so registry traffic uses clean system DNS.
  • .env-referenced services auto-start before php/composer/laravel commands, dashboard preset installs auto-start the new container, and certificates are no longer reissued when they already exist.
  • Shims use os.Executable() instead of a hardcoded ~/.local/bin/lerd path so Homebrew installs work; lerd share skips VPN/tunnel interfaces when picking the LAN IP; fnm download picks the arm64 archive on ARM Linux; test runs no longer hang because the completion installer now skips when invoked from a .test binary.

See CHANGELOG.md for per-fix detail.

geodro added 13 commits April 20, 2026 13:33
On macOS, ensureServiceQuadlet called WriteContainerUnitFn which only
writes the launchd plist — no .container file in QuadletDir. When
startRestoredServices later calls quadletImage() it reads from QuadletDir
and gets "", skipping the pre-pull step. podman run then has to auto-pull
large images (mysql, postgres, etc.) on a brand-new Podman Machine, which
often fails or times out, leaving services in a "failed" state.

Switch ensureServiceQuadlet to WriteQuadletDiff, which writes both the
.container file (so quadletImage can find the image) and the launchd plist
via AfterQuadletWriteFn. startRestoredServices can now pre-pull images
before starting containers.
…after fresh install

ensureFPMQuadletTo wrote the launchd plist only after a successful image
build. If the build failed, no plist was written, so the PHP version was
invisible to lerd start's ensureImages() and would never be retried.

Move WriteFPMQuadlet before BuildFPMImageTo so the version is always
registered in lerd status (shown as 'image missing') even on build failure,
and lerd start can rebuild it automatically on the next run.

Also call ensureImages() in the install autostartOn block to retry any
failed PHP FPM builds (and service image pulls), then start the PHP FPM
containers whose images are now available.
Image pulls (nginx:alpine, DNS images) were happening after ConfigureResolver
on macOS, meaning registry lookups ran while the system DNS was already
redirecting .test queries through lerd-dns. Pull all images first so the
unmodified system resolver handles registry traffic.
…/lerd

php/composer/laravel shims were always written with ~/.local/bin/lerd,
breaking them when lerd is installed via Homebrew at /opt/homebrew/bin/lerd.
Use os.Executable() so shims point to whichever binary ran lerd install.
IssueCert always re-ran mkcert even when the cert and key files were
present, causing lerd setup to regenerate certificates on every run.
ensureServicesForCwd only kicked in for paused sites, so on a fresh
install services like mysql were not running and migrations would fail.
Now starts any .env-referenced services that are not running regardless
of pause state, silently for active sites.
… pre-pulled

WriteContainerUnitFn on macOS writes only the launchd plist, leaving no
.container file. quadletImage() reads the .container file to discover the
image name for pre-pull; when it doesn't exist the image is never pulled
and the container fails to start on a fresh install.

Switch every unit-write call site (FPM, custom services, custom containers,
UI server, MCP server) from WriteContainerUnitFn to WriteQuadletDiff, which
writes both the .container file and the plist on macOS.
InstallPresetByName only wrote the quadlet without starting the container,
leaving newly added services (mongodb, etc.) stopped after installation.
The UI now starts dependencies then the service itself, matching the
behaviour of clicking Start on the dashboard.
…lver

ensureImages() was called after ConfigureResolver() on macOS, meaning all
registry pulls happened through the overridden .test resolver. Move the
call to before the DNS block so all image pulls use the clean system DNS.
detectPrimaryLANIP() returned the VPN tunnel IP (utun*/tun*) when a VPN
was active, making the lan:share URL unreachable from other LAN devices.
Now validates the dial result against the interface name and falls back to
scanning physical interfaces, skipping utun/tun/tap/wg/container ones.
installCompletion ran os.Executable() which returned the test binary
path in CI; running the test binary with 'completion bash' args caused
it to hang for the full 10-minute timeout. Skip when the binary has a
.test suffix.
fnm-linux.zip is x86_64 only; ARM machines need fnm-arm64.zip.
mkcert already handled this correctly — apply the same arch check to fnm.
@geodro geodro changed the title fix(install): services not started after fresh macOS install release: v1.17.1 — fresh-install fixes for macOS services, FPM images, certs, shims Apr 20, 2026
@geodro geodro merged commit 02f2a99 into main Apr 20, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant