Reboot CMS auf Borstensohn

Torsten Borstensohn testet Reboot CMS

Reboot CMS

A flat file, Markdown CMS in PHP, inspired by Pico, Redaxo and Craft CMS.

Reboot CMS is a minimal CMS without a database, but with the support of blocks to structure the content.

Edit a page

Why another CMS?

I developed Reboot CMS because I couldn't find a CMS that works with flat markdown files but allows easy use of blocks.

Reboot CMS is very small and the pages are delivered extremely fast. My website shaack.com, built with Reboot CMS, has a PageSpeed Insights performance score of 100.

Websites using Reboot CMS

Minimum System Requirements

  • PHP 8.0 or higher
  • Web Server: Apache with mod_rewrite (or compatible server)
  • No database required — all content is stored as flat files

Install

Clone or download the Reboot CMS repository:

Quick Start

Run the CMS with PHP's built-in web server (no Apache or Docker needed):

The site is available at http://localhost:8080, the admin at http://localhost:8080/admin. You can specify a custom port: ./run.sh 3000.

Docker / Podman

The site is available at http://localhost:8080.

Production Setup

Point your web server's document root to the web/ directory. The CMS should work out of the box.

On first visit to /admin, you will be prompted to create an admin account.

Directory Structure

  • core/src/ — Core CMS classes (Reboot, Site, Page, Block, Request, AddOn)
  • site/ — Site content: pages/, blocks/, addons/, template.php, config.yml
  • web/ — Document root (index.php, .htaccess)
  • local/ — Local environment config (config.yml, .htpasswd) — not in git
  • core/admin/ — Admin interface (itself a Reboot CMS site)

Configuration

  • site/config.yml — Site-wide settings: addon registration, navbar with brand and structure
  • local/config.yml — Local/environment settings (not committed to git):

Available editor tools: Headings, Bold, Italic, Strikethrough, UnorderedList, OrderedList, InsertLink, InsertImage. Use "|" for a separator. The admin tools (InsertPageLink, InsertMedia, InsertBlock) are always appended automatically.

Template

The file site/template.php is the main HTML template. It receives three variables:

  • $site — the Site object
  • $page — the Page object
  • $request — the Request object

Call $page->render($request) to render the page content and $page->getConfig() to access the YAML front matter.

Documentation

Page

Folder: /site/pages

A Page can be a flat Markdown file, can contain Blocks or also can be a PHP file. PHP pages receive the same variables as the template: $site, $page, and $request.

Pages are auto-routed on web-requests:

  • index.md or index.php will be shown on requesting /
  • NAME.md or NAME.php will be shown on requesting /NAME
  • FOLDER/index.md (or .php) will be shown on requesting /FOLDER
  • FOLDER/NAME.md (or .php) will be shown on requesting /FOLDER/NAME
  • 404.md (or .php) will be used as a custom 404 error page

Example for a Markdown Page with Blocks:

This Page contains 3 Block types, "hero", "text-image" and "three-columns". It will render to this:

A rendered page

Blocks can be configured in the block comment. With this configuration, the text-image block allows to display the image to the left side in desktop view.

Markdown files without blocks will render to a flat Markdown page like in every other flat file CMS.

You can define metadata for the page on top of the file in YAML Front Matter syntax.

Block

Folder: /site/blocks

A Block describes how a block is rendered. Blocks are written in PHP.

The code for the "text-image" Block which was used in the page above, looks like this:

Elements in the markdown are queried and used as values for the block. The query syntax is Xpath with the addition of the part(n) function.

Use $block->content() to get the full block content as rendered HTML (without XPath querying). This is useful for simple blocks like "text":

Schema validation

$block->xpath() accepts an optional second parameter — an array of props for validation:

Prop Type Description
required bool Field must match at least once
description string Human-readable name, shown in validation warnings
min int Minimum number of matches required (for lists)
max int Maximum number of matches allowed (for lists)

When a required field is missing or a minimum count is not met, the CMS logs an error and — in debug mode (logLevel: 0) — shows a warning banner on the page and a toast with the expected markdown structure in the admin editor.

Example — the "hero" block with validation:

For list fields (like the "cards" block), use min to require a minimum number of matches:

Admin interface

You find the admin interface at /admin.

If no users exist yet (e.g. on a fresh installation), the admin interface will automatically show a setup page where you can create the first admin account. After that, you can log in with the credentials you created.

In the admin interface you can edit markdown pages with a live preview, manage media files, set the site configuration, manage users and roles, and update the CMS.

Edit a page

The "Pages" section lists all markdown pages in your site. Click on a page name to open it in the editor. Pages are organized in a tree structure reflecting the folder hierarchy in site/pages/.

A live preview panel can be toggled to see the rendered page side-by-side with the editor (available on screens lg and wider). The preview updates automatically as you type.

The editor tracks page history — every save creates a snapshot. You can view previous versions and restore them from the History dialog. The number of snapshots kept per page is configurable via history.maxVersions in local/config.yml.

Edit a page

Media

The "Media" section lets you manage files in the web/media/ directory. You can upload files, create folders, and delete files or empty folders. Media files are accessible at /media/ in the browser and can be referenced in your markdown pages.

Media

Site configuration

In the site configuration, you can store global values of the site, like the navigation structure or the content of header elements. The site configuration is written in YAML.

Site configuration

User management

The "Users" page in the admin interface allows you to manage accounts directly from the browser. You can:

  • Add users — create new accounts with a username, password, and role
  • Change passwords — update the password for any existing user
  • Change roles — switch a user between Admin and Editor roles
  • Delete users — remove accounts (you cannot delete your own account)

Admins have full access to all admin pages. Editors can only access the page editor and media manager.

Usernames may contain letters, numbers, and underscores (max 64 characters). Passwords must be at least 8 characters. Credentials are stored as APR1-MD5 hashes in local/.htpasswd, roles in local/roles.yml.

Users

You can also manage users via the command line:

Update

The "Update" page in the admin interface shows the currently installed version and checks for available updates from the GitHub repository.

You can switch between two branches:

  • distrib (stable) — versioned releases, compared by version number
  • main (unstable) — latest development commits, compared by commit SHA

When an update is available, you can apply it directly from the admin interface. The updater downloads the latest tarball and replaces core/, web/admin/, and vendor/. Your site content (site/), local configuration (local/), and entry point (web/index.php) are not affected.

It is recommended to make a backup of the project folder before updating.

Update

AddOns

In Reboot CMS you can extend the functionality of your site with AddOns. AddOns allow you to hook into the request lifecycle to add authentication, modify rendered content, inject headers, track analytics, or implement any custom logic.

Creating an AddOn

An AddOn is a PHP class that extends AddOn. Place your AddOn file in site/addons/ with the class name matching the file name.

Registering AddOns

Register your AddOns in site/config.yml. They are loaded and executed in the order listed:

Available Properties

Inside your AddOn, you have access to:

  • $this->reboot — the Reboot instance (base paths, config, redirects)
  • $this->site — the Site instance (site config, paths, other addons)

Lifecycle Hooks

init(): void

Called once after construction of the AddOn. Use this to initialize data, read configurations, or start sessions.

preRender(Request $request): bool

Called on every request before rendering the page. Use it to:

  • Control access — check authentication and redirect unauthorized users
  • Modify request handling — perform redirects based on request path or parameters

Return true to continue rendering the page, or false to stop (e.g. after calling $this->reboot->redirect()).

postRender(Request $request, string $content): string

Called after the page is rendered, before the output is sent to the browser. Use it to:

  • Modify HTML output — inject scripts, stylesheets, or meta tags
  • Add tracking — append analytics snippets
  • Transform content — search and replace patterns in the rendered HTML

Returns the (possibly modified) content string.

Accessing AddOns from Pages

You can access a registered AddOn from any page template using:

Examples

See the included ExampleAddOn.php for a basic implementation. The admin interface itself uses AddOns: Authentication for login session handling and Admin for admin-specific functionality.