Blueprint authoring
How a site type is defined — the blueprint, its required services, environment, install steps, the smoke check, the beta badge, and how to add a new one.
A blueprint is how a site type (WordPress, PHP, static, Node, Python) is defined. Like the
catalog, a blueprint is data, not a release: each type lives in its own
file, validated against a schema. Adding or changing a site type is a data change — no deploy, no
database migration. All site types share one definition shape, distinguished only by their type.
Where blueprints live
The contract is panel/src/catalog/blueprints/types.ts; the five type definitions are in
panel/src/catalog/blueprints/entries/ (wordpress.ts, php.ts, static.ts, node.ts,
python.ts). The launch engine (panel/src/server/sites/launch.ts) runs a blueprint's steps with
the same compiler the catalog uses.
What a blueprint declares
A blueprint declares everything needed to launch the site type, as plain data:
id/type/name/summary—typeis the site type (one blueprint per type).requiredServices— the catalog categories the type needs (e.g. WordPress needswebserver+php+database). Each may pin a specific entry or version; omit it to use the category's default. The wizard uses this to sort instances into compatible / install-on-the-way / none, and the engine installs any missing category on the way during launch.servedPort— the port the site serves on inside the instance.envContract— the environment variables the site accepts (what the env editor validates against).credentials— the secrets a launch creates (e.g. a database password), stored encrypted.steps— the install/deploy plan (below). Must end in acheck.smoke— the smoke check (below).backup— what to back up (the stateful paths, and whether the database is included).beta—trueuntil the type is verified live; flipping it tofalseis a data change.
Required services and the environment
requiredServices names categories, never specific software — the engine resolves each to a
catalog entry (a pin, else the default) and installs it inside the instance if missing. The
envContract is a list of items, each with:
key—SCREAMING_SNAKE_CASE;required/secretflags;default— used when you supply no value (non-secret only);generate—"none"(you or the blueprint supplies it), or"hex32"/"hex64"to generate a random secret at launch (this is how WordPress mints unique salts and keys per install).
A secret never ships a default value
An environment item marked secret must not carry a default value — a secret must be generated or
supplied by you, never baked into the blueprint. A secret is stored encrypted and revealed once,
with an audit record.
Steps — the same kinds as the catalog
A blueprint's steps use the same step kinds the catalog uses, run inside the instance:
exec— run a command (the workhorse: write configs, run the installer);file— write file content to a path inside the instance;service— manage a systemd unit (e.g. enable a Node app's unit);check— a read-only check that confirms a step worked (the gate).
Every blueprint must end in a check step, and each step carries a remedy — the message shown
when it fails (and the one used to resume). Steps marked idempotent can run again safely, so a
relaunch of an already-set-up site changes nothing.
The site's environment reaches each step by being passed in alongside the command, so a step can
reference $WP_* and the value is filled in inside the instance. Values are passed as discrete
tokens, so a value with spaces or quotes can't break the command.
The smoke check — proof the site actually serves
Every blueprint must declare a smoke check: the final check steps that prove the site is
actually serving (HTTP 200 on its port, a type-specific reachability check, the database connected).
A failed smoke check means the site is marked failed with a remedy — never live. smoke names:
stepIds— thecheckstep ids that make up the gate (each must exist and be acheck);httpPath— the path the 200 check hits (e.g./,/wp-login.php);securityHeaders— confirm the default config returns the baseline security headers.
The beta badge
A blueprint is beta until it's been verified live. beta: true shows a badge in the wizard;
once the type is proven to launch and serve, the badge clears by flipping beta to false — a data
change.
Adding a new blueprint
Adding a site type is a contained data change:
- Add
panel/src/catalog/blueprints/entries/<type>.tsdefining the blueprint — required services, environment, credentials, steps (ending in acheck), the served port, and the smoke check. - Register it in the blueprints index and add the new
typetoSITE_TYPES. - A check run under
pnpm check/pnpm testenforces the rules: ids unique, steps end incheck, everysmokestep id names an existingcheckstep, the served port is declared, required-service categories are valid, and no secret ships a default. A broken blueprint fails the check with a clear message. - Prove it live:
pnpm rig -- --stage site-live --type <type> --profile clean. When it's green, clear the beta badge.
No part of the platform special-cases a type — the engine, the wizard, and the API all work the same way for every blueprint.
WordPress settings
Tune a WordPress site without touching a config file — the fronting web server (nginx or OpenLiteSpeed), PHP limits, OPcache, and page / object caching, applied with one click.
Site owners (isolation)
Each isolated site gets its own Linux owner inside the instance — a login user that owns the docroot and has a narrow, safe permission grant, so a site is walled off from its neighbours.