Documentation
¶
Index ¶
- Constants
- Variables
- func AccessFeedListenAddr() string
- func AccessLogTarget() string
- func AccessSocketPath() string
- func AddProjectWorker(dir, name string) error
- func AddSite(site Site) error
- func AddWorktreeDB(e WorktreeDBEntry) error
- func AddWorktreeLAN(e WorktreeLANEntry) error
- func ApproveSiteCommand(siteName, command string) error
- func BackupBinaryFile() string
- func BackupTrayFile() string
- func BackupVersionFile() string
- func BackupsDir() string
- func BinDir() string
- func BrowserHostsFile() string
- func CertsDir() string
- func ClearStopped() error
- func ComposerHasPackage(dir, pkg string, extraSections ...string) bool
- func ConfigDir() string
- func ContainerHostsFile() string
- func ContainsUnitInjectionChars(s string) bool
- func ControlSocketPath() string
- func CountSitesUsingPHP(version string) int
- func CountSitesUsingService(name string) int
- func CustomServiceExists(name string) bool
- func CustomServicesDependingOn(name string) []string
- func CustomServicesDir() string
- func DashboardProxyPath(name string) string
- func DataDir() string
- func DataSubDir(name string) string
- func DefaultPresetConnectionURL(name string) string
- func DefaultPresetDashboard(name string) string
- func DefaultPresetEnvVars(name string) []string
- func DefaultPresetNames() []string
- func DetectFramework(dir string) (string, bool)
- func DetectFrameworkForDir(dir string) (string, bool)
- func DetectMajorVersion(projectDir, frameworkName string) string
- func DetectPublicDir(dir string) string
- func DevtoolsAssetsDir() string
- func DevtoolsBridgeTarget() string
- func DevtoolsCollectorFile() string
- func DevtoolsIniFile() string
- func DevtoolsWorkersFlagFile() string
- func DnsmasqDir() string
- func DumpsAssetsDir() string
- func DumpsBridgeFile() string
- func DumpsBridgeTarget() string
- func DumpsEnabledFlagFile() string
- func DumpsIniFile() string
- func DumpsListenAddr() string
- func DumpsListenNetwork() string
- func DumpsSocketPath() string
- func EffectiveTLD() string
- func ErrorPagesDir() string
- func FPMPortsFor(version string) []string
- func FamilyOf(svc *CustomService) string
- func FamilyOfName(name string) string
- func FrameworksDir() string
- func FrankenPHPVersions() []string
- func GetConsoleCommand(projectDir string) (string, error)
- func GlobalConfigFile() string
- func HostCommandAllowed(siteName, command string) (allowed, disabled bool)
- func HostProxyWorkerUnit(siteName string) string
- func IdleActivityFile() string
- func IgnoreSite(name string) error
- func InferFamily(name string) string
- func InstalledFrameworkNames() []string
- func IsBuiltinFramework(name string) bool
- func IsDBServiceName(name string) bool
- func IsDefaultPreset(name string) bool
- func IsFrankenPHPVersion(v string) bool
- func IsKnownFamily(name string) bool
- func IsStopped() bool
- func IsSupportedPHPVersion(v string) bool
- func LaravelAdapterFile() string
- func LatestFrankenPHPVersion() string
- func LoadOrGenerateProfilerKey() (string, error)
- func MappingHostPort(mapping string) int
- func MarkStopped() error
- func MatchesRule(dir string, rule FrameworkRule) bool
- func MaterializeServiceFiles(svc *CustomService) error
- func MaterializeServiceFilesChanged(svc *CustomService) (bool, error)
- func MaterializeServiceTuning(svc *CustomService) error
- func NginxConfD() string
- func NginxCustomD() string
- func NginxCustomDBkp() string
- func NginxDir() string
- func NginxHttpD() string
- func NginxHttpDBkp() string
- func NginxHttpUserConf() string
- func NodeGlobalDir() string
- func NormalizeFrankenPHPVersion(v string) string
- func PHPConfFile(version string) string
- func PHPImageHashFile() string
- func PHPUserIniBkpDir(version string) string
- func PHPUserIniFile(version string) string
- func PausedDir() string
- func PresetDashboardBootstrap(svc *CustomService) string
- func PresetExists(name string) bool
- func PresetPorts(name string) []string
- func PresetProxyEnv(svc *CustomService) (key, value string, ok bool)
- func PresetVersionServiceName(presetName string, v PresetVersion) string
- func ProjectHasChokidar(sitePath string) bool
- func ProjectReloadsWorker(dir, name string) bool
- func QuadletDir() string
- func RegisterFrameworkFetchHook(fn FrameworkFetchFunc)
- func RegisterPresetFetchHook(fn PresetFetchFunc)
- func RemoveCustomService(name string) error
- func RemoveFramework(name string) error
- func RemoveFrameworkFile(path string) error
- func RemoveFrameworks(names []string) (removed, failed []string)
- func RemoveProjectCommand(dir string, name string) error
- func RemoveProjectCustomWorker(dir string, name string) error
- func RemoveProjectDomain(dir string, domain string) error
- func RemoveSite(name string) error
- func RemoveStorePreset(name string) error
- func RemoveUserFramework(name string)
- func ReorderSites(order []string) error
- func ReplaceProjectDBService(dir string, choice string) error
- func ReplaceProjectDomain(dir string, fullDomains []string, oldDomain, tld string) error
- func RequestStatsDB() string
- func RequestStatsFile() string
- func ReservedHostPorts() map[int]bool
- func ResolveDynamicEnv(svc *CustomService) error
- func ResolveSiteRef(ref string) string
- func ResolveStripeSecret(sitePath string) (envKey, value string)
- func RunDir() string
- func SanitizeImageTag(tag string) string
- func SaveCustomService(svc *CustomService) error
- func SaveFramework(fw *Framework) error
- func SaveGlobal(cfg *GlobalConfig) error
- func SaveProjectConfig(dir string, cfg *ProjectConfig) error
- func SaveSites(reg *SiteRegistry) error
- func SaveStoreFramework(fw *Framework) error
- func SaveStorePreset(name string, data []byte) error
- func ServiceExtraPorts(name string) []string
- func ServiceFilePath(svcName string, target string) string
- func ServiceFilesDir(name string) string
- func ServiceFilesNewestMtime(svc *CustomService) (time.Time, bool)
- func ServiceIsManuallyStarted(name string) bool
- func ServiceIsPaused(name string) bool
- func ServiceIsPinned(name string) bool
- func ServicePublishedPort(name string) int
- func ServicePublishedPorts(name string) map[int]int
- func ServiceTuningAux(svc *CustomService) (target, content string, ok bool)
- func ServiceTuningAuxFile(name string) string
- func ServiceTuningBkpDir() string
- func ServiceTuningCommand(svc *CustomService) (command string, ok bool)
- func ServiceTuningFile(name string) string
- func ServiceTuningMount(svc *CustomService) (target string, ok bool)
- func ServiceTuningTemplate(svc *CustomService) (string, bool)
- func ServicesInFamily(family string) []string
- func SetExtraPresetsForTest(fsys fs.FS)
- func SetProjectCommand(dir string, cmd FrameworkCommand) error
- func SetProjectCustomWorker(dir string, name string, w FrameworkWorker) error
- func SetProjectDomains(dir string, domains []string) error
- func SetProjectFrameworkDef(dir string, def *Framework) error
- func SetProjectFrameworkVersion(dir string, version string) error
- func SetProjectJSRuntime(dir, runtime string) error
- func SetProjectPHPVersion(dir string, version string) error
- func SetProjectRuntime(dir, runtime string, worker bool) error
- func SetProjectSecured(dir string, secured bool) error
- func SetProjectStripe(dir, path, secretEnvKey string) error
- func SetProjectWorkerReload(dir, name string, enabled bool) error
- func SetProjectWorkers(dir string, workers []string) error
- func SetServiceManuallyStarted(name string, v bool) error
- func SetServicePaused(name string, paused bool) error
- func SetServicePinned(name string, v bool) error
- func SetSiteIdleSuspendedWorkers(name string, workers []string) error
- func SetSitePinned(name string, pinned bool) error
- func SetWorktreeDBIsolated(worktreePath string, isolated bool) error
- func SetWorktreeIdleSuspendedWorkers(name, wtBase string, workers []string) error
- func SetWorktreeNodeVersion(worktreePath, version string) error
- func SetWorktreePHPVersion(worktreePath, version string) error
- func SitePHPUserIniBkpDir(siteName string) string
- func SitePHPUserIniFile(siteName string) string
- func SiteSlug(name string) string
- func SitesFile() string
- func SitesUsingFramework(name string) []string
- func SkipSourceDir(name string) bool
- func SnapshotsDir() string
- func SourceWatchRoots(fw *Framework, root string) []string
- func SpxAssetsDir() string
- func SpxDataDir() string
- func SpxIniFile() string
- func SpxKeyFile() string
- func StoreFrameworksDir() string
- func StoreIndexFile() string
- func StorePresetsDir() string
- func StripeSecretSet(sitePath string) bool
- func StripeWebhookPath(sitePath string) string
- func SyncProjectDomains(dir string, fullDomains []string, tld string) error
- func SystemdUserDir() string
- func TuningFamilies() []string
- func UIClientAddr() string
- func UIClientNetwork() string
- func UISocketPath() string
- func UnusedInstalledFrameworks() []string
- func UpdateCheckFile() string
- func ValidateCustomService(svc *CustomService) error
- func ValidatePresetYAML(data []byte, name string) error
- func ValidatePublicDir(s string) error
- func ValidateStripeWebhookPath(path string) (string, error)
- func WatcherNeedsPolling(sitePath string) bool
- func WorktreeDBIsolated(worktreePath string) bool
- func WorktreeDBRegistryPath() string
- func WorktreeLANRegistryPath() string
- func WorktreeNodeVersion(worktreePath, fallback string) string
- func WorktreePHPVersion(worktreePath, fallback string) string
- func WorktreeUnitSlug(wtBase string) string
- type ClientShim
- type CommandNotFoundError
- type CommandValidationError
- type ContainerConfig
- type CustomService
- func DefaultPresetMeta(name string) (*CustomService, error)
- func ListCustomServices() ([]*CustomService, error)
- func LoadCustomService(name string) (*CustomService, error)
- func LoadCustomServiceFromFile(path string) (*CustomService, error)
- func ResolveServiceForTuning(name string) (*CustomService, error)
- type DoctorCheck
- type EnvDetect
- type EnvKeyGeneration
- type FileMount
- type Framework
- func (fw *Framework) DetectProxy(dir string) (*WorkerProxy, string)
- func (fw *Framework) FrankenPHPEntrypoint(worker bool) []string
- func (fw *Framework) FrankenPHPEnv(worker bool) map[string]string
- func (fw *Framework) HasWorker(name, dir string) bool
- func (fw *Framework) ResolveFrankenPHPWorkerEntrypoint(sitePath string, worker bool) []string
- type FrameworkCommand
- type FrameworkDoctor
- type FrameworkEnvConf
- type FrameworkFetchFunc
- type FrameworkFile
- type FrameworkFrankenPHP
- type FrameworkInfo
- type FrameworkLogSource
- type FrameworkPHP
- type FrameworkRule
- type FrameworkServiceDef
- type FrameworkServiceDetect
- type FrameworkSetupCmd
- type FrameworkSource
- type FrameworkTinker
- type FrameworkWorker
- type FrankenPHPHint
- type GlobalConfig
- func (c *GlobalConfig) AddExtension(version, ext string)
- func (c *GlobalConfig) AddPackage(version, pkg string)
- func (c *GlobalConfig) AllExtApkDeps() map[string][]string
- func (c *GlobalConfig) AutoCleanupEnabled() bool
- func (c *GlobalConfig) DNSManaged() bool
- func (c *GlobalConfig) GetExtApkDeps(ext string) []string
- func (c *GlobalConfig) GetExtensions(version string) []string
- func (c *GlobalConfig) GetPackages(version string) []string
- func (c *GlobalConfig) GetXdebugMode(version string) string
- func (c *GlobalConfig) GetXdebugStart(version string) string
- func (c *GlobalConfig) IdleSuspendTimeout() time.Duration
- func (c *GlobalConfig) IsDevtoolsWorkers() bool
- func (c *GlobalConfig) IsDumpsEnabled() bool
- func (c *GlobalConfig) IsDumpsPassthrough() bool
- func (c *GlobalConfig) IsNotificationsEnabled() bool
- func (c *GlobalConfig) IsProfilerEnabled() bool
- func (c *GlobalConfig) IsXdebugEnabled(version string) bool
- func (c *GlobalConfig) NodeManagedPref() (val bool, set bool)
- func (c *GlobalConfig) RemoveExtension(version, ext string)
- func (c *GlobalConfig) RemovePackage(version, pkg string)
- func (c *GlobalConfig) RequestTimeoutSeconds() int
- func (c *GlobalConfig) SetDevtoolsWorkers(enabled bool)
- func (c *GlobalConfig) SetDumpsEnabled(enabled bool)
- func (c *GlobalConfig) SetDumpsPassthrough(enabled bool)
- func (c *GlobalConfig) SetExtApkDeps(ext string, deps []string)
- func (c *GlobalConfig) SetNodeManaged(managed bool)
- func (c *GlobalConfig) SetNotificationsEnabled(enabled bool)
- func (c *GlobalConfig) SetXdebug(version string, enabled bool)
- func (c *GlobalConfig) SetXdebugMode(version, mode string)
- func (c *GlobalConfig) SetXdebugStart(version, value string)
- func (c *GlobalConfig) WorkerExecMode() string
- type Preset
- type PresetFetchFunc
- type PresetMeta
- type PresetPlatformImage
- type PresetVersion
- type ProjectConfig
- type ProjectDB
- type ProjectService
- type ProxyConfig
- type ServiceConfig
- type Site
- func FindSite(name string) (*Site, error)
- func FindSiteByDomain(domain string) (*Site, error)
- func FindSiteByPath(path string) (*Site, error)
- func FindSiteByRef(ref string) (*Site, error)
- func IsDomainUsed(domain string) (*Site, error)
- func ParentSiteForWorktreeDir(dir string) (*Site, bool)
- func SitesUsingService(name string) []Site
- func (s Site) CommandApproved(command string) bool
- func (s *Site) FrankenPHPQuadletSpec() (entrypoint []string, env map[string]string)
- func (s *Site) HasDomain(domain string) bool
- func (s *Site) IsCustomContainer() bool
- func (s *Site) IsCustomFPM() bool
- func (s *Site) IsFrankenPHP() bool
- func (s *Site) IsGroupMain() bool
- func (s *Site) IsGroupSecondary() bool
- func (s *Site) IsHostProxy() bool
- func (s *Site) PrimaryDomain() string
- type SiteInit
- type SiteRegistry
- type StripeConfig
- type TuningSpec
- type WorkerNotFoundError
- type WorkerProxy
- type WorktreeDBEntry
- type WorktreeLANEntry
Constants ¶
const ( CommandOutputSilent = "silent" CommandOutputText = "text" CommandOutputURL = "url" CommandOutputTerminal = "terminal" // spawn the user's terminal emulator instead of streaming to the modal )
Valid Output values for FrameworkCommand.
const ( WorkerExecModeExec = "exec" WorkerExecModeContainer = "container" )
Worker exec-mode constants. `exec` is the default on every platform; `container` is available as an opt-in on macOS for users who prefer the reliability of per-worker containers over the memory savings of podman-exec into the shared FPM container.
const AccessFeedUDPPort = "9914"
AccessFeedUDPPort is the UDP port the watcher binds on darwin for the nginx access feed: nginx runs in the podman-machine VM where the host unix socket isn't reachable, so the feed travels over gvproxy UDP (like DumpsTCPPort).
const DashboardProxyPrefix = "/_svc/"
DashboardProxyPrefix is the lerd-ui mount under which bundled admin dashboards (rabbitmq, redisinsight) are served same-origin so their cookies stay first-party in the iframe overlay. Shared by the lerd-ui proxy and the quadlet generator, which configures each upstream to serve its UI there.
const DefaultIdleSuspendTimeout = 30 * time.Minute
DefaultIdleSuspendTimeout is how long a site stays idle before its suspendable workers are stopped, when no explicit timeout is configured.
const DefaultRequestTimeout = 60
DefaultRequestTimeout is nginx's built-in fastcgi/proxy read-timeout default (seconds), used when neither the project nor the global config sets one.
const DefaultStripeWebhookPath = "/stripe/webhook"
DefaultStripeWebhookPath is the route a Stripe listener forwards events to when the project does not configure one. Matches Laravel Cashier's default.
const DumpsTCPPort = "9913"
DumpsTCPPort is the loopback port the dump receiver binds on darwin (where a unix socket on the macOS host can't be reached from FPM inside the podman-machine VM). Linux uses a unix socket instead so this is unused there. Picked to avoid Symfony var-dump-server's default :9912 — see internal/dumps.DefaultAddr.
const FrankenPHPMinVersion = "8.2"
FrankenPHPMinVersion is the oldest PHP version dunglas/frankenphp publishes an image for; supported versions below it run under FPM only.
const HostProxyWorkerName = "app"
HostProxyWorkerName is the worker name of a host-proxy site's supervised dev server. There is exactly one per site.
const MySQLImportMaxPacket = "1G"
MySQLImportMaxPacket is the client-side max_allowed_packet lerd passes whenever it loads a dump into mysql/mariadb (db:import, snapshot restore, cross-version migrate), so a large extended-insert statement is never truncated by the client's 16MB default. The server ceiling still governs the effective limit, set in the bundled lerd.cnf and raiseable from the service Config tab.
Variables ¶
var DefaultSourceDirs = []string{
"app", "src", "resources", "routes", "lib", "components", "pages", "config", "database",
}
DefaultSourceDirs are the project subdirectories watched for "active coding" activity (keeping a site awake under idle-suspend) when a framework declares none of its own. Deliberately framework-agnostic: it covers the common PHP and JS source roots — Laravel's app/resources/routes, Symfony and Vite's src, Node's lib/components/pages — and never lists generated or vendored trees like node_modules or vendor, so the watch set stays small.
var KnownCommandIcons = []string{
"broom", "database", "refresh", "link", "check", "list",
"key", "edit", "arrow-down", "arrow-up", "play", "terminal",
}
KnownCommandIcons is the curated icon vocabulary. .lerd.yaml entries with an icon outside this set fail `lerd check`. Keep in sync with the UI Icon component so an icon present here always resolves to a visual on screen.
var StripeSecretEnvCandidates = []string{"STRIPE_SECRET", "STRIPE_SECRET_KEY", "STRIPE_API_KEY"}
StripeSecretEnvCandidates are the env var names that commonly hold a Stripe secret key, in priority order: Laravel/Cashier, the Stripe Node/Nest convention, then the generic SDK name. Probed when a project pins no explicit secret_env_key, so the listener detects a secret regardless of framework.
var SupportedPHPVersions = []string{"7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5"}
SupportedPHPVersions lists the PHP versions lerd can build FPM images for. 7.4 and 8.0 are a frozen legacy tier for old projects: still buildable from Alpine 3.16, but pinned (older xdebug, no mongodb ext) and not security-updated.
var ValidCommandOutputs = []string{CommandOutputSilent, CommandOutputText, CommandOutputURL, CommandOutputTerminal}
ValidCommandOutputs lists the accepted Output values; used by validation.
Functions ¶
func AccessFeedListenAddr ¶ added in v1.27.0
func AccessFeedListenAddr() string
AccessFeedListenAddr is the host address the watcher binds for the darwin UDP access feed. Loopback matches the gvproxy host.containers.internal forward.
func AccessLogTarget ¶ added in v1.27.0
func AccessLogTarget() string
AccessLogTarget is the nginx syslog `server=` for the access feed: the bind-mounted unix socket on Linux, or host.containers.internal over gvproxy UDP on macOS where nginx lives in the VM and the host socket isn't reachable.
func AccessSocketPath ¶ added in v1.25.0
func AccessSocketPath() string
AccessSocketPath is the unix datagram socket the lerd-watcher binds to receive the nginx access feed (one "$host" line per request) that drives idle-suspend's per-site last-active tracking. It lives in RunDir, which is bind-mounted into the lerd-nginx container at the same path, so nginx's syslog access_log can reach it without container→host TCP routing.
func AddProjectWorker ¶ added in v1.12.6
AddProjectWorker appends name to the workers list if not already present. No-op if .lerd.yaml does not exist.
func AddWorktreeDB ¶ added in v1.19.0
func AddWorktreeDB(e WorktreeDBEntry) error
AddWorktreeDB inserts or updates an entry by (site, branch).
func AddWorktreeLAN ¶ added in v1.19.0
func AddWorktreeLAN(e WorktreeLANEntry) error
AddWorktreeLAN inserts or updates an entry by (site, branch).
func ApproveSiteCommand ¶ added in v1.27.0
ApproveSiteCommand records that the user consented to run command on the host for the named site, so future runs and boot restore don't re-prompt. No-op if already recorded or the site is unknown.
func BackupBinaryFile ¶ added in v1.5.0
func BackupBinaryFile() string
BackupBinaryFile returns the path to the backup lerd binary used for rollback.
func BackupTrayFile ¶ added in v1.5.0
func BackupTrayFile() string
BackupTrayFile returns the path to the backup lerd-tray binary used for rollback.
func BackupVersionFile ¶ added in v1.5.0
func BackupVersionFile() string
BackupVersionFile returns the path to the file storing the pre-update version string.
func BackupsDir ¶ added in v1.19.0
func BackupsDir() string
BackupsDir returns the directory where migration dumps are stored so users can recover manually if an automated migration fails.
func BrowserHostsFile ¶ added in v1.10.0
func BrowserHostsFile() string
BrowserHostsFile returns the path to the hosts file for browser testing containers (e.g. Selenium). It maps .test domains to the nginx container's IP so that Chromium inside the container can reach lerd sites directly over the Podman network instead of going through the host gateway.
func ClearStopped ¶ added in v1.24.0
func ClearStopped() error
ClearStopped clears the intentional-stop marker (lerd is starting or running).
func ComposerHasPackage ¶ added in v1.10.0
ComposerHasPackage reports whether the composer.json in dir lists pkg in require or require-dev. ComposerHasPackage reports whether the composer.json in dir lists pkg in require, require-dev, or any of the extra sections specified.
func ConfigDir ¶
func ConfigDir() string
ConfigDir returns ~/.config/lerd/ (or $XDG_CONFIG_HOME/lerd/).
func ContainerHostsFile ¶ added in v1.2.4
func ContainerHostsFile() string
ContainerHostsFile returns the path to the shared hosts file mounted into PHP containers.
func ContainsUnitInjectionChars ¶ added in v1.24.0
ContainsUnitInjectionChars reports whether s contains a newline, carriage return, or NUL: characters that would let a value break out of its line in a generated systemd unit or podman quadlet and inject an extra directive.
func ControlSocketPath ¶ added in v1.25.0
func ControlSocketPath() string
ControlSocketPath is the unix datagram socket the lerd-watcher binds for idle-suspend control messages: "enable"/"disable" from the CLI and dashboard toggle, and "activity <site>" from the CLI shims and MCP.
func CountSitesUsingPHP ¶ added in v1.4.0
CountSitesUsingPHP returns how many non-ignored, non-paused sites are registered with the given PHP version.
func CountSitesUsingService ¶ added in v1.0.0
CountSitesUsingService returns how many active (non-ignored, non-paused) site .env files reference lerd-{name}, i.e. are configured to use the service.
func CustomServiceExists ¶ added in v1.27.0
CustomServiceExists reports whether a custom service's definition YAML exists. The YAML is the authoritative install-state signal for a custom service, so ServiceInstalled and the services list resolve from it and can't drift (#678).
func CustomServicesDependingOn ¶ added in v1.0.0
CustomServicesDependingOn returns the names of all custom services that declare name in their depends_on list.
func CustomServicesDir ¶ added in v0.5.4
func CustomServicesDir() string
CustomServicesDir returns the directory for custom service YAML files.
func DashboardProxyPath ¶ added in v1.25.0
DashboardProxyPath is the same-origin mount path for a proxied dashboard.
func DataDir ¶
func DataDir() string
DataDir returns ~/.local/share/lerd/ (or $XDG_DATA_HOME/lerd/).
func DataSubDir ¶
DataSubDir returns a named subdirectory under data.
func DefaultPresetConnectionURL ¶ added in v1.19.0
DefaultPresetConnectionURL returns the developer-facing connection URL for a default preset, or empty for non-defaults / presets without one.
func DefaultPresetDashboard ¶ added in v1.19.0
DefaultPresetDashboard returns the dashboard URL for a default preset, or empty for non-defaults / presets that don't expose a dashboard. It reads the cached meta directly rather than through DefaultPresetMeta, which deep-copies the struct and clones its slices — wasteful here since callers (the services snapshot, rebuilt for every service every refresh) only want one string.
func DefaultPresetEnvVars ¶ added in v1.19.0
DefaultPresetEnvVars returns the resolved env_vars slice for a default preset, or nil for any other name. Used by the env writer (lerd env) and the web UI to surface the same .env hints regardless of caller.
func DefaultPresetNames ¶ added in v1.19.0
func DefaultPresetNames() []string
DefaultPresetNames returns sorted names of every bundled preset whose YAML declares default: true. Cached on first call: the embed FS never changes during a process lifetime, so re-walking it on every lookup is wasteful.
func DetectFramework ¶ added in v1.0.0
DetectFramework inspects dir and returns the detected framework name. It checks user-defined and store-installed frameworks first so that more specific frameworks (e.g. Statamic, which also contains an artisan file) are detected before the broad built-in Laravel detection. Returns ("", false) if no framework matches.
func DetectFrameworkForDir ¶ added in v1.11.0
DetectFrameworkForDir is the primary entry point for framework detection. It checks .lerd.yaml first (committed source of truth), restoring embedded definitions if needed, then falls back to file/composer-based detection. Does NOT prompt or fetch from the remote store — callers that need store interaction should fall back to store.DetectFrameworkWithStore.
func DetectMajorVersion ¶ added in v1.11.0
func DetectPublicDir ¶ added in v1.0.0
DetectPublicDir inspects dir for a well-known PHP public directory and returns it. It checks directories used by common PHP frameworks in priority order. A candidate is accepted only if it contains an index.php file, ensuring the directory is actually the document root and not an empty placeholder. Returns "." if no valid candidate is found (serve from project root).
func DevtoolsAssetsDir ¶ added in v1.23.0
func DevtoolsAssetsDir() string
DevtoolsAssetsDir holds the devtools collector conf.d ini. Bind-mounted read-only into every FPM container; version-agnostic like the debug bridge.
func DevtoolsBridgeTarget ¶ added in v1.23.0
func DevtoolsBridgeTarget() string
DevtoolsBridgeTarget is the socket the extension ships events to — the same receiver lerd-ui binds for dumps, so captured queries land in the shared ring and fan out through the same SSE stream.
func DevtoolsCollectorFile ¶ added in v1.23.0
func DevtoolsCollectorFile() string
DevtoolsCollectorFile is the host path for the framework-neutral collector (agnostic mail and other shared-library capture), loaded lazily by the lerd_devtools extension. Lives in the dumps assets dir (mounted at /usr/local/etc/lerd), where the extension expects it.
func DevtoolsIniFile ¶ added in v1.23.0
func DevtoolsIniFile() string
DevtoolsIniFile is the host path for the conf.d ini that configures the lerd_devtools extension (socket target + enabled kinds + sentinel path).
func DevtoolsWorkersFlagFile ¶ added in v1.23.0
func DevtoolsWorkersFlagFile() string
DevtoolsWorkersFlagFile is the sentinel that opts worker (queue/scheduler) queries into capture. Absent (default) = workers skipped. Lives beside the devtools enable flag under the /usr/local/etc/lerd mount; toggling it never restarts FPM.
func DumpsAssetsDir ¶ added in v1.20.0
func DumpsAssetsDir() string
DumpsAssetsDir returns the host directory holding the version-agnostic dump bridge assets (PHP file + ini). Both files are bind-mounted read-only into every FPM container when `lerd dump on` is active. Single shared copy because the bridge is identical across PHP versions.
func DumpsBridgeFile ¶ added in v1.20.0
func DumpsBridgeFile() string
DumpsBridgeFile is the host path for dump-bridge.php (the auto-prepended PHP file).
func DumpsBridgeTarget ¶ added in v1.20.0
func DumpsBridgeTarget() string
DumpsBridgeTarget is the stream_socket_client target the PHP bridge reads from the conf.d ini. On macOS gvproxy forwards host.containers.internal:<port> from inside the podman-machine VM to the lerd-ui process on the host; on Linux the FPM container hits the host unix socket directly via the %h:%h bind mount.
func DumpsEnabledFlagFile ¶ added in v1.20.0
func DumpsEnabledFlagFile() string
DumpsEnabledFlagFile is the sentinel the debug bridge checks on every request. Present file = bridge captures dump()/dd() calls; absent file = bridge is a fast no-op. Toggling is a single touch/rm on this file so the FPM container never restarts.
func DumpsIniFile ¶ added in v1.20.0
func DumpsIniFile() string
DumpsIniFile is the host path for the conf.d ini that turns the bridge on.
func DumpsListenAddr ¶ added in v1.20.0
func DumpsListenAddr() string
DumpsListenAddr is the address paired with DumpsListenNetwork.
func DumpsListenNetwork ¶ added in v1.20.0
func DumpsListenNetwork() string
DumpsListenNetwork reports the net.Listen network lerd-ui should bind for the dump receiver. On macOS we fall back to TCP because unix sockets don't traverse the podman-machine virtio-fs boundary as functional sockets (same constraint that drives EnsureLerdVhost's host.containers.internal:7073 fallback). On Linux the unix socket is reachable inside FPM via the %h:%h bind mount.
func DumpsSocketPath ¶ added in v1.20.0
func DumpsSocketPath() string
DumpsSocketPath is the Unix socket lerd-ui binds for dump payloads. Kept in RunDir so it sits alongside the UI socket and so the existing %h:%h volume in every FPM container surfaces it at the same path inside.
func EffectiveTLD ¶ added in v1.24.0
func EffectiveTLD() string
EffectiveTLD returns the configured DNS TLD, falling back to "test" when the global config can't be loaded or leaves it empty. Single source of truth for the many callers that need the active TLD with that default.
func ErrorPagesDir ¶ added in v1.5.0
func ErrorPagesDir() string
ErrorPagesDir returns the directory where nginx error page HTML files are stored.
func FPMPortsFor ¶ added in v1.28.1
FPMPortsFor returns the extra published port mappings recorded for a PHP version's shared FPM container, or nil when none are configured. Read by the FPM quadlet renderer so a `lerd shell` process on one of these ports is reachable from the host, and by the port-shift guard to skip a version's own ports when relocating a colliding one.
func FamilyOf ¶ added in v1.22.0
func FamilyOf(svc *CustomService) string
FamilyOf returns the family for a resolved CustomService, preferring the explicit Family field over name-pattern inference. Use this anywhere behavior branches on family (env wiring, DB creation, migration) so services with non-digit suffixes like postgres-pgvector are recognised.
func FamilyOfName ¶ added in v1.22.0
FamilyOfName resolves a family by service name. Loads the installed custom service definition (if any) to honour its Family field, falling back to InferFamily for built-ins, uninstalled names, or anything without a saved definition. Use this from call sites that only have the bare service name.
func FrameworksDir ¶ added in v1.0.0
func FrameworksDir() string
FrameworksDir returns the directory for user-defined framework YAML files.
func FrankenPHPVersions ¶ added in v1.25.0
func FrankenPHPVersions() []string
FrankenPHPVersions returns the subset of SupportedPHPVersions that dunglas/frankenphp publishes an image for, in the same ascending order.
func GetConsoleCommand ¶ added in v1.2.0
GetConsoleCommand returns the console binary (without the "php" prefix) for the framework detected in projectDir. It checks the site registry first, then falls back to auto-detection. For Laravel the default is "artisan".
func GlobalConfigFile ¶
func GlobalConfigFile() string
GlobalConfigFile returns the path to config.yaml.
func HostCommandAllowed ¶ added in v1.27.0
HostCommandAllowed reports whether a project-supplied host command may run for a site without prompting. disabled is true when the global switch refuses all project host commands; otherwise allowed is true when the global skip is set or the user already approved this exact command for the site.
func HostProxyWorkerUnit ¶ added in v1.24.0
HostProxyWorkerUnit returns the worker unit name for a host-proxy site's dev server (lerd-app-<site>). Single source of truth for the cli (which starts and stops it) and siteinfo (which reports its health).
func IdleActivityFile ¶ added in v1.25.0
func IdleActivityFile() string
IdleActivityFile is where the lerd-watcher persists per-site last-active times so a restart restores the idle countdowns instead of re-seeding to now; lerd-ui and the CLI read it to render each site's idle state. Lives in RunDir.
func IgnoreSite ¶ added in v0.3.0
IgnoreSite marks a site as ignored (used for parked sites that have been unlinked).
func InferFamily ¶ added in v1.9.0
InferFamily returns the family for a custom service whose name follows the versioned-alternate template <family>-<digit...>, or the bare family name when the service is the canonical preset (e.g. "mongo"). Returns empty when neither pattern matches a known family.
func InstalledFrameworkNames ¶ added in v1.27.0
func InstalledFrameworkNames() []string
InstalledFrameworkNames returns the unique names of frameworks that have a removable definition file on disk (user-defined or store-installed). Built-in frameworks are excluded: their definitions live in the binary, so what is on disk is only an overlay we never prune away.
func IsBuiltinFramework ¶ added in v1.27.0
IsBuiltinFramework reports whether name is one of lerd's built-in frameworks (laravel, symfony). Their definitions ship in the binary, so their store or user files are overlays that prune and the unlink offer leave alone.
func IsDBServiceName ¶ added in v1.22.0
IsDBServiceName reports whether name refers to a database service: sqlite, or any service whose family is mysql, mariadb, postgres, or mongo. Used by the DB-picker logic in `lerd env` and `db_set` to decide what counts as "the database for this project".
func IsDefaultPreset ¶ added in v1.19.0
IsDefaultPreset reports whether name belongs to a default preset (the successor to the previous "built-in service" concept).
func IsFrankenPHPVersion ¶ added in v1.25.0
IsFrankenPHPVersion reports whether dunglas/frankenphp publishes an image for v.
func IsKnownFamily ¶ added in v1.9.0
IsKnownFamily reports whether name is a recognised service family. Computed from every preset YAML's family field (default + add-on), so e.g. mongo and mariadb are recognised even though no default preset declares them.
func IsStopped ¶ added in v1.24.0
func IsStopped() bool
IsStopped reports whether lerd was intentionally stopped via `lerd stop`.
func IsSupportedPHPVersion ¶ added in v1.25.0
IsSupportedPHPVersion reports whether v is a version lerd can install.
func LaravelAdapterFile ¶ added in v1.23.0
func LaravelAdapterFile() string
LaravelAdapterFile is the host path for the Laravel devtools adapter, loaded by the lerd_devtools extension at Application::boot. It lives in the dumps assets dir because that directory is bind-mounted into FPM at /usr/local/etc/lerd, where the extension expects it.
func LatestFrankenPHPVersion ¶ added in v1.25.0
func LatestFrankenPHPVersion() string
LatestFrankenPHPVersion returns the newest PHP version dunglas/frankenphp publishes an image for, used as the fallback for unsupported versions. Falls back to FrankenPHPMinVersion so callers never index an empty slice.
func LoadOrGenerateProfilerKey ¶ added in v1.22.0
LoadOrGenerateProfilerKey returns the SPX HTTP key, generating and persisting a fresh random one on first use. The key gates the SPX profiler UI and per-request profiling. Lerd injects it into the FPM HTTP_COOKIE via nginx so it never has to live in a browser cookie (which would be a blocked third-party cookie inside the dashboard iframe).
func MappingHostPort ¶ added in v1.28.1
MappingHostPort extracts the host port from a podman port mapping: a bare host port "3411", "3411:3306", or "127.0.0.1:3411:3306", with an optional "/tcp" suffix. Returns 0 when no valid host port is present.
func MarkStopped ¶ added in v1.24.0
func MarkStopped() error
MarkStopped records that lerd was intentionally stopped, so background watchers suppress worker heal/notification noise until the next start.
func MatchesRule ¶ added in v1.6.0
func MatchesRule(dir string, rule FrameworkRule) bool
MatchesRule returns true if the given rule matches the project directory.
func MaterializeServiceFiles ¶ added in v1.9.0
func MaterializeServiceFiles(svc *CustomService) error
MaterializeServiceFiles writes each FileMount for svc to its host path, creating the parent directory and applying the requested mode. The file list is looked up from the hardcoded presetFiles map using svc.Preset, so the Go binary is always the source of truth — updating lerd and restarting the service is enough to roll out new file contents.
func MaterializeServiceFilesChanged ¶ added in v1.28.1
func MaterializeServiceFilesChanged(svc *CustomService) (bool, error)
MaterializeServiceFilesChanged is MaterializeServiceFiles with drift detection: it rewrites a preset file only when its content differs from what is already on disk, and reports whether anything changed. The passive reconcile uses this to roll a shipped preset config bump (e.g. a higher max_allowed_packet) onto an already-installed service on update and to know when a restart is warranted, without churning a service whose config is already current.
func MaterializeServiceTuning ¶ added in v1.23.0
func MaterializeServiceTuning(svc *CustomService) error
MaterializeServiceTuning seeds svc's tuning override with its commented template when the host file does not exist yet, and is a no-op once the file is present so user edits are never clobbered. When the family declares a lerd-managed helper file (AuxTarget), that file is (re)written every call so helper changes from a new lerd version land automatically. Services without a tuning mount (neither inline nor family-keyed) are skipped. Call this before GenerateCustomQuadlet so every mounted host path always exists.
func NginxCustomD ¶ added in v1.17.0
func NginxCustomD() string
NginxCustomD holds user-authored nginx snippets included at the end of each per-site server block. Lerd never writes here, so edits survive vhost regeneration and `lerd update`.
func NginxCustomDBkp ¶ added in v1.23.0
func NginxCustomDBkp() string
NginxCustomDBkp holds timestamped backups of per-site custom.d overrides produced by the web UI editor. It deliberately sits next to (not inside) custom.d/ because the generated vhost templates include /etc/nginx/custom.d/{domain}.conf*; a backup file in custom.d/ would be auto-loaded by nginx and produce duplicate directives.
func NginxHttpD ¶ added in v1.23.0
func NginxHttpD() string
NginxHttpD holds user-authored nginx snippets included at the http{} level (e.g. global gzip, proxy buffers, client_max_body_size). Lerd never writes here, so edits survive nginx.conf regeneration and `lerd update`.
func NginxHttpDBkp ¶ added in v1.23.0
func NginxHttpDBkp() string
NginxHttpDBkp holds timestamped backups of the global http-level override produced by the web UI editor. It sits next to (not inside) http.d/ because nginx.conf includes /etc/nginx/http.d/*.conf; a backup inside http.d/ would be loaded too and produce duplicate http{} directives.
func NginxHttpUserConf ¶ added in v1.23.0
func NginxHttpUserConf() string
NginxHttpUserConf is the single global http-level tuning override file. The zz- prefix sorts it after any other http.d snippets so user values win.
func NodeGlobalDir ¶ added in v1.21.1
func NodeGlobalDir() string
NodeGlobalDir is the npm prefix lerd points its node shim at, so `npm install -g foo` lands in a stable per-user path instead of a version-specific fnm directory that nothing has on PATH.
func NormalizeFrankenPHPVersion ¶ added in v1.25.0
NormalizeFrankenPHPVersion returns v when dunglas/frankenphp publishes an image for it, otherwise the latest version it does, so the base image, the derived image name, and the quadlet all agree on one version.
func PHPConfFile ¶ added in v0.4.0
PHPConfFile returns the host path for the per-version xdebug ini file.
func PHPImageHashFile ¶ added in v0.1.25
func PHPImageHashFile() string
PHPImageHashFile returns the path to the stored PHP-FPM Containerfile hash.
func PHPUserIniBkpDir ¶ added in v1.23.0
PHPUserIniBkpDir holds timestamped backups of the per-version user ini produced by the web UI editor. It sits next to (not inside) the version directory's ini scan path so the FPM container does not load backup files as live config.
func PHPUserIniFile ¶ added in v0.5.5
PHPUserIniFile returns the host path for the per-version user php.ini file.
func PausedDir ¶ added in v1.0.0
func PausedDir() string
PausedDir returns the directory where paused-site landing page HTML files are stored.
func PresetDashboardBootstrap ¶ added in v1.25.0
func PresetDashboardBootstrap(svc *CustomService) string
PresetDashboardBootstrap returns an inline <script> to inject into the proxied dashboard's HTML so it opens already authenticated, mirroring how pgadmin/phpmyadmin auto-log-in via config. Returns "" when the dashboard needs no client-side priming.
RabbitMQ's management UI (3.13) keeps no server session: the login form just stores HTTP Basic credentials in localStorage plus a `loggedIn` marker packed into its `m` cookie under a runtime-hashed key. We seed the same state before its scripts run. The cookie key is derived with the app's own hashCode/ short_key algorithm at runtime (replicated inline) so it stays correct across versions; the page's CSP already allows unsafe-inline scripts.
func PresetExists ¶ added in v1.9.0
PresetExists reports whether a bundled preset with the given name exists.
func PresetPorts ¶ added in v1.27.0
PresetPorts returns the resolved default host port mappings for any bundled preset — default-stack (mysql, redis) or optional (gotenberg, mongo) alike — or nil when name isn't a preset we ship. The ports live in the preset YAML the same way regardless of the default flag, so the ports UI keys off ownership, not default-stack membership. Like DefaultPresetDashboard it reads the cached meta directly instead of through DefaultPresetMeta, which deep-copies the struct and clones its slices — wasteful for the services snapshot, which rebuilds every service every refresh and only reads the ports. The returned slice is the cached instance's own; callers must not mutate it.
func PresetProxyEnv ¶ added in v1.25.0
func PresetProxyEnv(svc *CustomService) (key, value string, ok bool)
PresetProxyEnv returns the container env that makes a bundled upstream serve its UI under the same /_svc/<name> path the lerd-ui proxy mounts it at, so the dashboard embeds same-origin. It is injected at quadlet generation (not stored in the service YAML) so existing installs pick it up on the next start without a reinstall, mirroring how PresetFiles are re-sourced. Returns ok=false for presets that configure the prefix another way: rabbitmq uses a management.path_prefix conf mount (see presetFiles).
func PresetVersionServiceName ¶ added in v1.22.0
func PresetVersionServiceName(presetName string, v PresetVersion) string
PresetVersionServiceName returns the resolved service (container) name for a specific version of a multi-version preset. Canonical versions keep the bare preset name; non-canonical versions get the sanitised-tag suffix. Use this anywhere code needs to map a (preset, version) pair to the on-disk custom service name (e.g. install-state probes).
func ProjectHasChokidar ¶ added in v1.25.0
ProjectHasChokidar reports whether the chokidar npm package, required by the Octane and Horizon file watchers, is installed in the project. Canonical home; cli.projectHasChokidar delegates here.
func ProjectReloadsWorker ¶ added in v1.24.0
ProjectReloadsWorker reports whether the project at dir opts the named worker into auto-reload mode. Returns false when .lerd.yaml is absent or unreadable.
func RegisterFrameworkFetchHook ¶ added in v1.10.0
func RegisterFrameworkFetchHook(fn FrameworkFetchFunc)
RegisterFrameworkFetchHook sets the callback used to auto-fetch missing framework definitions from the store.
func RegisterPresetFetchHook ¶ added in v1.28.1
func RegisterPresetFetchHook(fn PresetFetchFunc)
RegisterPresetFetchHook sets the callback used to auto-fetch missing service presets from the store.
func RemoveCustomService ¶ added in v0.5.4
RemoveCustomService deletes a custom service config file.
func RemoveFramework ¶ added in v1.0.0
RemoveFramework deletes all framework definition files (user and store) for the given name.
func RemoveFrameworkFile ¶ added in v1.10.0
RemoveFrameworkFile removes a single framework definition file.
func RemoveFrameworks ¶ added in v1.27.0
RemoveFrameworks removes each named framework definition, returning the names that were removed and the names that failed so callers can report accurately.
func RemoveProjectCommand ¶ added in v1.21.0
RemoveProjectCommand deletes a project-level command entry by Name. Returns CommandNotFoundError if .lerd.yaml has no entry with that name.
func RemoveProjectCustomWorker ¶ added in v1.11.0
RemoveProjectCustomWorker deletes a custom worker by name. No-op if .lerd.yaml does not exist. Returns an error if the worker is not found.
func RemoveProjectDomain ¶ added in v1.11.0
RemoveProjectDomain removes a single domain (case-insensitive match). No-op if .lerd.yaml does not exist.
func RemoveSite ¶
RemoveSite removes a site by name from the registry.
func RemoveStorePreset ¶ added in v1.28.1
RemoveStorePreset deletes a preset's cached copy from the store-cache dir, if present, and drops it from the parse cache. It never touches the embedded bundle (a no-op when only the built-in exists). Called when the last service using a store preset is removed, so the definition reverts from "local" to "store" and a future install re-fetches it fresh.
func RemoveUserFramework ¶ added in v1.10.0
func RemoveUserFramework(name string)
RemoveUserFramework silently removes a user-defined framework YAML if it exists. Used when migrating from user-defined to store-installed.
func ReorderSites ¶ added in v1.24.0
ReorderSites permutes the registry so its sites follow the given order of names. Names that don't match a site are ignored, and any site whose name is absent from order is kept and appended after the ordered ones in its original relative position, so paused sites and grouped secondaries are never dropped.
func ReplaceProjectDBService ¶ added in v1.11.0
ReplaceProjectDBService removes any existing DB service entry from the project's .lerd.yaml and adds the given choice. A "DB service" is sqlite or any service in the mysql / mariadb / postgres / mongo families, so alternates like postgres-pgvector or mariadb-10-11 replace the previous DB pick cleanly. Creates .lerd.yaml entries even if the file doesn't exist yet.
func ReplaceProjectDomain ¶ added in v1.24.0
ReplaceProjectDomain syncs the registry domains into .lerd.yaml (preserving conflict-filtered extras via SyncProjectDomains) and then drops oldDomain when it is no longer one of the site's domains. Use this on a rename or removal so the replaced domain isn't left behind to re-register on a future link; SyncProjectDomains alone merges and would re-append it. oldDomain is the full domain (with TLD). No-op if .lerd.yaml does not exist.
func RequestStatsDB ¶ added in v1.28.1
func RequestStatsDB() string
RequestStatsDB is the durable SQLite store of individual requests the watcher writes and lerd-ui reads to build the request-timing analytics view over any window. Unlike the ephemeral snapshot it lives in DataDir so history survives a reboot.
func RequestStatsFile ¶ added in v1.28.1
func RequestStatsFile() string
RequestStatsFile is where the watcher persists its rolling per-site request timing snapshot for lerd-ui to read, since the two run as separate processes and only the watcher binds the nginx access feed. Ephemeral, lives in RunDir.
func ReservedHostPorts ¶ added in v1.27.0
ReservedHostPorts returns every host port a lerd service may bind: each configured service entry's effective ports (HostPorts), every bundled preset's default ports (including optional presets not in the default set), and every installed custom service's ports. It is the single shared definition consumed by both the serviceops port-ownership guard and the host-proxy dev-server allocator so the two can never drift — the divergence that previously let the guard shift a built-in onto a stopped custom service's port and collide at boot, since the guard read only cfg.Services while the allocator also covered presets and customs.
func ResolveDynamicEnv ¶ added in v1.9.0
func ResolveDynamicEnv(svc *CustomService) error
ResolveDynamicEnv applies any dynamic_env directives on svc, writing the computed values into svc.Environment. Called immediately before quadlet generation so the resolved values land in the rendered .container file.
func ResolveSiteRef ¶ added in v1.28.1
ResolveSiteRef maps a site reference that may be a name or any of the site's domains to the canonical site name. An unknown reference is returned unchanged, so callers still surface their own "not found" error rather than a rewrite.
func ResolveStripeSecret ¶ added in v1.24.0
ResolveStripeSecret returns the env key name and value of a project's Stripe secret. An explicit secret_env_key in .lerd.yaml wins; otherwise the common candidate keys are probed in .env. An empty value means none is set.
func RunDir ¶ added in v1.15.1
func RunDir() string
RunDir returns the directory for runtime sockets shared between lerd-ui (host process) and lerd-nginx (container). Bind-mounted into lerd-nginx so the lerd.localhost vhost can reach lerd-ui without depending on container → host TCP routing (host.containers.internal / 169.254.1.2), which is unreliable across podman/netavark/pasta versions and host network changes.
func SanitizeImageTag ¶ added in v1.9.0
SanitizeImageTag returns a container-name-safe form of an image tag by replacing every character that systemd/podman do not accept in unit names with a hyphen. "5.7" -> "5-7", "8.0.34" -> "8-0-34", "11.4+focal" -> "11-4-focal".
func SaveCustomService ¶ added in v0.5.4
func SaveCustomService(svc *CustomService) error
SaveCustomService validates and writes a custom service config to disk.
func SaveFramework ¶ added in v1.0.0
SaveFramework writes a framework definition to FrameworksDir()/{name}.yaml. For the laravel built-in, only the Workers field is persisted (other fields come from the built-in definition and are always merged in by GetFramework).
func SaveGlobal ¶
func SaveGlobal(cfg *GlobalConfig) error
SaveGlobal writes the configuration to config.yaml.
func SaveProjectConfig ¶ added in v1.2.0
func SaveProjectConfig(dir string, cfg *ProjectConfig) error
SaveProjectConfig writes cfg to .lerd.yaml in dir.
func SaveSites ¶
func SaveSites(reg *SiteRegistry) error
SaveSites writes the registry to sites.yaml.
func SaveStoreFramework ¶ added in v1.10.0
SaveStoreFramework writes a store-installed framework definition to StoreFrameworksDir(). If the framework has a Version field, the file is named <name>@<version>.yaml. Otherwise it is named <name>.yaml (backwards compatible).
func SaveStorePreset ¶ added in v1.28.1
SaveStorePreset validates raw preset YAML fetched from the external service store and writes it verbatim into the store-cache dir, where the seam then serves it above the embedded bundle. Writing the original bytes (rather than a re-marshal) preserves every field, including any the running binary's Preset struct doesn't yet know about. The name is taken from the argument, not the YAML, so it always matches the on-disk filename the seam looks up.
func ServiceExtraPorts ¶ added in v1.27.0
ServiceExtraPorts returns the extra published port mappings recorded for a service (set via `lerd service expose` or the Web UI ports modal), or nil when none. Applied at the quadlet choke point so every preset-backed service, not just the default-stack ones, honours the same extra-port overrides.
func ServiceFilePath ¶ added in v1.9.0
ServiceFilePath returns the deterministic host path for a single FileMount belonging to the named service. Both the materialiser and the quadlet generator use this so they agree on layout without explicit plumbing.
func ServiceFilesDir ¶ added in v1.9.0
ServiceFilesDir returns the directory holding rendered FileMount content for the named custom service. Each file is bind-mounted into the container at its declared target path.
func ServiceFilesNewestMtime ¶ added in v1.28.1
func ServiceFilesNewestMtime(svc *CustomService) (time.Time, bool)
ServiceFilesNewestMtime returns the most recent modification time across svc's materialised preset files, and whether any exist on disk. Because a re-materialise only rewrites a file whose content actually changed, this mod time advances only on a real config change, so comparing it against a container's start time tells whether the running container is on stale config.
func ServiceIsManuallyStarted ¶ added in v1.0.0
ServiceIsManuallyStarted returns true if the service was explicitly started by the user (via `lerd service start` or the dashboard), making it exempt from auto-stop when no sites reference it.
func ServiceIsPaused ¶ added in v0.6.0
ServiceIsPaused returns true if the service was manually stopped by the user.
func ServiceIsPinned ¶ added in v1.0.0
ServiceIsPinned returns true if the service has been pinned by the user, meaning it will never be auto-stopped even when no sites reference it.
func ServicePublishedPort ¶ added in v1.27.0
ServicePublishedPort returns the published host port a service was pinned to (0 = preset/version default). It is non-zero when the user ran `lerd service port`, or when the port-ownership guard auto-shifted lerd's DB off the engine default because a host server owns it. Readers that surface a host-facing endpoint (a host-proxy app's .env, a connection URL) use it so the port reflects where lerd's container actually listens, not the default a coexisting host server may be sitting on.
func ServicePublishedPorts ¶ added in v1.27.1
ServicePublishedPorts returns the per-container-port host overrides for a service's secondary mappings (nil when none). The primary override lives in ServicePublishedPort; these cover the extra ports a multi-port service exposes.
func ServiceTuningAux ¶ added in v1.23.0
func ServiceTuningAux(svc *CustomService) (target, content string, ok bool)
ServiceTuningAux returns the in-container mount target and content of svc's lerd-managed tuning helper file, and whether one applies. ok is false unless the effective tuningMount declares an AuxTarget (only postgres does today). The matching host file is ServiceTuningAuxFile(svc.Name).
func ServiceTuningAuxFile ¶ added in v1.23.0
ServiceTuningAuxFile returns the host path for a service's lerd-managed tuning helper file — a static config that the family's tuning Command depends on (e.g. the postgres `config_file` wrapper that `include_dir`s the user override directory, because `-c include_dir` is rejected at runtime). Unlike ServiceTuningFile this is regenerated on every start, never user-edited, and lives alongside the override with a distinct `.aux.conf` suffix so it is never mistaken for it.
func ServiceTuningBkpDir ¶ added in v1.23.0
func ServiceTuningBkpDir() string
ServiceTuningBkpDir holds timestamped backups of per-service tuning overrides produced when the user ticks "back up the current file first" before saving in the web UI editor. It lives next to (not inside) the service-tuning/ directory so it cannot be picked up by any future include glob and never gets bind-mounted into the service container, keeping backups invisible to the running service even if it tries to scan its config dir.
func ServiceTuningCommand ¶ added in v1.23.0
func ServiceTuningCommand(svc *CustomService) (command string, ok bool)
ServiceTuningCommand returns the container command that makes svc's image read its tuning override, and whether one applies. ok is false unless the effective tuningMount declares a Command (mysql/mariadb auto-include their conf dir and need none; redis sets one because the image loads no config file by default). Callers should only use it when the service has no Exec of its own.
func ServiceTuningFile ¶ added in v1.23.0
ServiceTuningFile returns the host path for a service's user-editable runtime tuning override. Lerd seeds it once with a commented template and never overwrites it afterwards, so edits survive `lerd service reinstall` and `lerd update` — the same never-clobber contract as NginxCustomD and the per-version PHP 98-user.ini.
func ServiceTuningMount ¶ added in v1.23.0
func ServiceTuningMount(svc *CustomService) (target string, ok bool)
ServiceTuningMount returns the in-container mount target for svc's tuning override and whether the service exposes one. The matching host file is ServiceTuningFile(svc.Name). A service exposes a mount when either it declares one inline via svc.Tuning, or its family is in the built-in tuningMounts map (mysql / mariadb / redis). Returns ok=false otherwise.
func ServiceTuningTemplate ¶ added in v1.23.0
func ServiceTuningTemplate(svc *CustomService) (string, bool)
ServiceTuningTemplate returns the commented template for svc's tuning mount so callers (most notably the Reset endpoint) can restore the file to the "no active directives" state without deleting it. Deleting the file is unsafe in practice because the generated quadlet declares a Volume= bind mount at the same path; a missing source path makes podman refuse to start the container. Overwriting with the template keeps the mount valid while making the service fall back to its bundled defaults. Inline TuningSpec entries with no Template field return ok=true with the empty string, which is still a valid "reset" target.
func ServicesInFamily ¶ added in v1.9.0
ServicesInFamily returns the container hostnames (lerd-<name>) of every installed service that belongs to the named family. Built-ins match against builtinFamilies; custom services match by their Family field, with a fallback that infers family from the name prefix (e.g. mysql-5-7 -> mysql) so services installed before the explicit field existed still discover. Names are returned in deterministic order so the resulting env var stays stable across regenerations.
func SetExtraPresetsForTest ¶ added in v1.28.1
SetExtraPresetsForTest installs (or clears, with nil) the test-only extra preset layer. Production never calls this, so the shipped binary serves only the embedded defaults plus whatever the store fetches into the cache.
func SetProjectCommand ¶ added in v1.21.0
func SetProjectCommand(dir string, cmd FrameworkCommand) error
SetProjectCommand adds or replaces a command in .lerd.yaml's commands: block, matched by Name. Creates the file if it doesn't exist (commands can land on fresh projects, unlike custom workers which presume a registered site).
func SetProjectCustomWorker ¶ added in v1.11.0
func SetProjectCustomWorker(dir string, name string, w FrameworkWorker) error
SetProjectCustomWorker adds or replaces a custom worker entry. No-op if .lerd.yaml does not exist.
func SetProjectDomains ¶ added in v1.11.0
SetProjectDomains replaces the domains list. No-op if .lerd.yaml does not exist.
func SetProjectFrameworkDef ¶ added in v1.11.0
SetProjectFrameworkDef replaces the embedded framework definition. No-op if .lerd.yaml does not exist.
func SetProjectFrameworkVersion ¶ added in v1.11.0
SetProjectFrameworkVersion updates framework_version. No-op if .lerd.yaml does not exist or the version hasn't changed.
func SetProjectJSRuntime ¶ added in v1.25.0
SetProjectJSRuntime pins the JavaScript runtime ("bun" or "node") in .lerd.yaml, preserving every other field (notably node_version). Unlike updateProjectConfig it creates .lerd.yaml when missing so the toggle persists for sites that never had one. Passing "" clears the pin (back to autodetect).
func SetProjectPHPVersion ¶ added in v1.11.0
SetProjectPHPVersion updates php_version. No-op if .lerd.yaml does not exist.
func SetProjectRuntime ¶ added in v1.18.0
SetProjectRuntime updates runtime and runtime_worker. No-op if .lerd.yaml does not exist. Passing an empty runtime clears both fields.
func SetProjectSecured ¶ added in v1.11.0
SetProjectSecured updates the secured field. No-op if .lerd.yaml does not exist.
func SetProjectStripe ¶ added in v1.24.0
SetProjectStripe writes the project's Stripe listener settings (webhook path and/or secret env key) to .lerd.yaml, creating the file if needed. An empty argument leaves the corresponding field untouched; when both are empty this is a no-op so we never materialise an empty "stripe: {}" block or create a .lerd.yaml the project didn't have.
func SetProjectWorkerReload ¶ added in v1.24.0
SetProjectWorkerReload opts the named worker into or out of auto-reload mode (restart on file changes) for the project, persisting to .lerd.yaml. Enabling creates .lerd.yaml when it does not exist yet, so the preference survives rather than silently no-op'ing. Disabling on a project with no .lerd.yaml is a no-op: the worker is already in standard mode, so no file is created.
func SetProjectWorkers ¶ added in v1.11.0
SetProjectWorkers replaces the workers list. No-op if .lerd.yaml does not exist.
func SetServiceManuallyStarted ¶ added in v1.0.0
SetServiceManuallyStarted marks or clears the manually-started flag for the named service.
func SetServicePaused ¶ added in v0.6.0
SetServicePaused marks or clears the manual-stop flag for the named service.
func SetServicePinned ¶ added in v1.0.0
SetServicePinned marks or clears the pinned flag for the named service.
func SetSiteIdleSuspendedWorkers ¶ added in v1.25.0
SetSiteIdleSuspendedWorkers atomically updates just a site's idle-suspended worker list. It reloads the record under the write lock and rewrites only that field, so a stale full-record write (FindSite -> mutate -> AddSite) can't clobber a concurrent change to another field like Paused or Pinned.
func SetSitePinned ¶ added in v1.25.0
SetSitePinned atomically updates just a site's idle-suspend pin flag. Like SetSiteIdleSuspendedWorkers it rewrites only that field under the write lock, so `lerd idle pin/unpin` can't clobber a concurrent SetSiteIdleSuspendedWorkers write the idle engine makes for the same site.
func SetWorktreeDBIsolated ¶ added in v1.19.0
SetWorktreeDBIsolated writes the flag to the worktree's .lerd.yaml, creating the file if missing.
func SetWorktreeIdleSuspendedWorkers ¶ added in v1.25.0
SetWorktreeIdleSuspendedWorkers atomically updates a single worktree's idle-suspended worker list (keyed by the worktree's unit-slug base). Passing an empty list clears that worktree's entry, and clearing the last entry drops the map, so a resumed worktree leaves no residue in sites.yaml. Uses the same write lock as the other registry mutators.
func SetWorktreeNodeVersion ¶ added in v1.19.0
SetWorktreeNodeVersion mirrors SetWorktreePHPVersion for Node.
func SetWorktreePHPVersion ¶ added in v1.19.0
SetWorktreePHPVersion writes the override to the worktree's .lerd.yaml, creating the file if missing. Passing "" clears the override. Unlike SetProjectPHPVersion this always materialises the file.
func SitePHPUserIniBkpDir ¶ added in v1.25.0
SitePHPUserIniBkpDir holds timestamped backups of a site's per-site user ini, next to (not inside) the file so the container's conf.d scan never loads them.
func SitePHPUserIniFile ¶ added in v1.25.0
SitePHPUserIniFile is the per-site user php.ini for a runtime site that runs its own container (FrankenPHP). Unlike PHPUserIniFile (shared by every site on a PHP version), this is scoped to one site so its php.ini is independent.
func SiteSlug ¶ added in v1.20.0
SiteSlug converts a name (site name, branch, directory basename, or domain) to a database-safe, underscore-separated slug. It lowercases and maps every character outside [a-z0-9_] to an underscore, extending the long-standing hyphen/dot-to-underscore convention to all separators. The mapping matters for security: slugs flow into shell-run site_init commands and SQL identifiers, so a name carrying a backtick, quote, semicolon, or $(...) must not survive into those sinks. Mapping (rather than dropping) keeps slashed branches like "feature/x" collision-free as "feature_x".
func SitesUsingFramework ¶ added in v1.27.0
SitesUsingFramework returns the names of active sites whose framework field matches name. Ignored entries (parked directories that were unlinked) are not served, so they do not count as usage. It is the basis for the remove confirmation and prune.
func SkipSourceDir ¶ added in v1.25.0
SkipSourceDir reports whether a directory should not be watched or descended when walking a source tree: an excluded name, or any hidden (dot-prefixed) directory such as .git, .vite, .next, or editor metadata.
func SnapshotsDir ¶ added in v1.22.0
func SnapshotsDir() string
SnapshotsDir returns the directory where db:snapshot point-in-time database copies are stored, organised per service and database scope.
func SourceWatchRoots ¶ added in v1.25.0
SourceWatchRoots returns the absolute, existing source directories to watch for a checkout rooted at root, using the framework's declared source_dirs or the default set when it declares none.
func SpxAssetsDir ¶ added in v1.22.0
func SpxAssetsDir() string
SpxAssetsDir returns the host directory holding the SPX profiler conf.d ini and the generated http key. The ini is bind-mounted read-only into every FPM container.
func SpxDataDir ¶ added in v1.22.0
func SpxDataDir() string
SpxDataDir is the host directory SPX writes profile reports into. Mounted read-write into every FPM container at /var/spx.
func SpxIniFile ¶ added in v1.22.0
func SpxIniFile() string
SpxIniFile is the host path for the SPX conf.d ini.
func SpxKeyFile ¶ added in v1.22.0
func SpxKeyFile() string
SpxKeyFile holds the generated SPX http key.
func StoreFrameworksDir ¶ added in v1.10.0
func StoreFrameworksDir() string
StoreFrameworksDir returns the directory for store-installed framework YAML files.
func StoreIndexFile ¶ added in v1.28.1
func StoreIndexFile() string
StoreIndexFile returns the path to the locally cached framework store index. The store package refreshes it in the background; offline detection and listing read it so a fresh machine can resolve any framework without a definition already on disk.
func StorePresetsDir ¶ added in v1.28.1
func StorePresetsDir() string
StorePresetsDir returns the directory for store-installed service-preset YAML files, fetched from the external service store. It sits under the preset-source seam as a layer above the embedded bundle: a valid preset here is served in place of (or in addition to) the built-in of the same name, while the embed bundle stays as the permanent offline fallback. Distinct from ConfigDir()/services (user-defined custom services) so store presets and user services never mix.
func StripeSecretSet ¶ added in v1.24.0
StripeSecretSet reports whether a project has a Stripe secret in .env under its configured or any recognised env key.
func StripeWebhookPath ¶ added in v1.24.0
StripeWebhookPath returns the configured webhook route for a project, or DefaultStripeWebhookPath when none is set. The stored value is normalised to a leading slash so a hand-edited ".lerd.yaml" can't yield a slash-less URL like "https://site.teststripe/webhook".
func SyncProjectDomains ¶ added in v1.11.0
SyncProjectDomains merges fullDomains (stripping the TLD suffix) with any existing .lerd.yaml domains, deduplicating case-insensitively. Registered domains come first; pre-existing entries not in the registered list are appended (conflict-filtered domains preserved for self-healing). No-op if .lerd.yaml does not exist.
func SystemdUserDir ¶
func SystemdUserDir() string
SystemdUserDir returns the systemd user unit directory.
func TuningFamilies ¶ added in v1.23.0
func TuningFamilies() []string
TuningFamilies returns the sorted list of service families that expose a tuning override. Callers use it to render an honest "supported: …" hint in error messages, so it stays in sync as new families are added to tuningMounts.
func UIClientAddr ¶ added in v1.27.0
func UIClientAddr() string
UIClientAddr is the address paired with UIClientNetwork.
func UIClientNetwork ¶ added in v1.27.0
func UIClientNetwork() string
UIClientNetwork / UIClientAddr give the transport a CLI process uses to reach the running lerd-ui daemon. On macOS the unix socket is never created (the server binds it Linux-only, see internal/ui/server.go), so the CLI dials the same TCP loopback the dashboard uses; on Linux it stays on the unix socket. Mirrors the DumpsListenNetwork/Addr split. The port matches lerd-ui's fixed listen port (internal/ui/server.go listenAddr).
func UISocketPath ¶ added in v1.15.1
func UISocketPath() string
UISocketPath returns the path to the lerd-ui unix domain socket.
func UnusedInstalledFrameworks ¶ added in v1.27.0
func UnusedInstalledFrameworks() []string
UnusedInstalledFrameworks returns installed framework names that no active site references, sorted. Built-in frameworks are never included.
func UpdateCheckFile ¶ added in v0.9.0
func UpdateCheckFile() string
UpdateCheckFile returns the path to the cached update-check state file.
func ValidateCustomService ¶ added in v1.24.0
func ValidateCustomService(svc *CustomService) error
ValidateCustomService refuses newline/NUL in any field that reaches the generated quadlet, so a cloned repo's inline service can't inject systemd directives. Run on save and again at the quadlet boundary (post dynamic_env).
func ValidatePresetYAML ¶ added in v1.19.0
ValidatePresetYAML parses and validates raw preset YAML, returning a descriptive error on the first issue found. Exposed for tests that need to assert validation rules without round-tripping through the embed FS.
func ValidatePublicDir ¶ added in v1.21.0
ValidatePublicDir returns nil when s is a safe relative subdirectory and an error otherwise. A malicious .lerd.yaml could otherwise pivot the nginx document root out of the project with `public_dir: ../../etc`. Callers should reject the config or fall back to the framework default on error.
func ValidateStripeWebhookPath ¶ added in v1.24.0
ValidateStripeWebhookPath normalises a webhook route to a leading slash and rejects whitespace, which would otherwise break the systemd ExecStart line the path is interpolated into (a space adds an argument, a newline ends the directive). An empty path is returned unchanged for callers that leave it unset.
func WatcherNeedsPolling ¶ added in v1.25.0
WatcherNeedsPolling reports whether a file-change watcher has to poll because host filesystem events don't reach the process watching them: always on macOS (the runtime runs inside the podman VM) and on WSL2 only for projects under a /mnt (9p) mount, where inotify isn't delivered. This is the canonical home for the predicate; cli.watcherNeedsPolling delegates here so the Horizon and Octane reload paths agree.
func WorktreeDBIsolated ¶ added in v1.19.0
WorktreeDBIsolated reports whether the worktree at the given path opted into its own database. Returns false when .lerd.yaml is missing or the flag is unset.
func WorktreeDBRegistryPath ¶ added in v1.19.0
func WorktreeDBRegistryPath() string
WorktreeDBRegistryPath returns the path to the per-user worktree DB registry.
func WorktreeLANRegistryPath ¶ added in v1.19.0
func WorktreeLANRegistryPath() string
WorktreeLANRegistryPath returns the path to the per-user LAN-share registry.
func WorktreeNodeVersion ¶ added in v1.19.0
WorktreeNodeVersion mirrors WorktreePHPVersion for Node. No nginx side effects, but the same precedence so `lerd sites` and the dashboard report the worktree's effective version rather than the parent's.
func WorktreePHPVersion ¶ added in v1.19.0
WorktreePHPVersion returns the worktree's effective PHP version: the override from its .lerd.yaml when set, otherwise fallback (the parent's). Used by every code path that materialises worktree state on disk.
func WorktreeUnitSlug ¶ added in v1.24.0
WorktreeUnitSlug sanitizes a worktree directory basename for use inside a systemd unit name, which treats a dot as the start of the unit-type suffix. Only dots are rewritten, so dot-free worktree dirs keep their existing unit names (no migration needed) while domain-named dirs (api.gonitro.com-feat) stop producing invalid unit names.
Types ¶
type ClientShim ¶ added in v1.28.1
type ClientShim struct {
Name string `yaml:"name" json:"name"`
Binaries []string `yaml:"binary,omitempty" json:"binary,omitempty"`
}
ClientShim declares a service client tool that lerd exposes as a host shim. Name is the command written onto the host PATH; Binaries are the candidate binaries to resolve inside the service container, tried in order, so a mariadb service can back the mysqldump shim with mariadb-dump. In YAML a bare string is shorthand for a shim whose host name and container binary are identical.
func (*ClientShim) UnmarshalYAML ¶ added in v1.28.1
func (c *ClientShim) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML accepts either a bare string (name == binary) or a mapping with an explicit name and one or more candidate binaries.
type CommandNotFoundError ¶ added in v1.21.0
type CommandNotFoundError struct{ Name string }
CommandNotFoundError is returned when a project command name is not in .lerd.yaml.
func (*CommandNotFoundError) Error ¶ added in v1.21.0
func (e *CommandNotFoundError) Error() string
type CommandValidationError ¶ added in v1.21.0
type CommandValidationError struct{ Reason string }
CommandValidationError flags structural problems before we touch the yaml.
func (*CommandValidationError) Error ¶ added in v1.21.0
func (e *CommandValidationError) Error() string
type ContainerConfig ¶ added in v1.15.0
type ContainerConfig struct {
Port int `yaml:"port"` // port the app listens on inside the container (required)
Containerfile string `yaml:"containerfile,omitempty"` // path to Containerfile, default "Containerfile.lerd"
BuildContext string `yaml:"build_context,omitempty"` // build context directory, default "."
Target string `yaml:"target,omitempty"` // multi-stage build target passed as --target to podman build
SSL bool `yaml:"ssl,omitempty"` // proxy to the container via HTTPS (app serves TLS on its port)
}
ContainerConfig holds per-project custom container settings. When present in .lerd.yaml the site gets its own dedicated container built from the user's Containerfile, and nginx reverse-proxies to it instead of using the shared PHP-FPM image.
type CustomService ¶ added in v0.5.4
type CustomService struct {
Name string `yaml:"name"`
Image string `yaml:"image"`
Ports []string `yaml:"ports,omitempty"`
Environment map[string]string `yaml:"environment,omitempty"`
DataDir string `yaml:"data_dir,omitempty"`
Exec string `yaml:"exec,omitempty"`
EnvVars []string `yaml:"env_vars,omitempty"`
EnvDetect *EnvDetect `yaml:"env_detect,omitempty"`
SiteInit *SiteInit `yaml:"site_init,omitempty"`
Dashboard string `yaml:"dashboard,omitempty"`
ConnectionURL string `yaml:"connection_url,omitempty"`
Description string `yaml:"description,omitempty"`
DependsOn []string `yaml:"depends_on,omitempty"`
// Files is deprecated as a YAML user field but kept with its yaml tag so
// LoadCustomServiceFromFile can detect legacy on-disk entries and migrate
// them away. The authoritative source of file mounts is presetFiles in
// preset_files.go, looked up by Preset at materialise time.
Files []FileMount `yaml:"files,omitempty"`
// Family groups related services so admin UIs can auto-discover every
// member. e.g. the mysql preset declares family: mysql, and phpMyAdmin
// uses dynamic_env to read all family members at quadlet generation time.
Family string `yaml:"family,omitempty"`
// Tuning, when set, exposes a user-editable runtime config override
// for this service via the web UI's Config tab and the
// `lerd service config` CLI. Custom services declare their own
// override path here without needing a known family — the built-in
// mysql/mariadb/redis families remain the fallback when this is nil.
// See ServiceTuningMount / ServiceTuningTemplate / ServiceTuningCommand.
Tuning *TuningSpec `yaml:"tuning,omitempty"`
// Preset is the bundled preset name this service was installed from.
// Set by InstallPresetByName. Used so the init wizard can store a
// preset reference in .lerd.yaml instead of an inlined definition.
Preset string `yaml:"preset,omitempty"`
// PresetVersion is the picked version tag for multi-version presets.
// Empty for single-version presets.
PresetVersion string `yaml:"preset_version,omitempty"`
// PreviousImage is set by the update flow to the image that was running
// before the last update, so a one-click rollback can swap back to it.
// Toggled on each rollback so consecutive rollbacks redo the update.
PreviousImage string `yaml:"previous_image,omitempty"`
// LastOp is "update" or "migrate" — set by serviceops to mark whether the
// most recent change is rollback-safe. Migrate is one-way: rolling back the
// image without restoring the pre-migrate data dir would run the old binary
// against the new schema, so the rollback path refuses unless this is empty
// or "update".
LastOp string `yaml:"last_op,omitempty"`
// PreMigrateBackup is the absolute host path to the data dir that was
// preserved when the most recent op was a migrate.
PreMigrateBackup string `yaml:"pre_migrate_backup,omitempty"`
// (~/.local/share/lerd/browser-hosts) into the container at /etc/hosts,
// so the container can resolve .test domains to the nginx container's IP
// on the Podman network. Used by browser testing services like Selenium
// that need to reach lerd sites by domain name.
ShareHosts bool `yaml:"share_hosts,omitempty" json:"share_hosts,omitempty"`
// DynamicEnv declares container env vars whose value is computed at
// quadlet generation time. Currently supported directive:
// discover_family:<name> -> comma-joined hostnames of every installed
// service in the named family (built-in or custom).
DynamicEnv map[string]string `yaml:"dynamic_env,omitempty"`
// Userns sets the quadlet UserNS= line verbatim, e.g. "keep-id:uid=1000,gid=0"
// for images whose process runs as a non-root UID and needs that UID
// mapped to the host user for bind-mounted volumes.
Userns string `yaml:"userns,omitempty"`
// ChownData adds :U to the data_dir mount so podman re-chowns the host
// directory to the container's expected UID at mount time. Pair with
// Userns to keep bind-mounted data writable to non-root container users.
ChownData bool `yaml:"chown_data,omitempty"`
// DashboardExternal opens the dashboard URL in a new browser tab instead
// of embedding it as an iframe. Use for admin UIs that set session
// cookies the iframe can't carry across origins (e.g. RabbitMQ Cowboy).
DashboardExternal bool `yaml:"dashboard_external,omitempty" json:"dashboard_external,omitempty"`
// Init injects podman's catatonit as PID 1 (--init) so SIGTERM gets
// forwarded to the container's main process. Required for images whose
// main binary (e.g. mysqld in mysql:8.4) doesn't install a signal
// handler when it runs as PID 1, which makes podman stop time out and
// systemctl restart wedge for ~90s.
Init bool `yaml:"init,omitempty" json:"init,omitempty"`
// ClientShims lists the client tools this service exposes as host shims
// (mysqldump, pg_dump, psql…) so host tools and IDEs can run them against
// external databases. Empty for services with nothing to expose.
ClientShims []ClientShim `yaml:"client_shims,omitempty" json:"client_shims,omitempty"`
}
CustomService represents a user-defined OCI-based service.
func DefaultPresetMeta ¶ added in v1.19.0
func DefaultPresetMeta(name string) (*CustomService, error)
DefaultPresetMeta returns the resolved canonical CustomService for a default preset by name. The resolved service carries the preset's env_vars, dashboard, connection_url, ports and family, plus any platform image override. Returns an error for unknown or non-default preset names.
The result is the canonical instance only — it does not consult the user's global config Services map for image overrides. Callers that need user overrides applied should layer that on themselves; serviceops.EnsureDefaultPresetQuadlet (introduced in Phase C) is the integration point.
func ListCustomServices ¶ added in v0.5.4
func ListCustomServices() ([]*CustomService, error)
ListCustomServices returns all custom services defined in the services directory.
func LoadCustomService ¶ added in v0.5.4
func LoadCustomService(name string) (*CustomService, error)
LoadCustomService loads a custom service by name from the services directory.
func LoadCustomServiceFromFile ¶ added in v0.5.4
func LoadCustomServiceFromFile(path string) (*CustomService, error)
LoadCustomServiceFromFile parses a CustomService from any YAML file path.
files: is an internal mechanism for bundled presets only and is not a user feature. Any files: entries in the on-disk YAML are stripped on load (and the file re-saved without them) so the hardcoded Go definitions in presetFiles are the single source of truth.
func ResolveServiceForTuning ¶ added in v1.23.0
func ResolveServiceForTuning(name string) (*CustomService, error)
ResolveServiceForTuning loads the service definition behind name for tuning purposes, whether it is a user custom service (a YAML in the services dir) or a built-in default preset (e.g. the default mysql, which has no YAML on disk). Both kinds render their quadlet through EnsureCustomServiceQuadlet, so the resolved value carries the Family that ServiceTuningMount keys off.
type DoctorCheck ¶ added in v1.27.0
type DoctorCheck struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Label string `yaml:"label,omitempty"`
// Fix names a command from the framework's command set a UI can run to
// resolve the finding, so the doctor never grows its own mutation endpoints.
Fix string `yaml:"fix,omitempty"`
// Detail overrides the generated finding message when set.
Detail string `yaml:"detail,omitempty"`
// Severity overrides the triggered status ("warn" or "fail"); each type has
// a sensible default (command→fail, the rest→warn).
Severity string `yaml:"severity,omitempty"`
// env_key_set
EnvKey string `yaml:"env_key,omitempty"`
// env_combo
When map[string]string `yaml:"when,omitempty"`
WarnIf map[string]string `yaml:"warn_if,omitempty"`
// symlink
Link string `yaml:"link,omitempty"`
Target string `yaml:"target,omitempty"`
RequiresDir string `yaml:"requires_dir,omitempty"`
// command
Command string `yaml:"command,omitempty"`
FailIfOutputContains string `yaml:"fail_if_output_contains,omitempty"`
UnknownOnError bool `yaml:"unknown_on_error,omitempty"`
TimeoutSeconds int `yaml:"timeout,omitempty"`
}
DoctorCheck is one declarative health check; Type selects the evaluator (env_key_set, env_combo, symlink, command) and which other fields apply.
type EnvDetect ¶ added in v0.5.4
type EnvDetect struct {
Key string `yaml:"key,omitempty"`
ValuePrefix string `yaml:"value_prefix,omitempty"`
// Composer triggers detection when the named package is present in the
// project's composer.json (require or require-dev). Used instead of Key
// when the service should be auto-detected by a dependency rather than
// an existing .env variable (e.g. selenium detected via laravel/dusk).
Composer string `yaml:"composer,omitempty"`
}
EnvDetect defines auto-detection rules for `lerd env`.
type EnvKeyGeneration ¶ added in v1.10.0
type EnvKeyGeneration struct {
EnvKey string `yaml:"env_key"` // env var to check/set (e.g. "APP_KEY")
Command string `yaml:"command,omitempty"` // console command to run if vendor/ exists, via the framework's console binary (e.g. "key:generate")
FallbackPrefix string `yaml:"fallback_prefix,omitempty"` // prefix for random key fallback (e.g. "base64:")
}
EnvKeyGeneration describes how to generate an application encryption key.
type FileMount ¶ added in v1.9.0
type FileMount struct {
// Target is the absolute path inside the container where the file appears.
Target string `yaml:"target"`
// Content is the literal file body, written verbatim. Ignored when
// ContentFn is set.
Content string `yaml:"content"`
// ContentFn dynamically generates the file body at materialise time
// based on the resolved service (e.g. to inject family-discovered
// hosts into pgAdmin's servers.json). Not loadable from YAML directly;
// a preset selects one by name via Generator.
ContentFn func(*CustomService) (string, error) `yaml:"-"`
// Generator names a built-in content generator (see presetFileGenerators)
// for dynamic mounts a preset can't express as static Content, such as
// pgAdmin's family-discovered servers.json. Resolved to ContentFn when the
// preset's files are read; an unknown name is skipped, not fatal, so a store
// preset built for a newer lerd degrades gracefully.
Generator string `yaml:"generator,omitempty"`
// Mode is the octal permission bits, e.g. "0600". Defaults to "0644".
Mode string `yaml:"mode,omitempty"`
// Chown adds the :U flag to the volume mount so podman re-chowns the file
// to match the container's expected UID. Required when the in-container
// process runs as a non-root user (e.g. pgAdmin runs as uid 5050) and the
// file mode would otherwise hide it from that user (e.g. 0600).
Chown bool `yaml:"chown,omitempty"`
}
FileMount is a single file rendered to disk on the host and bind-mounted into a custom service container. It exists so presets can ship config files (e.g. pgAdmin's servers.json, a pgpass) without requiring the user to manage any host paths themselves.
func PresetFiles ¶ added in v1.13.0
PresetFiles returns the file mounts declared in the named preset's YAML, with each mount's `generator:` resolved to its ContentFn. It reads the preset fresh (embed bundle or store cache) so updating lerd, or the store definition, rolls out new file contents on the next service start without a reinstall. A mount naming an unknown generator is skipped rather than mounted empty, so a store preset built for a newer lerd degrades gracefully. Only presets carry files; custom services have any files: block stripped on load (see LoadCustomService).
type Framework ¶ added in v1.0.0
type Framework struct {
Name string `yaml:"name"`
Label string `yaml:"label"`
// Version is the framework major version this definition targets (e.g. "11", "7").
Version string `yaml:"version,omitempty"`
// DetectedVersion is the project's real major version when it differs from
// Version because no exact definition existed and we clamped to the nearest
// available one. Runtime only, never serialized.
DetectedVersion string `yaml:"-"`
// VersionGuessed is true when Version was clamped to a borrowed definition
// because the detected version had none of its own (Laravel 6 served by the
// Laravel 10 definition); callers must not clamp PHP to its range.
VersionGuessed bool `yaml:"-"`
// PHP defines the supported PHP version range for this framework version.
PHP FrameworkPHP `yaml:"php,omitempty"`
Detect []FrameworkRule `yaml:"detect,omitempty"`
PublicDir string `yaml:"public_dir"`
// SourceDirs overrides which project directories the activity watcher treats
// as source for idle-suspend (a save there keeps the site awake). When empty,
// config.DefaultSourceDirs applies. Paths are relative to the project root.
SourceDirs []string `yaml:"source_dirs,omitempty"`
Env FrameworkEnvConf `yaml:"env,omitempty"`
Composer string `yaml:"composer,omitempty"` // auto | true | false
NPM string `yaml:"npm,omitempty"` // auto | true | false
Workers map[string]FrameworkWorker `yaml:"workers,omitempty"`
Setup []FrameworkSetupCmd `yaml:"setup,omitempty"`
// Commands are on-demand actions surfaced in the dashboard "Run command"
// dropdown. See FrameworkCommand for the schema. Projects extend or
// override this list in .lerd.yaml; use ResolveCommands to merge.
Commands []FrameworkCommand `yaml:"commands,omitempty"`
// Console is the console command to run (without 'php' prefix).
// Example: "artisan", "bin/console"
Console string `yaml:"console,omitempty"`
// Tinker, when set, defines how to run an interactive PHP REPL for
// this framework (the in-browser Tinker tab + `lerd tinker` CLI).
// Absent → fall back to plain `php` execution.
Tinker *FrameworkTinker `yaml:"tinker,omitempty"`
// Create is the scaffold command used by "lerd new". The target directory is appended automatically.
// Example: "composer create-project --no-install --no-plugins --no-scripts laravel/laravel"
Create string `yaml:"create,omitempty"`
// Logs defines where application log files live for this framework.
Logs []FrameworkLogSource `yaml:"logs,omitempty"`
// Favicon is the path to the favicon file relative to the public directory.
// When set, detectFavicon checks this path in addition to the standard candidates.
// Example: "core/misc/favicon.ico" for Drupal.
Favicon string `yaml:"favicon,omitempty"`
// FrankenPHP, when set, tells lerd how to start a FrankenPHP container
// for this framework. When absent, lerd falls back to the generic
// `frankenphp php-server -r <public>/` entrypoint.
FrankenPHP *FrameworkFrankenPHP `yaml:"frankenphp,omitempty"`
// Doctor, when set, declares framework-specific health checks the site
// doctor runs in addition to the universal defaults (env, dependency, and
// audit checks every framework gets). See FrameworkDoctor.
Doctor *FrameworkDoctor `yaml:"doctor,omitempty"`
}
Framework describes a PHP project framework type.
func GetFramework ¶ added in v1.0.0
GetFramework returns the framework definition for the given name. It loads the base definition from the built-in (laravel), store, or user dir, then merges any user-defined overlay on top. The overlay can add/override workers and setup commands without replacing the entire definition. Returns (nil, false) if the framework is not found.
func GetFrameworkForDir ¶ added in v1.10.0
GetFrameworkForDir is like GetFramework but auto-detects the framework version from composer.lock in projectDir. If a version-specific store definition exists it is preferred over an unversioned one. User overlay workers are always merged. When a version is detected but no local definition exists, it attempts to fetch the definition from the store automatically.
func ListFrameworks ¶ added in v1.0.0
func ListFrameworks() []*Framework
ListFrameworks returns all available framework definitions: the built-in frameworks plus any user-defined YAMLs in FrameworksDir().
func LoadUserFramework ¶ added in v1.10.0
LoadUserFramework loads a user-defined framework from FrameworksDir(). Returns nil if not found.
func SanitizeProjectFrameworkDef ¶ added in v1.27.0
SanitizeProjectFrameworkDef returns a copy of an embedded framework_def that is safe to install into the store. A .lerd.yaml is untrusted, so command-type doctor checks (which the site doctor would run on the host) are stripped. The original is left untouched so config diffs and round-trips see the real file.
func (*Framework) DetectProxy ¶ added in v1.10.0
func (fw *Framework) DetectProxy(dir string) (*WorkerProxy, string)
WorkerProxy returns the proxy configuration for the first worker that has one and whose check rule passes for the project at dir. Returns nil if no proxy is configured.
func (*Framework) FrankenPHPEntrypoint ¶ added in v1.18.0
FrankenPHPEntrypoint returns the argv to launch inside the FrankenPHP container for this framework, preferring the worker entrypoint when worker mode is requested and the framework declares support. A generic fallback uses `frankenphp php-server` rooted at the framework's PublicDir.
func (*Framework) FrankenPHPEnv ¶ added in v1.18.0
FrankenPHPEnv returns the environment variables to set in the FrankenPHP container, merging WorkerEnv on top of Env when worker mode is requested.
func (*Framework) HasWorker ¶ added in v1.10.0
HasWorker returns true if the framework defines a worker with the given name and (if the worker has a Check rule) the check passes for the project at dir.
func (*Framework) ResolveFrankenPHPWorkerEntrypoint ¶ added in v1.25.0
ResolveFrankenPHPWorkerEntrypoint returns the entrypoint to launch inside the FrankenPHP container, substituting the watch-enabled variant (WorkerReloadEntrypoint) for WorkerEntrypoint when the site is in worker mode, the framework declares a watch variant, and the project has opted the "octane" worker into reload. On hosts where the container can't observe host filesystem events it appends Octane's --poll flag, mirroring how Horizon's resolveWorkerCommand handles polling.
When reload is requested but chokidar is absent it silently falls back to the standard entrypoint; the enable paths (cli.ApplyOctaneReload and the UI) refuse up front when chokidar is missing, so the displayed state never diverges from what actually runs.
type FrameworkCommand ¶ added in v1.21.0
type FrameworkCommand struct {
Name string `yaml:"name" json:"name"` // stable identifier, also the `lerd run` argument
Label string `yaml:"label" json:"label"` // human label shown in the UI
Command string `yaml:"command" json:"command"` // shell command, passed to `sh -c`
Description string `yaml:"description,omitempty" json:"description,omitempty"` // one-line description for tooltips
Output string `yaml:"output,omitempty" json:"output,omitempty"` // silent | text | url | terminal (default: silent)
Confirm bool `yaml:"confirm,omitempty" json:"confirm,omitempty"` // gate behind a confirm modal before running
Icon string `yaml:"icon,omitempty" json:"icon,omitempty"` // icon name from the known set
Check *FrameworkRule `yaml:"check,omitempty" json:"check,omitempty"` // hide the command when this rule fails
CWD string `yaml:"cwd,omitempty" json:"cwd,omitempty"` // working dir relative to project root (default: ".")
// Disabled, in a project .lerd.yaml entry, suppresses the framework default
// of the same Name without replacing it. Ignored when read from a framework yaml.
Disabled bool `yaml:"disabled,omitempty" json:"disabled,omitempty"`
// ProjectOrigin marks a command that came from the untrusted project .lerd.yaml
// (top-level commands or framework_def), so the host-execution gate can require
// consent before running it. Never persisted; set only at the merge point.
ProjectOrigin bool `yaml:"-" json:"-"`
}
FrameworkCommand describes a one-shot, on-demand action surfaced in the dashboard "Commands" dropdown and as `lerd run <name>`. The framework yaml ships canonical defaults; projects extend or override them by name in .lerd.yaml. Distinct from FrameworkWorker (long-running) and FrameworkSetupCmd (install-time only).
func ResolveCommands ¶ added in v1.21.0
func ResolveCommands(fw *Framework, proj *ProjectConfig, projectDir string) []FrameworkCommand
ResolveCommands merges the framework's command set with project-level entries from .lerd.yaml. Rules:
- Project entry with the same Name as a framework entry fully replaces it.
- Project entry with Disabled=true suppresses the framework default and does not contribute a runnable command.
- Project entries with no matching framework entry are appended.
- Framework entries with a failing Check are dropped before merging.
The resulting slice preserves framework ordering, with project-only additions appended in declaration order.
type FrameworkDoctor ¶ added in v1.27.0
type FrameworkDoctor struct {
Checks []DoctorCheck `yaml:"checks,omitempty"`
}
FrameworkDoctor declares a framework's site-doctor checks, run after the universal baseline (env, dependency install/lock, audit, PHP range) that every framework gets. Keeping it declarative means new frameworks need no Go change.
type FrameworkEnvConf ¶ added in v1.0.0
type FrameworkEnvConf struct {
File string `yaml:"file,omitempty"` // primary env file (relative to project)
ExampleFile string `yaml:"example_file,omitempty"` // example to copy from if File missing
Format string `yaml:"format,omitempty"` // dotenv | php-const (default: dotenv)
FallbackFile string `yaml:"fallback_file,omitempty"` // used when File doesn't exist
FallbackFormat string `yaml:"fallback_format,omitempty"` // format for FallbackFile
// URLKey is the env key that holds the application URL (default: APP_URL).
URLKey string `yaml:"url_key,omitempty"`
// Vars are unconditional KEY=VALUE env defaults the framework always wants
// applied during `lerd env`, regardless of which services are detected
// (e.g. CodeIgniter's CI_ENVIRONMENT=development for local dev). They
// support the same {{...}} template placeholders as service vars and are
// applied as defaults, so detected-service values and personal
// .env.lerd_override entries still win over them.
Vars []string `yaml:"vars,omitempty"`
// Services defines per-service detection rules and env vars to apply.
// Keys match the built-in service names: mysql, postgres, redis, meilisearch, rustfs, mailpit.
Services map[string]FrameworkServiceDef `yaml:"services,omitempty"`
// KeyGeneration describes how to generate an application key if missing.
KeyGeneration *EnvKeyGeneration `yaml:"key_generation,omitempty"`
}
FrameworkEnvConf describes how the framework manages its env file.
func (FrameworkEnvConf) Resolve ¶ added in v1.0.0
func (e FrameworkEnvConf) Resolve(projectDir string) (file, format string)
Resolve returns the env file path and format to use for the given project directory. It returns the primary file if it exists, otherwise the fallback. Defaults to ".env" with "dotenv" format if nothing is configured.
type FrameworkFetchFunc ¶ added in v1.10.0
FrameworkFetchFunc is a callback that fetches a framework definition from the store and saves it locally. It is called when GetFrameworkForDir cannot find a local definition for the detected version. The store package registers this at startup to avoid a circular import.
type FrameworkFile ¶ added in v1.10.0
type FrameworkFile struct {
Path string
Version string // "" for unversioned
Source FrameworkSource
}
FrameworkFile describes a framework definition file on disk.
func ListFrameworkFiles ¶ added in v1.10.0
func ListFrameworkFiles(name string) []FrameworkFile
ListFrameworkFiles returns all definition files for a framework across user and store directories.
type FrameworkFrankenPHP ¶ added in v1.18.0
type FrameworkFrankenPHP struct {
// Entrypoint is the command to run when the site is served in normal
// (non-worker) FrankenPHP mode. Example: ["php","artisan","octane:start",
// "--server=frankenphp","--host=0.0.0.0","--port=8000"].
Entrypoint []string `yaml:"entrypoint,omitempty"`
// WorkerEntrypoint, when set and the site opts into worker mode, is used
// instead of Entrypoint. When SupportsWorker is false the flag is ignored.
WorkerEntrypoint []string `yaml:"worker_entrypoint,omitempty"`
// WorkerReloadEntrypoint, when set, is the watch-enabled variant of
// WorkerEntrypoint, selected instead of it when the project opts the
// "octane" worker into auto-reload (restart on file changes) for
// development. Keeping the watch flag in the framework definition rather
// than rewriting WorkerEntrypoint in Go means the store stays the single
// source of truth for what runs; core only appends the platform polling
// flag on hosts where the container can't observe filesystem events (see
// ResolveFrankenPHPWorkerEntrypoint). Laravel sets it to the octane:start
// command with --watch.
WorkerReloadEntrypoint []string `yaml:"worker_reload_entrypoint,omitempty"`
// SupportsWorker declares whether the framework ships a FrankenPHP worker
// script. If false, `--worker` is a no-op and the regular entrypoint is used.
SupportsWorker bool `yaml:"supports_worker,omitempty"`
// Env is the list of environment variables to set in the container in
// normal mode (appended to the defaults lerd always sets).
Env map[string]string `yaml:"env,omitempty"`
// WorkerEnv, when the site opts into worker mode, is merged on top of Env.
// Example for Symfony: {"FRANKENPHP_CONFIG": "worker ./public/index.php"}.
WorkerEnv map[string]string `yaml:"worker_env,omitempty"`
}
FrameworkFrankenPHP describes how to serve the framework via FrankenPHP. Entrypoints are shell-quoted strings executed inside the container; the working directory is the project root mounted at the same path as the host.
type FrameworkInfo ¶ added in v1.10.0
type FrameworkInfo struct {
*Framework
Source FrameworkSource
}
FrameworkInfo holds a framework definition together with its source metadata.
func ListFrameworksDetailed ¶ added in v1.10.0
func ListFrameworksDetailed() []FrameworkInfo
ListFrameworksDetailed returns all available framework definitions with source info. Frameworks with a store base + user overlay show as "store" with merged workers.
type FrameworkLogSource ¶ added in v1.7.0
type FrameworkLogSource struct {
Path string `yaml:"path"` // glob relative to project root, e.g. "storage/logs/*.log"
Format string `yaml:"format,omitempty"` // "monolog" | "raw" (default: "raw")
}
FrameworkLogSource describes where application log files live for a framework.
type FrameworkPHP ¶ added in v1.10.0
type FrameworkPHP struct {
Min string `yaml:"min,omitempty"` // minimum PHP version (e.g. "8.2")
Max string `yaml:"max,omitempty"` // maximum PHP version (e.g. "8.4")
}
FrameworkPHP defines the supported PHP version range for a framework version.
type FrameworkRule ¶ added in v1.0.0
type FrameworkRule struct {
File string `yaml:"file,omitempty" json:"file,omitempty"` // file must exist in project root
Composer string `yaml:"composer,omitempty" json:"composer,omitempty"` // package must be in composer.json require/require-dev
ComposerSections []string `yaml:"composer_sections,omitempty" json:"composer_sections,omitempty"` // extra composer.json keys to search (e.g. flex-require)
VersionKey string `yaml:"version_key,omitempty" json:"version_key,omitempty"` // dot-path to version in composer.json (e.g. extra.symfony.require)
VersionFile string `yaml:"version_file,omitempty" json:"version_file,omitempty"` // file to read version from (relative to project root)
VersionPattern string `yaml:"version_pattern,omitempty" json:"version_pattern,omitempty"` // regex with capture group for version (e.g. "\\$wp_version = '([^']+)'")
}
FrameworkRule is a single detection rule for a framework. Any matching rule is sufficient to identify the framework.
type FrameworkServiceDef ¶ added in v1.0.0
type FrameworkServiceDef struct {
// Detect lists env key conditions; any match signals the service is in use.
Detect []FrameworkServiceDetect `yaml:"detect,omitempty"`
// Vars is the list of KEY=VALUE pairs to apply when the service is detected.
// Use {{site}} for the per-project database name.
Vars []string `yaml:"vars,omitempty"`
}
FrameworkServiceDef describes how a service is detected and configured for a framework.
type FrameworkServiceDetect ¶ added in v1.0.0
type FrameworkServiceDetect struct {
Key string `yaml:"key"`
ValuePrefix string `yaml:"value_prefix,omitempty"`
}
FrameworkServiceDetect is a single detection condition. The service is considered active when Key exists in the env file and, if ValuePrefix is set, its value starts with that prefix.
type FrameworkSetupCmd ¶ added in v1.6.0
type FrameworkSetupCmd struct {
Label string `yaml:"label"`
Command string `yaml:"command"`
Default bool `yaml:"default,omitempty"`
Check *FrameworkRule `yaml:"check,omitempty"` // only show when check passes (file exists or composer package installed)
}
FrameworkSetupCmd describes a one-off bootstrap command run during project setup.
type FrameworkSource ¶ added in v1.10.0
type FrameworkSource string
FrameworkSource describes where a framework definition came from.
const ( SourceBuiltIn FrameworkSource = "built-in" SourceUser FrameworkSource = "user" SourceStore FrameworkSource = "store" )
func GetFrameworkSource ¶ added in v1.10.0
func GetFrameworkSource(name string) FrameworkSource
GetFrameworkSource returns the source of the active framework definition. Returns SourceBuiltIn for "laravel", SourceUser if a user-defined file exists, SourceStore if a store-installed file exists, or "" if not found.
type FrameworkTinker ¶ added in v1.19.0
type FrameworkTinker struct {
// Command is the argv to run, the first item is typically the entry
// script (e.g. "artisan", "bin/console psysh"). Each item is passed
// verbatim to `podman exec … php <Command…>`.
// Example for Laravel: ["artisan", "tinker"]
// Example for Symfony+psysh: ["vendor/bin/psysh"]
Command []string `yaml:"command"`
// ExecuteFlag, when set, is the flag used to pass user code as a
// single argument. Example: "--execute" → `--execute=<code>`.
// Mutually exclusive with ExecutePositional.
ExecuteFlag string `yaml:"execute_flag,omitempty"`
// ExecutePositional, when true, appends user code as a final
// positional argv element instead of using a flag. Useful for tools
// like `drush php:eval <code>` and `wp eval <code>` that take code
// as a bare argument. Mutually exclusive with ExecuteFlag.
ExecutePositional bool `yaml:"execute_positional,omitempty"`
// When neither ExecuteFlag nor ExecutePositional is set, user code
// is piped to the process via stdin.
//
// RequiresPackage is the composer package that must be installed in
// vendor/ for this REPL to work. Example: "laravel/tinker".
// When the package isn't found, lerd falls back to plain PHP.
RequiresPackage string `yaml:"requires_package,omitempty"`
// RequiresFile, similarly, is a relative path that must exist for
// this REPL to be usable (e.g. "artisan"). Defaults to no check.
RequiresFile string `yaml:"requires_file,omitempty"`
}
FrameworkTinker describes how to launch a REPL for a framework. Lerd uses these to drive both the Tinker tab in the Web UI and the (future) `lerd tinker` CLI command. The schema is intentionally minimal so frameworks don't need to ship a full executable spec — just the argv (relative to a `php …` invocation) and how user code is fed in.
func GetTinkerForDir ¶ added in v1.19.0
func GetTinkerForDir(projectDir string) *FrameworkTinker
GetTinkerForDir returns the framework's Tinker spec when:
- the project belongs to a registered framework,
- the framework definition declares a `tinker` block,
- all `requires_*` checks pass against the project directory.
Otherwise returns nil so callers fall back to plain `php`.
type FrameworkWorker ¶ added in v1.0.0
type FrameworkWorker struct {
Label string `yaml:"label,omitempty"`
Command string `yaml:"command"`
// ReloadCommand is the alternate command run when a project opts this
// worker into auto-reload (restart on file changes) for development.
// Empty means the worker has no reload variant. Laravel's horizon worker
// sets it to "php artisan horizon:listen"; core selects it over Command
// when the project enables reload for the worker and, on platforms where
// the container cannot observe host filesystem events, appends the polling
// flag (see resolveWorkerCommand). Keeping the literal command text in the
// framework definition rather than rewriting Command in Go means the store
// stays the single source of truth for what actually runs.
ReloadCommand string `yaml:"reload_command,omitempty"`
// TuneCommand is the parameterized variant of Command for `lerd queue:start`,
// a template with {queue}/{tries}/{timeout} placeholders so each framework
// declares its own flag syntax. Empty falls back to Command verbatim.
TuneCommand string `yaml:"tune_command,omitempty"`
// RestartCommand gracefully restarts the queue worker in-container (e.g.
// Laravel's "php artisan queue:restart"). Empty means no graceful restart.
RestartCommand string `yaml:"restart_command,omitempty"`
Restart string `yaml:"restart,omitempty"` // always | on-failure (default: always)
Schedule string `yaml:"schedule,omitempty"` // systemd OnCalendar expression (e.g. "minutely"); when set, the worker is run as a Type=oneshot service triggered by a .timer rather than a long-running daemon. Use this for Laravel <=10 schedule:run, cron-style cleanup tasks, etc.
Check *FrameworkRule `yaml:"check,omitempty"` // only show when check passes (file exists or composer package installed)
ExcludeCheck *FrameworkRule `yaml:"exclude_check,omitempty"` // only show when check FAILS (e.g. queue is hidden when laravel/horizon is installed because horizon supersedes it)
ConflictsWith []string `yaml:"conflicts_with,omitempty"` // workers to stop before starting this one (e.g. horizon conflicts_with queue)
Proxy *WorkerProxy `yaml:"proxy,omitempty"` // WebSocket/HTTP proxy config for nginx
Host bool `yaml:"host,omitempty"` // run on the host via fnm instead of inside the PHP-FPM container
// PerWorktree opts the worker into running independently per git worktree
// (lerd-<wname>-<site>-<wt>). Defaults to false; set true on workers that
// need a separate process per checkout (e.g. dev servers like vite).
PerWorktree *bool `yaml:"per_worktree,omitempty"`
// ReplacesBuild declares that, while this worker is running, the framework
// can render pages without a static asset build. Used by lerd worktree add
// and lerd setup to skip the npm run build step when the user opted into
// such a worker (vite is the canonical case).
ReplacesBuild bool `yaml:"replaces_build,omitempty"`
// ProjectOrigin marks a worker that came from the untrusted project .lerd.yaml
// (custom_workers), so the host-execution gate can require consent for it.
// Never persisted; set only at the merge point.
ProjectOrigin bool `yaml:"-" json:"-"`
}
FrameworkWorker describes a long-running process managed as a systemd service. The Command is executed inside the PHP-FPM container for the site unless Host is true, in which case it runs directly on the host via fnm.
func (FrameworkWorker) IsPerWorktree ¶ added in v1.20.0
func (w FrameworkWorker) IsPerWorktree() bool
IsPerWorktree reports whether this worker can run independently per git worktree. Defaults to false; framework yamls opt in with per_worktree: true.
type FrankenPHPHint ¶ added in v1.18.0
type FrankenPHPHint struct {
// Signal is a short machine-readable tag: "laravel-octane-franken",
// "symfony-runtime", "runtime-frankenphp", "containerfile", "caddyfile".
Signal string
// Reason is a one-line human-readable explanation.
Reason string
}
FrankenPHPHint describes one reason a project looks like it's set up for FrankenPHP. Multiple hints can be present at once.
func DetectFrankenPHPHints ¶ added in v1.18.0
func DetectFrankenPHPHints(dir string) []FrankenPHPHint
DetectFrankenPHPHints inspects a project directory for signals that it is intended to run under FrankenPHP. It never returns an error; an unreadable composer.json or missing file simply produces no hints for that signal. Hints are ordered by confidence (most specific first).
type GlobalConfig ¶
type GlobalConfig struct {
// Editor is the command lerd runs to open a file at a line (the
// "open in editor" links in the dashboard). Optional {file} and {line}
// placeholders; if omitted, lerd appends the file. Empty = autodetect a
// known GUI editor (code/cursor/phpstorm/subl/zed), then xdg-open/open.
Editor string `yaml:"editor,omitempty" mapstructure:"editor"`
PHP struct {
DefaultVersion string `yaml:"default_version" mapstructure:"default_version"`
XdebugEnabled map[string]bool `yaml:"xdebug_enabled" mapstructure:"xdebug_enabled"`
XdebugMode map[string]string `yaml:"xdebug_mode,omitempty" mapstructure:"xdebug_mode"`
// XdebugStart maps a PHP version to its xdebug.start_with_request value
// (yes | trigger | no). Absent means the default "yes" (connect on every
// request). "trigger"/"no" support on-demand debugging via the control
// socket without flooding the IDE from every request and worker.
XdebugStart map[string]string `yaml:"xdebug_start,omitempty" mapstructure:"xdebug_start"`
Extensions map[string][]string `yaml:"extensions" mapstructure:"extensions"`
// ExtApkDeps maps a custom extension name to extra Alpine packages its
// build needs. Keyed by extension (deps don't vary by PHP version).
// lerd already knows the deps for some extensions; this is for the rest.
ExtApkDeps map[string][]string `yaml:"ext_apk_deps,omitempty" mapstructure:"ext_apk_deps"`
// Packages maps a PHP version to extra Alpine packages to install in the
// FPM image's runtime stage (lerd php:pkg). For CLI tools and runtime
// libraries users want available in the container; re-applied on rebuild.
Packages map[string][]string `yaml:"packages,omitempty" mapstructure:"packages"`
// FPMPorts maps a PHP version to extra host ports published on that
// version's shared FPM container, so a process bound inside `lerd shell`
// (a Vite dev server, a websocket, an ad-hoc listener) is reachable at
// localhost:PORT. Environment-wide per version, not per site; the one
// shared FPM container per version owns the list, so two sites wanting
// the same in-container port on the same version collide. Each mapping is
// a "host:container" spec; the loopback/LAN bind is applied centrally on
// write. Managed via the PHP page's Ports tab (lerd php:ports).
FPMPorts map[string][]string `yaml:"fpm_ports,omitempty" mapstructure:"fpm_ports"`
} `yaml:"php" mapstructure:"php"`
Node struct {
DefaultVersion string `yaml:"default_version" mapstructure:"default_version"`
// Managed records whether lerd manages Node.js via fnm shims. A pointer
// so a config predating the field (nil) keeps the historical
// shim-presence behaviour, while an explicit false survives updates that
// would otherwise re-add the shims a `node:unmanage` removed.
Managed *bool `yaml:"managed,omitempty" mapstructure:"managed"`
} `yaml:"node" mapstructure:"node"`
Nginx struct {
HTTPPort int `yaml:"http_port" mapstructure:"http_port"`
HTTPSPort int `yaml:"https_port" mapstructure:"https_port"`
// RequestTimeout is the default nginx request timeout in seconds,
// overridable per project via .lerd.yaml request_timeout. Zero falls
// back to nginx's own 60s default; read it via RequestTimeoutSeconds.
RequestTimeout int `yaml:"request_timeout,omitempty" mapstructure:"request_timeout"`
} `yaml:"nginx" mapstructure:"nginx"`
DNS struct {
// Enabled=false skips lerd-dns, mkcert CA, sudoers, and resolver
// config; sites use *.localhost (RFC 6761). HTTPS is unavailable
// in that mode. Default true preserves historical behaviour.
Enabled bool `yaml:"enabled" mapstructure:"enabled"`
TLD string `yaml:"tld" mapstructure:"tld"`
// Upstream pins the upstream DNS servers dnsmasq forwards
// non-.test queries to. When empty, lerd auto-detects them from
// the system resolver. Set this when auto-detection picks the
// wrong servers (e.g. systemd-resolved fallbacks instead of your
// LAN resolver). Accepts plain IPs; #port is allowed.
Upstream []string `yaml:"upstream,omitempty" mapstructure:"upstream"`
} `yaml:"dns" mapstructure:"dns"`
LAN struct {
// Exposed controls whether lerd's services are reachable from
// other devices on the local network. When false (the default,
// safe-on-coffee-shop-wifi state) every container PublishPort is
// rewritten to bind 127.0.0.1, lerd-ui binds 127.0.0.1:7073, and
// the lerd-dns-forwarder is stopped. When true, container ports
// bind 0.0.0.0, lerd-ui binds 0.0.0.0:7073, dnsmasq is rewritten
// to answer .test queries with the host's LAN IP, and the
// userspace lerd-dns-forwarder runs to bridge LAN-IP:5300 to the
// loopback-only DNS container.
//
// Toggled via `lerd lan:expose on/off`. The previous standalone
// `dns:expose` flag was folded in here because there is no
// meaningful state where the DNS resolver answers the LAN but
// the actual services don't.
Exposed bool `yaml:"exposed,omitempty" mapstructure:"exposed"`
} `yaml:"lan,omitempty" mapstructure:"lan"`
Autostart struct {
// Disabled controls whether lerd boots itself at login. The
// zero value (false) means lerd autostarts as it always has:
// every lerd-* container quadlet ships with its [Install]
// section, the podman generator wires it into
// default.target.wants on every daemon-reload, and the
// lerd-ui / lerd-watcher / per-site worker units are enabled.
// Setting this to true makes WriteQuadletDiff strip the
// [Install] section before write (so the generator stops
// emitting wants symlinks), disables ui/watcher and every
// per-site worker, and stops them. Toggled via
// `lerd autostart enable / disable` and the dashboard / tray
// switches.
//
// Inverted form (Disabled rather than Enabled) so the YAML zero
// value preserves the historical autostart-on behaviour for
// every existing install — users who never touch the toggle
// see no change.
Disabled bool `yaml:"disabled,omitempty" mapstructure:"disabled"`
} `yaml:"autostart,omitempty" mapstructure:"autostart"`
UI struct {
// RemoteControl gates non-loopback access to the lerd dashboard.
// Empty PasswordHash = disabled = LAN clients get 403. With a hash
// set, LAN clients must present matching HTTP Basic auth. Loopback
// (127.0.0.1, ::1) always bypasses both checks.
Username string `yaml:"username,omitempty" mapstructure:"username"`
PasswordHash string `yaml:"password_hash,omitempty" mapstructure:"password_hash"`
} `yaml:"ui,omitempty" mapstructure:"ui"`
Workers struct {
// ExecMode controls how framework workers (queue, schedule, horizon,
// reverb, custom) are launched on macOS. "exec" (default) wraps a
// single `podman exec` per worker in a dedup guard and lets launchd
// supervise that process, matching Linux's lower-memory behaviour.
// "container" runs each worker as its own detached container, which
// costs more memory per worker but makes the podman supervisor
// boundary 1:1 and sidesteps the SSH-bridge hiccups that can
// otherwise produce phantom or duplicate workers.
//
// The field is ignored on Linux, which always runs workers as
// `podman exec` into the shared FPM container (systemd is a
// dependable supervisor there). Use WorkerExecMode() to read the
// effective value.
ExecMode string `yaml:"exec_mode,omitempty" mapstructure:"exec_mode"`
} `yaml:"workers,omitempty" mapstructure:"workers"`
Dumps struct {
// Enabled is the single switch for the whole debug window: the dump
// bridge AND the lerd_devtools collector (queries, mail, views, events,
// jobs, http). Both the bridge and the extension read one runtime
// sentinel (`enabled.flag`); their PHP/ini assets are always mounted
// regardless of this flag, so what Enabled controls is just that
// sentinel — touch = capture, missing = fast no-op, no FPM restart.
// Toggled via `lerd dump on/off` or the dashboard Debug view.
Enabled bool `yaml:"enabled,omitempty" mapstructure:"enabled"`
// Passthrough controls whether dump()/dd() ALSO emit to the response
// while the bridge is enabled. False (default) means captured-only:
// the dashboard is the single destination and the response stays
// clean (matching Herd's behaviour). True forwards each call through
// Symfony's stock VarDumper handler after capture, useful as a
// safety net when lerd-ui isn't running. No effect when Enabled is
// false — without the bridge, dump() behaves exactly as Symfony
// ships it.
Passthrough bool `yaml:"passthrough,omitempty" mapstructure:"passthrough"`
} `yaml:"dumps,omitempty" mapstructure:"dumps"`
Devtools struct {
// Workers includes long-running queue/scheduler worker queries in
// capture. Off by default because their constant polling floods the
// buffer; toggled from the dashboard "Show worker queries" checkbox.
// The collector's enable state is shared with the debug bridge: one
// sentinel (enabled.flag) and one config flag (Dumps.Enabled) arm both,
// so there is no separate devtools enable toggle.
Workers bool `yaml:"workers,omitempty" mapstructure:"workers"`
} `yaml:"devtools,omitempty" mapstructure:"devtools"`
Profiler struct {
// Enabled toggles the SPX profiler globally. When on, nginx injects
// SPX_ENABLED into every PHP-FPM site's requests so each is profiled.
// Toggled via `lerd profile on/off` and the dashboard Profiler view.
Enabled bool `yaml:"enabled,omitempty" mapstructure:"enabled"`
} `yaml:"profiler,omitempty" mapstructure:"profiler"`
Notifications struct {
// Disabled globally mutes the notifier (WebSocket banners + Web
// Push fanout). Inverted form so the zero value keeps existing
// installs on. Toggled via `lerd notify on/off` and the tray.
Disabled bool `yaml:"disabled,omitempty" mapstructure:"disabled"`
} `yaml:"notifications,omitempty" mapstructure:"notifications"`
HostProxy struct {
// Disabled refuses to set up or start any host-proxy dev-server unit,
// for users who never want lerd supervising a process on the host.
// Inverted so the zero value keeps the feature available.
Disabled bool `yaml:"disabled,omitempty" mapstructure:"disabled"`
// SkipConfirmation runs a newly-linked host-proxy command without the
// interactive "start this on your host?" prompt. Off by default so a
// command from a cloned repo never runs unconfirmed.
SkipConfirmation bool `yaml:"skip_confirmation,omitempty" mapstructure:"skip_confirmation"`
} `yaml:"host_proxy,omitempty" mapstructure:"host_proxy"`
HostCommands struct {
// Disabled refuses to run any project-supplied host command or host
// worker (custom_workers / commands from a project .lerd.yaml). Inverted
// so the zero value keeps the feature available.
Disabled bool `yaml:"disabled,omitempty" mapstructure:"disabled"`
// SkipConfirmation runs project-supplied host commands and workers without
// the interactive confirm. Off by default so a command from a cloned repo
// never runs unconfirmed.
SkipConfirmation bool `yaml:"skip_confirmation,omitempty" mapstructure:"skip_confirmation"`
} `yaml:"host_commands,omitempty" mapstructure:"host_commands"`
IdleSuspend struct {
// Enabled turns on activity-driven worker suspension: when a site sees
// no activity for Timeout, its suspendable workers (queue, horizon, ...)
// are gracefully stopped and resumed on the next request. Off by default
// so a quiet dev box reclaims worker memory only once the user opts in.
// Idle-suspend is a single global policy, not configured per site.
Enabled bool `yaml:"enabled,omitempty" mapstructure:"enabled"`
// Timeout is how long a site must be idle before its workers suspend, as
// a Go duration string ("30m"). Empty or unparseable falls back to
// DefaultIdleSuspendTimeout; read it via IdleSuspendTimeout.
Timeout string `yaml:"timeout,omitempty" mapstructure:"timeout"`
} `yaml:"idle_suspend,omitempty" mapstructure:"idle_suspend"`
// AutoCleanup lets the watcher periodically reclaim orphaned lerd images
// (safe tier only, never service images). On by default; set false to turn
// off the daily sweep. Read it via AutoCleanupEnabled for nil-safety.
AutoCleanup bool `yaml:"auto_cleanup" mapstructure:"auto_cleanup"`
ParkedDirectories []string `yaml:"parked_directories" mapstructure:"parked_directories"`
Services map[string]ServiceConfig `yaml:"services" mapstructure:"services"`
}
GlobalConfig is the top-level lerd configuration.
func LoadGlobal ¶
func LoadGlobal() (*GlobalConfig, error)
LoadGlobal reads config.yaml via viper, returning defaults if the file is absent.
func (*GlobalConfig) AddExtension ¶ added in v0.5.5
func (c *GlobalConfig) AddExtension(version, ext string)
AddExtension adds ext to the custom extension list for version (no-op if already present).
func (*GlobalConfig) AddPackage ¶ added in v1.25.0
func (c *GlobalConfig) AddPackage(version, pkg string)
AddPackage adds pkg to the extra-packages list for version (no-op if present).
func (*GlobalConfig) AllExtApkDeps ¶ added in v1.20.0
func (c *GlobalConfig) AllExtApkDeps() map[string][]string
AllExtApkDeps returns the full user-configured extension → apk deps map.
func (*GlobalConfig) AutoCleanupEnabled ¶ added in v1.27.0
func (c *GlobalConfig) AutoCleanupEnabled() bool
AutoCleanupEnabled reports whether the watcher's periodic image cleanup is on. Nil-safe and defaults on, matching defaultConfig, so an unconfigured install reclaims orphaned images on its own.
func (*GlobalConfig) DNSManaged ¶ added in v1.25.0
func (c *GlobalConfig) DNSManaged() bool
DNSManaged reports whether lerd is managing local DNS, which is the prerequisite for HTTPS (mkcert CA, *.test resolution). A nil receiver counts as managed, matching how the rest of the codebase treats an absent config (an unconfigured install behaves as if DNS is enabled). It is the single predicate the install wizard, `lerd secure`, and the cert layer all share.
func (*GlobalConfig) GetExtApkDeps ¶ added in v1.20.0
func (c *GlobalConfig) GetExtApkDeps(ext string) []string
GetExtApkDeps returns the user-configured extra Alpine packages for ext.
func (*GlobalConfig) GetExtensions ¶ added in v0.5.5
func (c *GlobalConfig) GetExtensions(version string) []string
GetExtensions returns the custom extensions configured for the given PHP version.
func (*GlobalConfig) GetPackages ¶ added in v1.25.0
func (c *GlobalConfig) GetPackages(version string) []string
GetPackages returns the extra Alpine packages configured for the given PHP version's FPM image.
func (*GlobalConfig) GetXdebugMode ¶ added in v1.16.0
func (c *GlobalConfig) GetXdebugMode(version string) string
GetXdebugMode returns the configured Xdebug mode for version, or "" when disabled. Entries in the legacy xdebug_enabled map (no explicit mode) are treated as mode "debug" so configs written by older lerd builds keep the same behaviour they had before per-mode support existed.
func (*GlobalConfig) GetXdebugStart ¶ added in v1.25.0
func (c *GlobalConfig) GetXdebugStart(version string) string
GetXdebugStart returns the xdebug.start_with_request value for version, defaulting to "yes" (connect on every request) when unset.
func (*GlobalConfig) IdleSuspendTimeout ¶ added in v1.25.0
func (c *GlobalConfig) IdleSuspendTimeout() time.Duration
IdleSuspendTimeout returns the effective global idle timeout, falling back to DefaultIdleSuspendTimeout when unset, unparseable, or non-positive.
func (*GlobalConfig) IsDevtoolsWorkers ¶ added in v1.23.0
func (c *GlobalConfig) IsDevtoolsWorkers() bool
IsDevtoolsWorkers reports whether queue/scheduler worker queries are captured.
func (*GlobalConfig) IsDumpsEnabled ¶ added in v1.20.0
func (c *GlobalConfig) IsDumpsEnabled() bool
IsDumpsEnabled reports whether the lerd debug bridge is on for all PHP versions. The toggle is global because the bridge file is a single, version-agnostic asset bind-mounted into every FPM container.
func (*GlobalConfig) IsDumpsPassthrough ¶ added in v1.20.0
func (c *GlobalConfig) IsDumpsPassthrough() bool
IsDumpsPassthrough reports whether the bridge should also forward each captured dump to Symfony's stock VarDumper handler (response output). Always false in effect when the bridge itself is disabled.
func (*GlobalConfig) IsNotificationsEnabled ¶ added in v1.21.0
func (c *GlobalConfig) IsNotificationsEnabled() bool
IsNotificationsEnabled reports whether the global notifier is allowed to fan out (WebSocket banners + Web Push). Inverted storage so existing installs default to enabled.
func (*GlobalConfig) IsProfilerEnabled ¶ added in v1.22.0
func (c *GlobalConfig) IsProfilerEnabled() bool
IsProfilerEnabled reports whether the SPX profiler is globally armed.
func (*GlobalConfig) IsXdebugEnabled ¶ added in v0.4.0
func (c *GlobalConfig) IsXdebugEnabled(version string) bool
IsXdebugEnabled returns true if Xdebug is enabled for the given PHP version.
func (*GlobalConfig) NodeManagedPref ¶ added in v1.28.1
func (c *GlobalConfig) NodeManagedPref() (val bool, set bool)
NodeManagedPref returns the persisted Node-management choice. set is false when the config predates the field, so callers fall back to the on-disk shim state instead of assuming a default.
func (*GlobalConfig) RemoveExtension ¶ added in v0.5.5
func (c *GlobalConfig) RemoveExtension(version, ext string)
RemoveExtension removes ext from the custom extension list for version, and drops any extra apk deps recorded for it once no version still uses it.
func (*GlobalConfig) RemovePackage ¶ added in v1.25.0
func (c *GlobalConfig) RemovePackage(version, pkg string)
RemovePackage removes pkg from the extra-packages list for version.
func (*GlobalConfig) RequestTimeoutSeconds ¶ added in v1.22.0
func (c *GlobalConfig) RequestTimeoutSeconds() int
RequestTimeoutSeconds returns the effective global nginx request timeout in seconds, falling back to nginx's 60s default when unset or non-positive.
func (*GlobalConfig) SetDevtoolsWorkers ¶ added in v1.23.0
func (c *GlobalConfig) SetDevtoolsWorkers(enabled bool)
SetDevtoolsWorkers flips worker-query capture. Persist via SaveGlobal and run devtoolsops.SetWorkers to touch the runtime sentinel.
func (*GlobalConfig) SetDumpsEnabled ¶ added in v1.20.0
func (c *GlobalConfig) SetDumpsEnabled(enabled bool)
SetDumpsEnabled flips the debug bridge toggle. Persist via SaveGlobal and run dumpsops.Apply to actually rewrite the FPM quadlets.
func (*GlobalConfig) SetDumpsPassthrough ¶ added in v1.20.0
func (c *GlobalConfig) SetDumpsPassthrough(enabled bool)
SetDumpsPassthrough flips the passthrough flag. Persist via SaveGlobal and follow up with a `lerd-php*-fpm` restart so the new ini value takes effect (PHP reads ini directives at FPM startup, not per request).
func (*GlobalConfig) SetExtApkDeps ¶ added in v1.20.0
func (c *GlobalConfig) SetExtApkDeps(ext string, deps []string)
SetExtApkDeps records (or clears, when deps is empty) the extra Alpine packages needed to build ext.
func (*GlobalConfig) SetNodeManaged ¶ added in v1.28.1
func (c *GlobalConfig) SetNodeManaged(managed bool)
SetNodeManaged records the Node-management choice. Persist via SaveGlobal; the install/update flow reads it to keep the choice across updates.
func (*GlobalConfig) SetNotificationsEnabled ¶ added in v1.21.0
func (c *GlobalConfig) SetNotificationsEnabled(enabled bool)
SetNotificationsEnabled flips the global notifier toggle. Persist via SaveGlobal; dispatchNotification re-reads the flag on every event.
func (*GlobalConfig) SetXdebug ¶ added in v0.4.0
func (c *GlobalConfig) SetXdebug(version string, enabled bool)
SetXdebug enables (mode "debug") or disables Xdebug for version. Use SetXdebugMode directly when a non-default mode is wanted.
func (*GlobalConfig) SetXdebugMode ¶ added in v1.16.0
func (c *GlobalConfig) SetXdebugMode(version, mode string)
SetXdebugMode sets the Xdebug mode for version. Empty mode disables Xdebug. Both the modern xdebug_mode map and the legacy xdebug_enabled map are kept in sync so downgrades don't silently flip state.
func (*GlobalConfig) SetXdebugStart ¶ added in v1.25.0
func (c *GlobalConfig) SetXdebugStart(version, value string)
SetXdebugStart records the xdebug.start_with_request value for version. An empty value (or "yes", the default) clears the entry so the config stays lean.
func (*GlobalConfig) WorkerExecMode ¶ added in v1.19.0
func (c *GlobalConfig) WorkerExecMode() string
WorkerExecMode returns the effective worker exec mode for the current platform. Invalid or empty configured values normalise to "exec".
type Preset ¶ added in v1.9.0
type Preset struct {
CustomService `yaml:",inline"`
Versions []PresetVersion `yaml:"versions,omitempty"`
DefaultVersion string `yaml:"default_version,omitempty"`
Default bool `yaml:"default,omitempty"`
UpdateStrategy string `yaml:"update_strategy,omitempty"`
PlatformOverrides []PresetPlatformImage `yaml:"platform_overrides,omitempty"`
// AllowMajorUpgrade lets the cross-strategy "Upgrade" button cross numeric
// major boundaries. Default false: major upgrades typically require manual
// data migration and should be installed as a separate alternate instead.
AllowMajorUpgrade bool `yaml:"allow_major_upgrade,omitempty"`
// TrackLatest makes fresh installs resolve the actual newest tag from the
// registry at first start (within same-major + variant constraints). The
// preset's `image:` field becomes a fallback for offline / registry-down
// installs. Existing users with a saved image override are untouched —
// they progress through the Update / Upgrade buttons instead.
TrackLatest bool `yaml:"track_latest,omitempty"`
}
Preset is the parsed YAML for a bundled service preset. It embeds CustomService for the shared fields and adds an optional Versions list + DefaultVersion for families that ship multiple selectable image tags. After the user picks a tag, Resolve() materialises a concrete CustomService whose Name and Image are version-specific while every other field stays shared.
func EnsurePreset ¶ added in v1.28.1
EnsurePreset returns the preset for name, fetching it from the external store when no local copy exists and opportunistically refreshing a cached store preset older than presetStaleAfter. This is the deliberate, network-touching entry point used by install and the service CLI. The plain LoadPreset / PresetExists paths stay purely local so hot loops and the many "is this name a preset?" checks never reach out to the network.
func LoadPreset ¶ added in v1.9.0
LoadPreset returns the parsed Preset for a bundled file by name.
func (*Preset) ApplyPlatformOverride ¶ added in v1.19.0
func (p *Preset) ApplyPlatformOverride(svc *CustomService, goos string)
ApplyPlatformOverride swaps svc.Image with a platform-specific replacement when the runtime OS matches and the current image satisfies ImageMatch. The override image may use {{tag}} as a placeholder for the current image's tag — this lets `track_latest`-resolved tags (e.g. 16.4-3.5-alpine) survive the override swap. goos is usually runtime.GOOS, parameterised for tests.
func (*Preset) CanonicalTag ¶ added in v1.21.0
CanonicalTag returns the tag of the version marked canonical, or empty when no version is flagged (single-version presets or all-alternate families).
func (*Preset) Resolve ¶ added in v1.9.0
func (p *Preset) Resolve(version string) (*CustomService, error)
Resolve materialises the preset into a concrete CustomService for the picked version. For single-version presets the embedded CustomService is returned as-is and version is ignored. For multi-version presets, version names a tag in Versions; an empty version selects DefaultVersion. The resolved service's Name is "<family>-<sanitized-tag>" and its Image is taken from the version entry. EnvVars and ConnectionURL are scanned for {{tag}} and {{tag_safe}} placeholders so the family-shared template can reference the picked tag.
func (*Preset) ResolvePinned ¶ added in v1.21.0
func (p *Preset) ResolvePinned(tag string) (*CustomService, error)
ResolvePinned is like Resolve but always returns the preset's bare family name even when the picked version is not flagged canonical. Used so a canonical flip in the YAML doesn't rename installed services.
type PresetFetchFunc ¶ added in v1.28.1
PresetFetchFunc downloads a preset from the external service store and saves it into the store-cache dir. The store package registers it at startup to avoid a circular import (config must not import store).
type PresetMeta ¶ added in v1.9.0
type PresetMeta struct {
Name string `json:"name"`
Description string `json:"description"`
Dashboard string `json:"dashboard,omitempty"`
DependsOn []string `json:"depends_on,omitempty"`
Image string `json:"image"`
Versions []PresetVersion `json:"versions,omitempty"`
DefaultVersion string `json:"default_version,omitempty"`
}
PresetMeta is the lightweight description of a bundled preset, suitable for listing in CLI tables and the web UI without parsing every field.
func ListPresets ¶ added in v1.9.0
func ListPresets() ([]PresetMeta, error)
ListPresets returns the metadata for all bundled service presets, sorted by name.
type PresetPlatformImage ¶ added in v1.19.0
type PresetPlatformImage struct {
OS string `yaml:"os"`
ImageMatch string `yaml:"image_match"`
Image string `yaml:"image"`
}
PresetPlatformImage swaps the resolved image when the host OS matches and the current image (after version selection) matches the glob in ImageMatch. Lifted from the prior cli.platformImageOverride hardcoded list.
type PresetVersion ¶ added in v1.9.0
type PresetVersion struct {
Tag string `yaml:"tag" json:"tag"`
Label string `yaml:"label,omitempty" json:"label,omitempty"`
Image string `yaml:"image" json:"image"`
// HostPort is the host-side port published for this version. Since #704
// every member of a family shares the family's canonical port (e.g. 3306,
// 5432); the runtime port-ownership guard shifts a later sibling off it only
// when another installed service already holds it, so the common single
// instance lands on the familiar port. Substituted into the family's
// templated ports, env_vars and connection_url via {{host_port}}.
HostPort int `yaml:"host_port,omitempty" json:"host_port,omitempty"`
// Canonical marks this version as the default-preset's bare instance:
// the service keeps the family name (no -<tag_safe> suffix), uses the
// preset's top-level ports literally, and skips {{host_port}}/{{tag_safe}}
// substitution. Exactly one version per multi-version preset may set it.
Canonical bool `yaml:"canonical,omitempty" json:"canonical,omitempty"`
}
PresetVersion is a single selectable image tag for a multi-version preset family (e.g. mysql 5.7, mysql 5.6, mariadb 11). Single-version presets like phpmyadmin or pgadmin omit Versions entirely and use the embedded CustomService image directly.
type ProjectConfig ¶ added in v1.2.0
type ProjectConfig struct {
Domains []string `yaml:"domains,omitempty"`
PHPVersion string `yaml:"php_version,omitempty"`
NodeVersion string `yaml:"node_version,omitempty"`
// JSRuntime pins the JavaScript runtime for this project's host workers and
// install/build steps: "bun" forces bun, "node" (or "npm") forces Node/npm
// and opts out of the no-Node bun fallback. Empty auto-detects bun from a
// bun.lockb / bunfig.toml / packageManager field. Use "node" for apps bun
// can't run (e.g. NestJS with native addons). See node.UsesBun.
JSRuntime string `yaml:"js_runtime,omitempty"`
Framework string `yaml:"framework,omitempty"`
FrameworkVersion string `yaml:"framework_version,omitempty"`
FrameworkDef *Framework `yaml:"framework_def,omitempty"`
// PublicDir overrides the framework's default document-root subdirectory
// for this project, e.g. "public_html" for a Laravel skeleton that doesn't
// use the conventional "public/" folder. Empty means use the framework
// default. Wins over Framework.PublicDir at nginx-config time.
PublicDir string `yaml:"public_dir,omitempty"`
Secured bool `yaml:"secured,omitempty"`
Services []ProjectService `yaml:"services,omitempty"`
Workers []string `yaml:"workers,omitempty"`
CustomWorkers map[string]FrameworkWorker `yaml:"custom_workers,omitempty"`
// ReloadWorkers lists worker names this project runs in auto-reload mode
// (restart on file changes) for development, for workers that declare a
// reload_command variant. Per project so one project can develop with
// reload while another stays in standard mode. Laravel's horizon worker is
// currently the only worker with a reload variant.
ReloadWorkers []string `yaml:"reload_workers,omitempty"`
// Commands extends or overrides the framework's command set. Entries with
// a Name matching a framework command replace it (set Disabled: true to
// suppress instead). Entries with a new Name are appended. See
// ResolveCommands for the merge logic.
Commands []FrameworkCommand `yaml:"commands,omitempty"`
// AppURL, when set, is the value lerd writes to the project's APP_URL (or
// the framework-configured URL key) on every `lerd env` run. Committed to
// the repo so the choice is shared across machines. Takes precedence over
// the per-machine override in sites.yaml.
AppURL string `yaml:"app_url,omitempty"`
DB ProjectDB `yaml:"db,omitempty"`
Container *ContainerConfig `yaml:"container,omitempty"`
// Proxy, when set, makes this a host-proxy site (see ProxyConfig). Mutually
// exclusive with Container; Validate rejects setting both.
Proxy *ProxyConfig `yaml:"proxy,omitempty"`
// Runtime selects how the site's PHP is served. "fpm" (default) uses the
// shared lerd-php{version}-fpm container; "frankenphp" spins up a
// per-site dunglas/frankenphp container that keeps PHP resident.
Runtime string `yaml:"runtime,omitempty"`
// RuntimeWorker, when true and Runtime is "frankenphp", starts the
// FrankenPHP container in worker mode. Framework-specific entrypoints
// decide whether this flag is honoured.
RuntimeWorker bool `yaml:"runtime_worker,omitempty"`
// DBIsolated, when true on a worktree's .lerd.yaml, opts the worktree
// into its own database (named <parent_db>_<sanitized_branch>) so
// migrations don't bleed into the parent. Off by default.
DBIsolated bool `yaml:"db_isolated,omitempty"`
// EnvOverrides maps env keys to template values that are resolved and
// written into the worktree's .env when a worktree is created. Supported
// placeholders: {{domain}} (worktree domain), {{scheme}} (http/https),
// {{site}} (database-safe name). When APP_URL is present here it takes
// precedence over the default scheme://domain rewrite.
EnvOverrides map[string]string `yaml:"env_overrides,omitempty"`
// RequestTimeout overrides the nginx request timeout for this project, in
// seconds. Zero inherits the global nginx.request_timeout (default 60s).
// Raise it for apps with deliberately long-running requests.
RequestTimeout int `yaml:"request_timeout,omitempty"`
// Stripe holds optional per-project Stripe webhook listener settings: the
// route events forward to and which .env key holds the secret. Absent for
// projects on the Laravel defaults, which are auto-detected.
Stripe *StripeConfig `yaml:"stripe,omitempty"`
// MCPInject opts the project out of automatic AI/MCP config refresh. When set
// to false, `lerd update`/`install` leaves the project's committed MCP config
// and skill files untouched so they change only when the user asks. Nil/unset
// keeps the default (refresh in place). An explicit `lerd mcp:inject` still
// writes, since that is the user asking.
MCPInject *bool `yaml:"mcp_inject,omitempty"`
}
ProjectConfig holds per-project configuration stored in .lerd.yaml.
func LoadProjectConfig ¶ added in v1.2.0
func LoadProjectConfig(dir string) (*ProjectConfig, error)
LoadProjectConfig reads .lerd.yaml from dir, returning an empty config if the file does not exist.
func (*ProjectConfig) IsEmpty ¶ added in v1.11.0
func (c *ProjectConfig) IsEmpty() bool
IsEmpty returns true when the config has no meaningful content, which typically means .lerd.yaml did not exist.
func (*ProjectConfig) MCPInjectDisabled ¶ added in v1.28.1
func (c *ProjectConfig) MCPInjectDisabled() bool
MCPInjectDisabled reports whether the project opted out of automatic MCP config injection via `mcp_inject: false` in .lerd.yaml.
func (*ProjectConfig) ReloadsWorker ¶ added in v1.24.0
func (c *ProjectConfig) ReloadsWorker(name string) bool
ReloadsWorker reports whether the named worker is opted into auto-reload (restart on file changes) for this project.
func (*ProjectConfig) ServiceNames ¶ added in v1.3.0
func (p *ProjectConfig) ServiceNames() []string
ServiceNames returns the name of every service in the config, for callers that only need the list of names (e.g. the init wizard multi-select).
func (*ProjectConfig) Validate ¶ added in v1.24.0
func (c *ProjectConfig) Validate() error
Validate reports configuration that can't be honoured. A site is either a custom container or a host proxy, never both.
type ProjectDB ¶ added in v1.14.0
type ProjectDB struct {
Service string `yaml:"service,omitempty"`
Database string `yaml:"database,omitempty"`
}
ProjectDB holds optional database targeting info for the project. Setting these in .lerd.yaml lets db commands work without a .env file, which is useful for non-PHP projects (NestJS, Go, etc.).
type ProjectService ¶ added in v1.3.0
type ProjectService struct {
Name string
Preset string // empty unless this is a preset reference
PresetVersion string // empty for single-version presets
Custom *CustomService // nil unless this is an inline definition
}
ProjectService entries take three YAML shapes:
- redis # named reference (built-in)
- mysql: # preset reference, optional version preset: mysql version: "5.6"
- mongodb: # inline custom definition (legacy / hand-rolled) image: mongo:7 ...
Preset references are the preferred form for services installed via `lerd service preset` because each machine resolves the embedded preset locally — picking up bug fixes, default tweaks, and per-machine port allocations without churn in .lerd.yaml.
func (ProjectService) MarshalYAML ¶ added in v1.3.0
func (s ProjectService) MarshalYAML() (interface{}, error)
MarshalYAML serialises back to the compact form: plain string for named references, single-key preset map for preset references, single-key custom map for inline definitions.
func (ProjectService) Resolve ¶ added in v1.9.0
func (s ProjectService) Resolve() (*CustomService, error)
Resolve returns the concrete CustomService for this entry. Preset references are resolved against the embedded preset library; inline definitions are returned as-is. Named built-in references return (nil, nil) — callers handle built-ins separately.
func (*ProjectService) UnmarshalYAML ¶ added in v1.3.0
func (s *ProjectService) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML accepts the three shapes documented on ProjectService.
type ProxyConfig ¶ added in v1.24.0
type ProxyConfig struct {
Command string `yaml:"command,omitempty"` // dev command, e.g. "npm run start:dev"; empty = proxy-only
Port int `yaml:"port"` // host port the app binds (required)
SSL bool `yaml:"ssl,omitempty"` // app serves TLS on its port; proxy via https
PortEnvKey string `yaml:"port_env_key,omitempty"` // env var the port is injected as (default "PORT")
HostEnvKey string `yaml:"host_env_key,omitempty"` // env var the bind address is injected as (default "HOST")
InjectHost *bool `yaml:"inject_host,omitempty"` // inject the bind-address env (HOST) so the server listens where the proxy container reaches it; nil/unset = true, set false to opt out
}
ProxyConfig holds per-project host-proxy settings. When present in .lerd.yaml the site runs no container: lerd supervises the dev command on the host and nginx reverse-proxies the domain to it on the given port.
type ServiceConfig ¶
type ServiceConfig struct {
Enabled bool `yaml:"enabled" mapstructure:"enabled"`
Image string `yaml:"image" mapstructure:"image"`
Port int `yaml:"port" mapstructure:"port"`
ExtraPorts []string `yaml:"extra_ports" mapstructure:"extra_ports"`
// PublishedPort overrides the host (published) port of this service's
// primary mapping. 0 = use the preset/version default (e.g. 3306 for MySQL
// 8.4). Set it to free the default port for a second server — e.g. move
// lerd-mysql to 3307 so the host system MySQL can keep 127.0.0.1:3306. The
// container-internal port is unchanged, so bridge clients still use 3306.
// Unlike Port (auto-seeded from the preset), this stays 0 until the user
// explicitly overrides, so it is an unambiguous "use default" sentinel.
PublishedPort int `yaml:"published_port,omitempty" mapstructure:"published_port"`
// PublishedPorts overrides the host (published) side of this service's
// secondary mappings, keyed by container-internal port. A multi-port service
// (mailpit's 8025 UI behind the 1025 SMTP primary, rustfs' 9001 console)
// exposes ports past the primary; this lets the user remap each one while the
// primary stays in PublishedPort. Empty = every secondary on its preset
// default. Keyed on the container port because that is the stable identity
// when the host side moves.
PublishedPorts map[int]int `yaml:"published_ports,omitempty" mapstructure:"published_ports"`
PreviousImage string `yaml:"previous_image,omitempty" mapstructure:"previous_image"`
// LastOp records the most recent mutation kind ("update" or "migrate") so
// the rollback flow can refuse a swap that would race the new image
// against the post-migrate (fresh) data dir. Empty means no recent op or a
// state predating the field — treated as plain update for compatibility.
LastOp string `yaml:"last_op,omitempty" mapstructure:"last_op"`
// PreMigrateBackup is the absolute path to the data dir that was preserved
// when the most recent operation was a migrate. Used by rollback to refuse
// (or, in future, restore) when undoing the migrate would corrupt data.
PreMigrateBackup string `yaml:"pre_migrate_backup,omitempty" mapstructure:"pre_migrate_backup"`
// CanonicalVersion pins the preset version tag this service was first
// installed on, so flipping the YAML's canonical (e.g. pg 16 → 18 in a
// future release) never silently major-jumps existing installs.
CanonicalVersion string `yaml:"canonical_version,omitempty" mapstructure:"canonical_version"`
}
ServiceConfig holds configuration for an optional service.
func (ServiceConfig) HostPortFor ¶ added in v1.27.1
func (s ServiceConfig) HostPortFor(containerPort, defaultHost int, isPrimary bool) int
HostPortFor returns the effective host port this service publishes for the mapping whose container-internal port is containerPort, given that mapping's preset default host side defaultHost and whether it is the primary (index-0) mapping. A per-port override in PublishedPorts wins; else the legacy primary PublishedPort applies to the primary mapping; else the preset default stands.
func (ServiceConfig) HostPorts ¶ added in v1.27.0
func (s ServiceConfig) HostPorts() []int
HostPorts returns every host port this service entry actually binds: its effective primary (the PublishedPort override when set, else the preset-default Port) plus the host side of each ExtraPorts mapping. Single source for the serviceops port-ownership guard and the host-proxy dev server allocator, which previously parsed these out separately and drifted (the guard even mis-read the host side of an "ip:host:container" extra mapping). The default Port is NOT reported once an override moves the service off it: the quadlet publishes only the override, so the freed default must be reassignable to another service.
type Site ¶
type Site struct {
Name string `yaml:"-"`
Domains []string `yaml:"-"`
Path string `yaml:"path"`
PHPVersion string `yaml:"php_version"`
NodeVersion string `yaml:"node_version"`
Secured bool `yaml:"secured"`
// SecuredBeforeDNSOff records that the site was on HTTPS when lerd DNS was
// last disabled, so re-enabling can restore it even for a site with no
// .lerd.yaml to carry the intent. Cleared once HTTPS is restored.
SecuredBeforeDNSOff bool `yaml:"secured_before_dns_off,omitempty"`
Ignored bool `yaml:"ignored,omitempty"`
Paused bool `yaml:"paused,omitempty"`
PausedWorkers []string `yaml:"paused_workers,omitempty"`
// Pinned excludes the site from idle-suspend: its workers stay running even
// when the global idle policy is on, so a site you want always-warm never
// sleeps.
Pinned bool `yaml:"pinned,omitempty"`
Framework string `yaml:"framework,omitempty"`
PublicDir string `yaml:"public_dir,omitempty"`
// AppURL, when set, is the per-machine override for APP_URL in the
// project's env file. Lower priority than ProjectConfig.AppURL (which is
// committed to the repo) and higher priority than the default generator
// (`<scheme>://<primary-domain>`). Use this for personal customizations
// you don't want to share via .lerd.yaml.
AppURL string `yaml:"app_url,omitempty"`
// LANPort, when non-zero, means a host-level reverse proxy is (or should
// be) listening on 0.0.0.0:LANPort, forwarding to the site with the Host
// header rewritten. LAN devices can reach the site at <lanIP>:LANPort
// without any DNS configuration.
LANPort int `yaml:"lan_port,omitempty"`
// ContainerPort, when non-zero, means this site uses a per-project custom
// container instead of the shared PHP-FPM image. The value is the port the
// app listens on inside the container; nginx reverse-proxies to it.
ContainerPort int `yaml:"container_port,omitempty"`
// ContainerSSL, when true, means the app inside the custom container serves
// TLS on its port; nginx will proxy_pass via HTTPS with ssl_verify off.
ContainerSSL bool `yaml:"container_ssl,omitempty"`
// Runtime is "fpm" (default) or "frankenphp". When "frankenphp" the site
// runs a per-site dunglas/frankenphp:php<version> container and nginx
// reverse-proxies to it on port 8000.
Runtime string `yaml:"runtime,omitempty"`
// RuntimeWorker toggles FrankenPHP worker mode when Runtime=="frankenphp".
RuntimeWorker bool `yaml:"runtime_worker,omitempty"`
// HostPort, when non-zero, means this site is a host-proxy site: it has no
// container, and nginx reverse-proxies the domain to a process running on
// the host (the dev server) listening on this port.
HostPort int `yaml:"host_port,omitempty"`
// HostSSL, when true, means the host process serves TLS on its port; nginx
// proxies via HTTPS with ssl_verify off.
HostSSL bool `yaml:"host_ssl,omitempty"`
// HostCommand is the dev command lerd supervises for a host-proxy site
// (e.g. "npm run start:dev"). Empty means proxy-only: the user runs the
// server themselves and lerd only wires the proxy.
HostCommand string `yaml:"host_command,omitempty"`
// ApprovedCommands holds exact command strings the user has consented to run
// on the host for this site (project-origin custom host workers and commands).
// Keyed by the exact string so a changed command re-prompts.
ApprovedCommands []string `yaml:"approved_commands,omitempty"`
// Group is the group key shared by a main site and its secondaries. It is
// set to the main site's name. Empty when the site is not grouped.
Group string `yaml:"group,omitempty"`
// GroupSubdomain is the subdomain label a secondary occupies on the group
// main's base domain (e.g. "admin" -> admin.<main-domain>). Empty on the
// main site; non-empty identifies a secondary.
GroupSubdomain string `yaml:"group_subdomain,omitempty"`
// main's database instead of its own: DB_DATABASE in its .env is kept in
// sync with the main's database name.
GroupSharedDB bool `yaml:"group_shared_db,omitempty"`
// IdleSuspendedWorkers records the workers the idle engine gracefully
// stopped while the site was quiet, so activity can resume them. Kept
// distinct from PausedWorkers (manual `lerd pause`) so an automatic suspend
// and a manual pause never clobber each other's restore list. Idle-suspend
// itself is configured globally (config.yaml idle_suspend), not per site.
IdleSuspendedWorkers []string `yaml:"idle_suspended_workers,omitempty"`
// WorktreeIdleSuspended records, per git worktree (keyed by the worktree's
// unit-slug base), the workers the idle engine stopped while that worktree was
// quiet. Each worktree idles on its own timer, independent of the main site
// and of the other worktrees, so its suspended set is tracked separately.
WorktreeIdleSuspended map[string][]string `yaml:"worktree_idle_suspended,omitempty"`
}
Site represents a single registered Lerd site.
func FindSiteByDomain ¶ added in v0.1.37
FindSiteByDomain returns the site that has the given domain (checks all domains), or an error if not found.
func FindSiteByPath ¶ added in v0.3.0
FindSiteByPath returns the site whose path matches, or an error if not found.
func FindSiteByRef ¶ added in v1.28.1
FindSiteByRef looks up a site by its internal name first, then by any of its domains, so a caller can pass either identifier.
func IsDomainUsed ¶ added in v1.5.0
IsDomainUsed checks if any site already uses this domain. Returns the site that uses it, or nil if the domain is free.
The check is strict: a domain may only belong to one site, regardless of TLS scheme. Two sites cannot share the same domain even if one runs on HTTPS and the other on HTTP — DNS and browser caches don't reliably disambiguate by scheme, and the resulting setup is fragile.
func ParentSiteForWorktreeDir ¶ added in v1.19.0
ParentSiteForWorktreeDir returns the registered Site whose .git/worktrees/* metadata points at dir as a checkout. Used by the PHP/Node version detectors to inherit the parent's pinned version before falling through to composer/package.json constraints.
Path-based scan over each site's .git/worktrees/<name>/gitdir file; no git CLI invocation, no dependency on the gitpkg package (which would create an import cycle for callers like internal/php and internal/node).
func SitesUsingService ¶ added in v1.19.0
SitesUsingService returns the active (non-ignored, non-paused) sites whose .lerd.yaml lists the service or whose .env references lerd-{name}.
func (Site) CommandApproved ¶ added in v1.27.0
CommandApproved reports whether the user has consented to run command on the host for this site (see ApprovedCommands).
func (*Site) FrankenPHPQuadletSpec ¶ added in v1.25.0
FrankenPHPQuadletSpec resolves the entrypoint and env a site's FrankenPHP container should run with, applying the reload-aware worker entrypoint (octane:start --watch) when the project opted in. Both the apply path (siteops.FinishFrankenPHPLink) and the global install refresh resolve through here, so a site's quadlet can't diverge between the two writers.
func (*Site) IsCustomContainer ¶ added in v1.15.0
IsCustomContainer returns true when the site uses a per-project custom container instead of the shared PHP-FPM image.
func (*Site) IsCustomFPM ¶ added in v1.25.0
IsCustomFPM returns true when the site is a PHP project served by fastcgi from its own per-site image, built from a Containerfile (a container: config with no port). It is a normal PHP-FPM site whose container is per-site.
func (*Site) IsFrankenPHP ¶ added in v1.18.0
IsFrankenPHP returns true when the site is served by a per-site dunglas/frankenphp container instead of the shared PHP-FPM image.
func (*Site) IsGroupMain ¶ added in v1.24.0
IsGroupMain returns true when the site owns a group's base domain: it has a group key but no subdomain of its own.
func (*Site) IsGroupSecondary ¶ added in v1.24.0
IsGroupSecondary returns true when the site occupies a subdomain of its group main's base domain.
func (*Site) IsHostProxy ¶ added in v1.24.0
IsHostProxy returns true when the site is a host-proxy site: nginx reverse-proxies the domain to a host process instead of a container.
func (*Site) PrimaryDomain ¶ added in v1.5.0
PrimaryDomain returns the first (primary) domain for the site.
type SiteInit ¶ added in v0.5.4
type SiteInit struct {
// Container to exec into. Defaults to lerd-<service name>.
Container string `yaml:"container,omitempty"`
// Exec is passed to sh -c inside the container.
Exec string `yaml:"exec"`
}
SiteInit defines an optional command to run inside the service container once per project when `lerd env` detects this service. Use it for any per-site setup: creating a database, a user, indexes, etc. The exec string may contain {{site}} and {{site_testing}} placeholders, which are replaced with the project site handle at runtime.
type SiteRegistry ¶
type SiteRegistry struct {
Sites []Site
}
SiteRegistry holds all registered sites.
func LoadSites ¶
func LoadSites() (*SiteRegistry, error)
LoadSites reads sites.yaml, returning an empty registry if the file does not exist.
type StripeConfig ¶ added in v1.24.0
type StripeConfig struct {
// Path is the webhook route the listener forwards events to, e.g.
// "/webhooks/stripe". Empty uses DefaultStripeWebhookPath.
Path string `yaml:"path,omitempty"`
// SecretEnvKey pins which .env key holds the Stripe secret. Empty probes
// StripeSecretEnvCandidates in order.
SecretEnvKey string `yaml:"secret_env_key,omitempty"`
}
StripeConfig is the optional per-project Stripe listener config in .lerd.yaml. Both fields are optional: empty values fall back to auto-detection and the default webhook path, so Laravel projects need no config at all.
type TuningSpec ¶ added in v1.23.0
type TuningSpec struct {
// Target is the absolute in-container path the override is mounted
// to. Required. Lerd bind-mounts the host file
// (ServiceTuningFile(svc.Name)) read-only at this path; the image
// must auto-include the file or be pointed at it via Command.
Target string `yaml:"target"`
// Template is the body lerd seeds the host file with on first use.
// Optional; defaults to an empty file. Conventionally a commented
// hint sheet so users discover the available knobs without lerd
// having to ship working defaults.
Template string `yaml:"template,omitempty"`
// Command, when set, overrides the container Exec so the image
// actually loads the override (e.g. `redis-server <path>` for an
// image that loads no config by default). Leave empty for images
// whose entrypoint already auto-includes the target path.
Command string `yaml:"command,omitempty"`
}
TuningSpec is the YAML shape user-authored CustomService entries use to declare their own tuning override without having to match a recognised family. Set svc.Tuning to expose the Config tab + lerd service config for any image whose config loader reads from a specific in-container path.
tuning:
target: /etc/memcached.conf
template: |
# Lerd user tuning for this memcached service.
# -m 128
command: memcached -f /etc/memcached.conf # optional, only when the
# image needs to be told
# to read the file
type WorkerNotFoundError ¶ added in v1.11.0
type WorkerNotFoundError struct {
Name string
}
WorkerNotFoundError is returned when a custom worker name is not in .lerd.yaml.
func (*WorkerNotFoundError) Error ¶ added in v1.11.0
func (e *WorkerNotFoundError) Error() string
type WorkerProxy ¶ added in v1.10.0
type WorkerProxy struct {
Path string `yaml:"path"` // URL path to proxy (e.g. "/app")
PortEnvKey string `yaml:"port_env_key,omitempty"` // env key holding the port (e.g. "REVERB_SERVER_PORT")
DefaultPort int `yaml:"default_port,omitempty"` // fallback port if env key is missing (default: 8080)
}
WorkerProxy describes an HTTP/WebSocket proxy that nginx should configure for this worker. When present, nginx adds a location block that proxies requests to the worker inside the PHP-FPM container.
type WorktreeDBEntry ¶ added in v1.19.0
type WorktreeDBEntry struct {
Site string `yaml:"site"`
Branch string `yaml:"branch"`
Service string `yaml:"service"`
DBName string `yaml:"db_name"`
}
WorktreeDBEntry tracks one isolated worktree database so lerd can drop it later — even after `git worktree remove` deletes the worktree's .lerd.yaml.
func FindWorktreeDB ¶ added in v1.19.0
func FindWorktreeDB(site, branch string) (WorktreeDBEntry, bool, error)
FindWorktreeDB returns the entry for (site, branch), if present.
func LoadWorktreeDBRegistry ¶ added in v1.19.0
func LoadWorktreeDBRegistry() ([]WorktreeDBEntry, error)
LoadWorktreeDBRegistry returns the persisted entries, an empty slice if the file is missing.
func RemoveWorktreeDB ¶ added in v1.19.0
func RemoveWorktreeDB(site, branch string) (WorktreeDBEntry, bool, error)
RemoveWorktreeDB deletes the entry for (site, branch) and returns the removed entry along with whether one was found.
func WorktreeDBsForSite ¶ added in v1.19.0
func WorktreeDBsForSite(site string) ([]WorktreeDBEntry, error)
WorktreeDBsForSite returns all entries belonging to a given site.
type WorktreeLANEntry ¶ added in v1.19.0
type WorktreeLANEntry struct {
Site string `yaml:"site"`
Branch string `yaml:"branch"`
Port int `yaml:"port"`
}
WorktreeLANEntry tracks one LAN share proxy bound to a worktree subdomain. LAN ports are machine-local (don't travel with the branch), so this registry lives under ~/.local/share/lerd, separate from the worktree's .lerd.yaml.
func FindWorktreeLAN ¶ added in v1.19.0
func FindWorktreeLAN(site, branch string) (WorktreeLANEntry, bool, error)
FindWorktreeLAN returns the entry for (site, branch).
func LoadWorktreeLANRegistry ¶ added in v1.19.0
func LoadWorktreeLANRegistry() ([]WorktreeLANEntry, error)
LoadWorktreeLANRegistry returns persisted entries, empty when the file is missing.
func RemoveWorktreeLAN ¶ added in v1.19.0
func RemoveWorktreeLAN(site, branch string) (WorktreeLANEntry, bool, error)
RemoveWorktreeLAN deletes an entry and returns it along with whether one was found.
func WorktreeLANsForSite ¶ added in v1.19.0
func WorktreeLANsForSite(site string) ([]WorktreeLANEntry, error)
WorktreeLANsForSite returns all entries belonging to a given site.
Source Files
¶
- custom_service.go
- framework.go
- frankenphp_detect.go
- frankenphp_reload.go
- global.go
- paths.go
- paused.go
- php_versions.go
- preset_files.go
- preset_source.go
- presets.go
- profiler.go
- project.go
- project_update.go
- service_manual.go
- service_set.go
- service_tuning.go
- site.go
- slug.go
- sourcedirs.go
- store_index.go
- stripe.go
- worktree_db_registry.go
- worktree_lan_registry.go
- worktree_overrides.go
- worktree_parent.go