What lazysite does, grouped by what you are trying to achieve. Each capability links to its 'how it works' reference for the mechanics.

Authoring & content

Write pages as plain text and let lazysite turn them into a site.

Markdown, served instantly

Drop a .md file in the docroot and it is served as a fully rendered HTML page on first request, then cached. No build step, no pipeline.

Template Toolkit variables

Pages can carry dynamic values - site config, page front matter, computed expressions, conditionals and loops - resolved at render time.

How it works: TT variables →

Reusable content includes

Inline shared Markdown partials, code files or remote fragments into a page so common content lives in one place.

How it works: Includes →

Cached remote includes

Includes can fetch remote content and cache it for a set time, so external data appears inline without a fetch on every request.

How it works: Include TTL →

Pull in remote pages

A .url file makes lazysite fetch Markdown from a remote URL (such as a GitHub raw file) and render it through the same pipeline - so docs can live with the code.

How it works: Remote pages →

Rich layout blocks (fenced divs)

Wrap content in :::named blocks that become styled containers - callouts, columns, hero sections - without leaving Markdown.

How it works: Fenced divs →

Embed media (oEmbed)

Paste a video or social URL and lazysite expands it into the proper embed automatically.

How it works: oEmbed →

QR codes in content

A ::: qr block turns a link, a payment URL or a wifi string into a QR code on the page - drawn client-side from a bundled library, with no external service involved.

How it works: QR codes →

List and scan pages

Generate indexes, galleries and menus by scanning a folder of pages and looping over them - with optional filtering by tag, date or path.

How it works: Page scan →

Site search

A built-in search index and results page let visitors find content without an external service.

How it works: Search →

Sitemaps & registries

Auto-maintained sitemap.xml and llms.txt registries so search engines and AI agents can discover every page.

How it works: Registries →

Dynamic pages from query parameters

Read URL query parameters in a page to vary its output - simple dynamic pages with no application code.

How it works: Query parameters →

JSON & API output

Serve a page as pure data with api mode, or as an unwrapped fragment with raw mode - the same content reused as an API.

How it works: API mode →

Page aliases & redirects

List old or alternate URLs in a page's front matter and lazysite redirects them - permanently or temporarily - to the canonical page, so links keep working when content moves.

How it works: Aliases →

Custom error pages

Author your own 404 (and other status) pages as ordinary Markdown.

How it works: 404 page →

Design: layouts & themes

Structure, style and content stay in separate layers that never touch.

Layouts and themes

A layout.tt owns the HTML chrome; a theme on top supplies colours, fonts and assets; content stays in .md files. Swap any layer independently - and if no layout is installed at all, an embedded fallback still renders a complete page.

How it works: Layouts →

Design tokens

A theme declares its palette and type as tokens in theme.json, auto-emitted as CSS custom properties - re-skin a site by editing values, not stylesheets.

How it works: theme.json →

Per-page layout override

Any single page can opt into a different layout from front matter - a landing page or print view without affecting the rest.

How it works: Layout override →

Install & publish themes

Install layouts and themes from a catalogue, upload a zip, or pull them from a remote source - activation validates the candidate and snapshots the outgoing version, so a change is easy to reverse.

How it works: Theme publishing →

Dynamic & interactive

Forms, accounts and payments are built in - no plugins to bolt on.

Customisable forms, built in

Build a contact, signup or feedback form right in Markdown with the :::form syntax - it works out of the box, validates input, accepts file and image attachments, and delivers to email or a handler. Fully customisable, and no third-party service or code required.

How it works: Forms →

Multi-step forms

Split a longer form into wizard steps with Back/Next navigation and per-step validation - still a single submission, and it degrades gracefully when JavaScript is off.

How it works: Forms →

Authentication & access control

Protect pages or whole sections behind sign-in, with the right state revealed per visitor.

How it works: Auth →

Payments (x402)

Gate content or downloads behind a payment using the x402 protocol, built into the core.

How it works: Payment →

Navigation from a config file

The site menu is a plain nav.conf file read by the layout - edit the menu without touching templates.

How it works: nav.conf →

Web manager UI

A browser-based manager to edit content, themes, navigation, users, backups and statistics without the command line.

How it works: Manager →

Operator notifications

Form submissions and requests awaiting a reply land in the manager's notices bell, and can also be delivered over XMPP - so a submission always reaches a human.

How it works: Notifications →

WebDAV & AI publishing

Publish over WebDAV and a control API - the path an AI agent or script uses to manage a site with no GUI in the loop. Standard WebDAV clients work too, including Windows Explorer and macOS Finder.

How it works: WebDAV →

Advanced data & templating

Power-user features for data-driven pages and feeds - no plugins, no build.

JSON data files

Point json:/data/file.json at a local JSON file and it is decoded into a real data structure you can loop over in the page - FOREACH, nested loops, indexed access and .size. The comparison and feature tables on this very site are built this way.

Template Toolkit helpers

The full Template Toolkit is available in pages and layouts: string, list and hash methods (split, join, replace, sort, first, last, size, match and more), computed expressions, and FILTERs such as markdown - real data shaping with no plugin.

How it works: TT variables →

RSS & Atom feeds

Register feed.rss and feed.atom in a page's front matter and lazysite emits both, generated from a scan of your pages and kept in sync as content changes - readers and aggregators subscribe directly.

How it works: Feeds →

Remote data & JSON

Pull a live value from a remote URL with url: (a version badge, an API field), or inline remote Markdown and feeds with includes - external data rendered through the same pipeline and cached for a chosen time.

How it works: Remote pages →

Operate & maintain

Files on disk, fast by default, and trivial to back up or move.

No database

Files are the source of truth. Nothing to provision, dump or migrate - back up by copying the folder.

Tiny footprint, low cost

One small CGI script plus a few Perl modules - no database, no application server, no build pipeline. The minimal infrastructure runs on almost anything and costs very little to host.

Self-contained, no external services

The engine runs entirely on your own server - just Perl and a web server - with no embedded AI and no dependency on any third-party or cloud service to operate. Nothing phones home, and nothing breaks when an outside API changes its terms or disappears. AI publishing is optional and uses an assistant you choose and control, not a service baked in.

Fast by default

Dynamic only on the first request; plain cached HTML is served after that, with fine-grained control over caching.

How it works: Cache management →

Persistent worker pools

For production speed, run the same processor as a per-site FastCGI pool - modules compile once, and a cached page measured at 62 ms as plain CGI serves in 0.4 ms. Plain CGI stays the default and behaves identically.

How it works: Worker pools →

Static export

Run in generation mode to produce a fully static site you can host anywhere - the same content, no server process.

How it works: Build static →

Local dev server

A built-in server renders any Markdown tree locally with live preview - no install needed to start.

How it works: Dev server →

Link auditing

Scan the site for broken internal links, orphan pages, missing titles and stale cached copies before you publish.

How it works: Link audit →

Configuration in one file

Site-wide settings live in a single lazysite.conf, with overrides where you need them.

How it works: lazysite.conf →

Version-control ready

Everything is a file, so the whole site - content, layout and theme - lives in a git repository.

Content version history

Switch on the Content history plugin and every edit - by a person or an agent - becomes a version you can view, diff and restore from the manager, with optional sync to a private git remote you control.

How it works: Content history →

Backups & site migration

Take content or full-system backups from the manager and restore content in-app; a full-system restore can rewrite the domain, moving a whole site - content, config and accounts - to its final home in one command.

How it works: Backups →

Overlay an existing site

Install lazysite over a live HTML site without losing anything - existing pages carry on being served, and each one migrates to Markdown when you are ready, page by page.

How it works: Overlay install →

First-party visitor analytics

Lazysite records its own traffic - anonymised at write, never storing the IP - so the statistics dashboard works out of the box, with no web-server log access and no third-party analytics service.

How it works: Visitor analytics →

Built-in site doctor

A health checker probes permissions, configuration and secrets exactly as the web server sees them, fixes what it can, then re-checks and reports the result.

How it works: Site doctor →

Packaged installs

Install from Debian packages with a lazysite CLI for provisioning and upgrades, one-command domain onboarding on HestiaCP, and a zero-configuration demo command that serves a scratch site locally.

How it works: Packaged installs →

Release channels & fleet updates

Each site declares the release maturity it accepts - edge, beta or stable - and whether upgrades apply automatically; fleet-wide upgrades respect every site's policy, with an override reserved for critical security fixes.

How it works: Update channels →

Audited releases, five-year support

Releases are built by a gated pipeline - full test suite, coverage floors, security lints and a software bill of materials - and the stable line carries a declared five-year support period.

How it works: Releases & support →

Multi-site & multilingual

One install can serve many domains and many languages - each first-class, all under one set of accounts.

Many domains, one instance

Host multiple first-class domains on a single install, each with its own content root, navigation and settings - confined from one another, managed through one engine and one set of accounts.

How it works: Multi-site →

Domain delegation

Delegate a domain to a group so its members manage that site's content and settings - with a preview that works before DNS even points at the server, and a panel that checks DNS, certificates and proxy wiring.

How it works: Domain delegation →

Multilingual sites

Publish the same site in several languages as linked per-language content roots - lazysite supplies the language switcher data, hreflang tags, localised page chrome and a translation-coverage report.

How it works: Multilingual →

Access, permissions & governance

Decide exactly who can do what, lock content down, and keep a record of every change.

Fine-grained capabilities

Channel-by-action grants carried by groups control exactly what each user or token can do - edit content, manage themes or layouts, change config, create sub-users. An account's rights are the union of its groups, checked once, server-side, across every surface.

How it works: Auth →

Per-file access control

Map any path to an owner with read and write lists (users or groups). Access only ever narrows, the owner is always allowed, and the same check binds the manager, WebDAV and the AI connector.

File locking

Lock a file so no one else can alter it. One lock store is shared across the manager and WebDAV, so a save anywhere respects a live lock.

Account & token expiry

Accounts and machine tokens can carry an expiry, after which access fails closed - useful for time-boxed contributors and partners.

Sub-users & delegation

A partner can mint scoped sub-accounts; onward delegation requires holding the capability itself, so nobody can grant more authority than they have.

Session visibility & revocation

See every live session - who, since when, from where, on what device - and sign out a single session, one user everywhere, or rotate the secret to sign out everyone at once.

How it works: Sessions →

Audit trail

An append-only log records who changed what, to what, when, from where, and the outcome - material changes only, never browsing.

Two-factor authentication

Optional TOTP second factor with recovery codes, self-contained with no external dependency.

How it works: Auth →

Automatic scanner blocking

Repeated probes for wp-login.php, .env and the like get the source IP blocked automatically - on by default, with blocked addresses listed and unblockable from the Stats page.

How it works: Scanner blocking →

Manager access stays interactive

An account that can reach the manager is refused on the API and MCP transports, so a leaked or misissued token on a manager account cannot drive the site remotely.

How it works: Interactive-only manager →

Protected internals

Scripts, secrets and credential files can never be read or written through the content tools - a hard deny-list, enforced on reads as well as writes.

AI & automation

Built for a human/AI partnership - agents publish through the same rules a person does.

AI publishing over WebDAV & API

An agent or script edits content over WebDAV and a JSON control API - no GUI in the loop - bound by exactly the same capabilities and ACLs as any human author.

How it works: WebDAV →

Analytics-driven improvement loops

An AI agent can read the site's own visitor analytics - aggregated and IP-anonymised, with real people separated from bots and crawlers - to see which content actually engages, then act on it: sharpen the copy, reorder or add pages, retune the layout or theme, and measure again. A continuous analyse-and-improve loop, run through the same publishing rules and permissions a person uses.

MCP AI connector

A built-in connector speaks the Model Context Protocol, so assistants such as Claude and ChatGPT can manage a site through first-class tools.

How it works: AI connector →

Pre-publish safety checks

Agents validate a page before it goes live - with a warning when content looks private, such as phone numbers or wifi passwords - preview it exactly as a visitor will see it, and audit the whole site for problems.

How it works: AI connector →

OAuth for AI partners

Web-based AI connectors authenticate via a minimal OAuth 2.1 server with PKCE - the person proves they may act as a partner, and no secret is ever typed into the third party.

One enforced core

Every door - browser, API, WebDAV, MCP - translates to the same shared handlers, so a lock, an ACL or a capability holds identically whoever knocks.

Beyond the capabilities above, see how lazysite is engineered - the testing, security and quality practices behind them.