Front matter is the YAML metadata block at the top of each page. Its keys are documented, with examples, in Front matter.
Site-wide configuration in public_html/lazysite/lazysite.conf. One
key-value pair per line.
key: value - used as-is.
key: ${ENV_VAR} - interpolated from the CGI environment. Multiple
vars and mixed text supported: ${REQUEST_SCHEME}://${SERVER_NAME}
key: url:https://... - fetched, trimmed, and cached with the page.
key: scan:/path/*.md sort=field dir limit=N offset=N - returns array of
page objects, at most scan_limit of them (limit= and offset= page the
sorted list, limit= capped by scan_limit), and key_total, the number the pattern
matched that the reader may see.
site_namesite_url${REQUEST_SCHEME}://${SERVER_NAME} so the same
config works on staging and production.
layoutlazysite/layouts/NAME/layout.tt. May also be a remote URL.
themelazysite/layouts/LAYOUT/themes/THEME/theme.json. The theme's
layouts[] array must contain the active layout or the theme is
skipped with a warning.
layouts_reponav_filelazysite/nav.conf.
scan_limitscan: reads, the first in file-name order. Default
200. A scan that reaches more logs a warning; its _total says how many.
The ceiling for a directive's limit=.
cspreport-only (the default, and what any
unrecognised value reads as), enforce, or off. The manager is never
enforced.
app_name, app_short_name, app_scope, app_start_url, app_theme_colour, app_background_colour, app_icon_64, app_icon_192, app_icon_512, app_icon_maskable, app_shell, app_offline_pages, app_updateapp_scope, as an app: the engine
generates the web app manifest and the service worker from these. Setting
app_name turns it on. See Installing a site as an app.
maintenance, maintenance_page, maintenance_untilmaintenance: on sends every page request, by
a temporary redirect (302), to maintenance_page - a path on the site, or an
https:// address; the default is /maintenance, a page the site ships and
you can restyle by writing your own maintenance.md. The maintenance page
itself answers 503 with Retry-After, the number of seconds to
maintenance_until (UTC, 2026-11-01 18:30; an hour when it is not set). A
form posted meanwhile is refused with the maintenance message and not stored,
and MCP, the control API, WebDAV and the data endpoint answer 503. The
exception is an account holding the maintenance_access capability (Access
during maintenance), which the operator group and the site-admins role hold and
any group can be given:
it browses the site as normal, under a banner. The sign-in pages, the
maintenance page and the assets they need stay reachable. On an instance
serving several domains alias.<host>.maintenance: on puts one declared
domain in maintenance (and alias.<host>.maintenance_page, .maintenance_until
give it its own), while maintenance: on covers them all. Anything but on
is off. Set on the Config page, and per domain on the Domains page; lazysite
check warns while it is on. A file the web server serves by name (an image, a
stylesheet, a cached page asked for by its .html name) is not a page request
and is not affected.
csp_script_src, csp_connect_src, csp_img_src, csp_frame_srccsp_script_src: https://ads.example.com,
https://*.cdn.example.com. Each entry is an https origin - https://host or
https://host:port, a leading *. for subdomains - and nothing else: no bare
*, no path, no 'unsafe-...' or other keyword. An entry that is not an
origin is left out of the policy and logged, and lazysite check names it.
On an instance serving several domains, alias.<host>.csp_script_src: (and
the others) gives a domain its own list in place of the site's. The manager's
pages carry none of them.
search_defaultsearch: front matter key. Set to true
(default) or false. Pages without an explicit search: key inherit
this value.
managerenabled or disabled. Controls the built-in manager UI at
/manager.
manager_path/manager.
manager_groups (retired - SM138)ui capability granted to a group (Groups
page); on upgrade any group this key named receives its capabilities and the
line is removed.
update_channeledge < beta < stable < certified ladder: stable takes supported
releases; certified takes only builds whose compliance records were
walked (ADR 0010),
beta takes beta and stable, any other value (default) accepts every
release. Out-of-channel upgrades are skipped and audited. See
Update channel.
update_policyauto or manual (default). Whether the fleet-wide
lazysite upgrade --all run on deb-managed hosts upgrades this site;
manual sites are skipped. Set with lazysite policy auto|manual.
log_levelERROR, WARN, INFO, DEBUG. Default: INFO.
log_formattext (default) or json.
extensionsauth_defaultauth: front matter key. Set to required,
optional, or none (default).
auth_header_user, auth_header_name, auth_header_email, auth_header_groupsX-Remote-User, X-Remote-Name, X-Remote-Email, X-Remote-Groups.
alias_hostsalias.<host>.<key><key> is limited to the per-host keys
listed under Domain aliases (presentation,
language, the CSP allow-lists, the app keys and the maintenance keys);
other keys are ignored with a logged warning. Each alias host has its
own page-cache slot (lazysite/cache/hosts/), cleared alongside the
primary cache. Set in the conf, on the manager's Domains page, or
with the domain-set control-API action, which take the presentation,
language and maintenance keys.
All other keys are available as TT variables in page content and the layout template.
See Configuration for full details.
page_titletitle:.
page_subtitlesubtitle:.
page_modifiedpage_modified_isocontentrequest_uri/about. Set from REDIRECT_URL or
REQUEST_URI, without any query string or fragment.
page_urlsite_url plus the path,
never the query. Already escaped, so write it as [% page_url %] in
og:url and <link rel="canonical">. Empty when site_url is not set.
page_source.md file, e.g. /about.md.
Useful for admin bar and edit links.
navnav.conf. Each item has label, url,
children (array of label/url hashes).
query, paramsquery_params: is declared
in front matter. params is an alias for query.
year2026.
search_enabled1 if a search-results.md (or .url) page exists in the docroot,
0 otherwise.
site_name, site_urllazysite.conf.
alias_hostbrand2.example) when the request's
Host header matches a declared alias_hosts entry; empty string on the
primary host. Useful for per-host branching.
canonical_urlsite_url of the domain this host is an alias of (one serving the same
content folder, listed before it), or this host's own site_url. The engine's
canonical link and the registries use it; a layout that writes its own
canonical link should too.
layout_namethemetheme.json (hash) when a compatible theme is active. Access
config values as [% theme.config.GROUP.KEY %]. Empty hash when no
theme is active.
theme_nametheme_assets/lazysite-assets/LAYOUT/THEME/ for local themes (nested per D013);
/lazysite-assets/CACHE_KEY/ for remote layouts (flat).
Unset when no theme is active.
theme_css<style>:root { ... } block of CSS custom properties
derived from theme.config. Empty string when no theme is active.
Naming convention: --theme-GROUP-KEY.
authenticated1 if the request carries valid auth headers, 0 otherwise.
auth_userauth_nameauth_emailauth_groupseditor1 if the authenticated user has manager access (a group grants the ui
capability), 0 otherwise. Use in layouts to gate admin UI.
visitor.in_list('NAME'), visitor.in_any(['A', 'B'])1 when the visitor's address is on the named address list (or on any of the
lists), 0 otherwise, including when no such list exists. It answers
membership only: no variable holds the address. A page, include or layout
that calls it is rendered for each request, never kept in the page cache, and
sent Cache-Control: no-store, private. The address is the one trusted_proxies
works out, so behind a front end name it there. See
Showing the visitor's IP.
Site variables (from lazysite.conf) are loaded first. Page variables
(from tt_page_var) override site variables of the same name. Automatic
variables (page_title, page_subtitle, content, etc.) override both.
Only these CGI variables may be interpolated via ${VAR} in
lazysite.conf:
SERVER_NAME - server hostnameSERVER_PORT - server portREQUEST_SCHEME - http or httpsHTTPS - on if HTTPSREQUEST_URI - full request URIREDIRECT_URL - requested page path (e.g. /about)DOCUMENT_ROOT - filesystem docroot pathSERVER_ADMIN - server admin emailHTTP_HOST is intentionally excluded - it is request-supplied and
untrusted. Use SERVER_NAME for host-based URL construction.
sanitise_uri rejects null bytes, .. path segments, and suspicious
characters before constructing filesystem paths. After construction, each
path is verified with realpath to confirm it resolves within $DOCROOT.
Symlinks pointing outside the docroot are rejected.
The same check is applied inside write_html before any file is written,
guarding against symlink-based overwrite attacks on the cache output path.
All values extracted from YAML front matter - including title, subtitle,
and tt_page_var entries - have TT directive markers ([%` and `%]) stripped
before entering the template context. register list items are stripped at
parse time. This prevents authored content from injecting TT directives into
the rendering pipeline.
The class name following ::: is validated against /\A[\w][\w-]*\z/ before
use. Blocks with class names containing characters outside word characters and
hyphens are rejected - the content renders without a wrapper div and a warning
is written to the error log.
oEmbed provider responses are parsed with JSON::PP (Perl core module) rather
than regex extraction. The html field from the parsed response is injected
into the page. Provider responses are trusted as-is - restrict %OEMBED_PROVIDERS
in lazysite-processor.pl to known hosts if untrusted providers are a concern in
your deployment.
DOCROOT/
lazysite/
lazysite.conf <- site configuration
nav.conf <- navigation
layouts/
NAME/layout.tt <- layout template
NAME/layout.json <- layout metadata (optional)
NAME/themes/THEME/
theme.json <- theme manifest
main.css <- theme-scoped CSS
assets/ <- theme assets (images, fonts)
manager/
layout.tt <- manager UI chrome (internal)
assets/manager.css <- manager CSS source
templates/
registries/ <- registry templates (.tt)
auth/
users <- user credentials
groups <- group memberships
forms/
FORMNAME.conf <- per-form target config
handlers.conf <- the handlers a form or the schedule calls
schedule.conf <- what the timer calls
smtp.conf <- SMTP connection settings
cache/
layouts/ <- remote-layout cache
tt/ <- TT compile cache
logs/ <- log files
lazysite-assets/
LAYOUT/THEME/ <- web-served theme assets (nested)
manager/
assets/
manager.css <- manager CSS (mirrored from source)
cm/ <- CodeMirror assets
404.md
index.md
[content pages]
Scripts (repo root, copied to site by the installer):
lazysite-processor.pl <- main processor
lazysite-auth.pl <- built-in auth
plugins/form-handler.pl <- form dispatch
plugins/form-smtp.pl <- SMTP helper
lazysite-manager-api.pl <- manager JSON API
plugins/payment-demo.pl <- payment demo helper
Source files:
*.md <- Markdown pages
*.url <- remote page pointers
*.html <- generated cache (auto-created)
Registry output (generated at DOCROOT):
sitemap.xml <- generated from sitemap.xml.tt
llms.txt <- generated from llms.txt.tt
feed.rss <- generated from feed.rss.tt
feed.atom <- generated from feed.atom.tt