ddtcorex

09 Aug 2026 · 5 min read

Under the hood of `govard env up`

A close look at the five-phase pipeline that brings a Govard environment online — from blueprint rendering and networking to resilient image pulls and global services.

When you run govard env up in a project directory, a lot happens before your site is reachable at https://project.test. Govard is a Go-native orchestrator, so the whole startup sequence runs as a single fast binary — no PHP bootstrap script, no Node wrapper, no shell ceremony. This post walks through exactly what that binary does, phase by phase, and what each step buys you.

The high-level design is documented in the architecture overview, and every flag referenced here is described in the configuration reference.

The 5-phase startup pipeline (detect, validate, render, start, verify)

govard env up (alias govard up) is deliberately split into five ordered phases. Each one has a clear contract, and a failure early stops the chain before it wastes time pulling images or starting containers.

  1. Detect — Govard reads .govard.yml (and any active profile layers) and identifies the framework in the current directory. Detection is registry-driven, so it never hard-codes a branch or a framework name.
  2. Validate — the resolved configuration is checked for internal consistency: required services exist, ports don't collide, and the effective profile resolves cleanly. govard doctor runs a superset of these checks on demand.
  3. Render — the matching blueprint is expanded into concrete Docker Compose files, environment files, and virtual-host definitions.
  4. Start — compose is brought up, images are pulled (with local fallback), and networks are attached.
  5. Verify — Govard probes the running services, confirms the reverse proxy answers on the .test domain, and reports a ready summary.

You can watch each phase in the logs:

govard env up
govard env logs        # tail all service logs
govard env ps          # show container status

If a phase fails, the partial environment is left in a known state so you can inspect it with govard env ps rather than staring at a half-built mess.

Blueprint rendering (Go text/template, framework-specific services.yml)

The "render" phase is where Govard earns its flexibility. Each framework ships a blueprint — a set of Go text/template assets — under its own package, while assets shared across frameworks live in a common blueprints directory. This keeps framework logic isolated and the shared contract in one place.

For a detected project, Govard renders a framework-specific services.yml that declares the containers that project actually needs: the web server, the PHP-FPM variant matching the detected version, the database, and any optional services you enabled in configuration. Because the templates are data-driven, the same Magento, Laravel, Symfony, or WordPress project gets a tailored compose file without you maintaining one by hand.

The effective output is controlled by your configuration, including profile layers that merge over the base .govard.yml. You can inspect what Govard resolved before starting anything, which is the fastest way to debug a surprising service set:

govard config profile       # show the resolved effective profile
govard env ps               # confirm what actually came up

Adding support for a new framework means contributing a blueprint package and registering it, not forking the core — see adding a framework.

Networking & HTTPS (Caddy reverse proxy, dnsmasq *.test, 308 redirect, root CA auto-trust)

Local HTTPS is a first-class concern in Govard, not an afterthought. During the start phase, a Caddy reverse proxy is wired in front of your project and issued a certificate from Govard's local root CA. That root CA is auto-trusted on your machine during setup, so browsers show a real green lock for https://project.test with no manual例外.

Two pieces make the domain magic work:

  • dnsmasq *.test — a local resolver answers every *.test query with 127.0.0.1, so any project you bring up is immediately addressable without editing /etc/hosts.
  • 308 redirect — HTTP requests are permanently redirected (status 308) to HTTPS, so bookmarks and integrations always land on the secure origin.

The net effect: govard env up ends with a URL you can paste into a browser and trust, with no curl -k workarounds. The proxy and DNS wiring are part of the orchestration described in the architecture overview.

Tip: if a .test domain stops resolving after a reboot, the dnsmasq service is usually the culprit — govard doctor flags it, and a fresh govard env up re-establishes the resolver.

Resilient image pull & local fallback

Image pulls are the part of local dev most likely to fail on a flaky connection, so Govard treats them defensively. When bringing a stack up, it attempts the normal registry pull, and if that fails (timeout, auth hiccup, offline), it falls back to any locally cached image rather than aborting the whole environment. You get a working, if slightly stale, container instead of a dead startup.

This matters for repeatable workflows: once you've pulled a PHP or database image once, subsequent govard env up runs are resilient to network trouble. When you do want to force fresh images, a normal govard env restart plus a re-pull keeps things current, and govard self-update keeps the orchestrator itself current.

govard env down      # stop and remove containers
govard self-update   # update the Govard binary
govard env up        # bring it back, reusing cached images

Global services (Mailpit, PHPMyAdmin, Portainer)

Some services are useful across every project, so Govard runs them once as shared global services rather than spinning up a copy per project. The standard set includes:

  • Mailpit — captures outbound email from your app so you can inspect password resets and order confirmations in a local inbox instead of guessing whether mail "sent".
  • PHPMyAdmin — a web UI for the database, handy when a raw govard db shell isn't enough.
  • Portainer — a management UI for the underlying Docker containers, useful when you want to see resource usage or restart a single container without leaving the browser.

These global services are brought up as part of the environment lifecycle and exposed on their own local ports, keeping them out of your per-project services.yml while still being one govard env up away. For database work specifically, the govard db family of commands — govard db dump, govard db import, govard db top — talks to the same database container the global UIs visualize.

Next in this series: Framework intelligence & discovery in Govard — /blog/govard-framework-discovery

govarddockerblueprints