Markdown-driven pages for any CGI-capable web server. No build step, no
database, no CMS. Drop a .md file in your docroot and it is served as
a fully rendered HTML page. The first request generates the HTML and
caches it; every subsequent request is a plain static file.
Content
- Markdown pages with YAML front matter
- Template Toolkit variables in pages and layouts
- Fenced divs, oEmbed, content includes
- Remote pages (
.urlfiles that fetch Markdown from a URL) - Page scan for blog/news index pages
- Registry files: sitemap.xml, llms.txt, RSS, Atom
- TTL-based cache and API/raw output modes
- Page alias redirects (
aliases:front matter → 301 to the canonical URL) - Per-request pages (
nocache:) and the visitor's IP as[% client_ip %]
Layouts and themes
- Template Toolkit layout templates (
layout.tt) - Themes nest under
lazysite/layouts/LAYOUT/themes/THEME/ - Design tokens auto-emit as CSS custom properties (
theme.config) - Built-in fallback so sites work with zero configuration
Manager
- Browser-based admin at
/manager - Config, Files, Nav, Plugins, Themes, Users, Cache, Audit, and Backups pages
- Recent-change markers on the Files and Users pages
- Typed backups (content + full-system) with cross-domain migration
- Admin bar on site pages for manager users
Authentication
- Built-in cookie auth (
lazysite-auth.pl) with users and groups - Drop-in replacement by any proxy that sets
X-Remote-*headers - Per-page
auth:andauth_groups:front matter - Per-user access mechanisms (browser UI / WebDAV) and generated credentials
Publishing
- WebDAV endpoint (
/dav, class 1+2) for headless per-file deploys - Works with
curl,rclone,davfs2, and Explorer/Finder mounts - Per-user path scopes; off by default, opt-in per user
Forms
- Inline
:::formblocks with field validation - Multi-step (wizard) forms with per-step validation (
--- step ---) - Named dispatch handlers (SMTP, file storage, webhooks)
- Honeypot, HMAC timestamp token, and rate limiting built in
Payment
- x402 payment flow support via
payment:front matter
Plugins
- Auto-discovery of CGI scripts and tools via
--describeJSON - Enable, disable, and configure from the manager
Operations
- Structured logging (text or JSON, env or config)
- Link audit (orphaned pages, broken internal links)
- Static site generation for GitHub Pages, Netlify, etc.
git clone https://github.com/OpenDigitalCC/lazysite.git
cd lazysite
perl tools/lazysite-server.pl
Open http://localhost:8080/ to browse the starter site.
The dev server can present any tree of Markdown - a docs/ folder, a notes
corpus - with no install, no cache, no theme and no index files, writing nothing
into the tree:
perl tools/lazysite-server.pl --docroot /path/to/tree --auto-index
--auto-index generates a directory index (folders and pages, with labels from
each note's front-matter title) plus a breadcrumb nav for any directory lacking
an index.md. Scaffolding is only ever seeded into a real lazysite docroot; an
arbitrary tree is left untouched (force seeding off anywhere with --no-seed).
You install lazysite on a host; you provision a site. Three site verbs, and you say which one you mean - none of them guesses from the state of the disk:
lazysite provision --docroot /path/to/public_html \
--cgibin /path/to/cgi-bin \
--domain example.com
lazysite upgrade --docroot /path/to/public_html
lazysite reinstall --docroot /path/to/public_html
provision refuses a docroot that already has a site; upgrade refuses one
that has none, and refuses a site already at this version - that is
reinstall, which re-lays this version's files and leaves content, accounts
and config alone. All three run as the site's user and refuse root.
From an unpacked tarball, before any package is installed, the same verbs work
out of the tree: perl tools/lazysite-cli.pl provision .... (install.sh
installs nothing; it prints the three verbs and exits.)
Seed files you've edited are preserved; code is always refreshed. --dry-run
previews without writing anything, lazysite backups --docroot D lists the
backups at {docroot}/lazysite/backups/ and --restore puts one back.
HestiaCP users: see installers/hestia/. Docker: see installers/docker/.
Open the admin at https://your-site/manager - go straight there rather than the
homepage. Some hosts (HestiaCP among them) seed a default index.html, which the web
server serves ahead of your lazysite homepage; /manager always works regardless. If
your homepage shows that placeholder, remove the stray file:
rm -f /path/to/public_html/index.html.
Create the first administrator with setup-sysop, which makes a NAMED account,
puts it in the sysops group and issues a single-use registration link (so no
password is handed over). A site may be deployed with no accounts at all - run
this when the person is ready to collect the link.
puts it in the admin group, enables the manager in lazysite.conf, and prints a
generated password if you don't supply one:
perl tools/lazysite-users.pl --docroot /path/to/public_html setup-sysop --user NAME
(The HestiaCP deploy runs this for you on a fresh install and prints the password in its output.) Pass a password as a final argument to set your own.
Full installation details in starter/docs/install.md.
To let an AI assistant manage the site over the connector (MCP), WebDAV, or the control API, provision a partner account - one command creates the account, grants the partner capability defaults on its own role group, and prints the onboarding brief:
perl tools/lazysite-users.pl --docroot /path/to/public_html partner-create my-agent --by manager
The brief is a ready-to-hand-over onboarding document - the connection details, the
partner's capabilities, and a fresh single-use pairing key the agent redeems for an
access token (re-print later with brief my-agent; the same brief is offered in the
manager UI under Users). Grant only the capabilities the task needs: the defaults cover
content, navigation, forms and themes - trim with --no-themes, extend with
--layouts / --config, confine with --scope /path.
Browse locally via the dev server, or read the Markdown directly:
starter/docs/install.md- installationstarter/docs/authoring.md- writing contentstarter/docs/configuration.md- lazysite.conf, nav, pluginsstarter/docs/layouts.md- layouts and themesstarter/docs/manager.md- the manager UIstarter/docs/auth.md- authenticationstarter/docs/forms.md- contact formsstarter/docs/payment.md- x402 paymentstarter/docs/development.md- dev server, rsync, troubleshootingstarter/docs/reference.md- keys, variables, file locations
AI-assistant briefings:
starter/docs/ai-briefing-authoring.mdstarter/docs/ai-briefing-layouts.mdstarter/docs/ai-briefing-configuration.mdstarter/docs/ai-briefing-development.md
Ready-to-use layouts and themes live in the companion repo
lazysite-layouts. Install a theme zip via the
manager Themes page, which unpacks it under
lazysite/layouts/LAYOUT/themes/THEME/. Layouts are installed
manually or via the "Install from Releases" browser.
- Perl 5.10 or later
- Apache or nginx with CGI support
- Template Toolkit (
libtemplate-perlon Debian) - Optional:
IO::Socket::SSLfor HTTPS SMTP delivery
MIT. See LICENSE.