One binary + directories
All logic lives in a single binary (~25 MB). The site is described by a few directories:
content/— Markdown files with TOML frontmatterbase/themes/{theme}/— Tera templates, SCSS and i18n of the active themebase/static/— user overlay: wins over the theme for static assets (CSS, JS, fonts, images)config.toml— configuration.env— OAuth keys
Themes are mandatory and switched via theme in config: all templates, styles and translations come only from the active theme, while the user base/static/ overrides the theme for other assets.
MVC layers
The code is organized into layers:
model/— data and domain logic (Page/Section/Taxonomy, Markdown parser, search, XML escaping)view/— view-model (build_*_context) and the Tera render engine (render_page,render_404)controller/— HTTP handlers (home, section, tags, search, rss, sitemap, auth)service/— AppState/SharedState, sessions, OAuth, static files, SQLite, SCSS, metricsrouter/andmiddleware/— routing and middleware layers (counter, ratelimit, security, timing)server/— startup orchestration: initialization split into independent subsystems (server/init/), TLS with four modes via dedicated modules (server/tls/)
Startup and hot reload
On startup the server reads the config, scans content/, compiles Tera templates and SCSS, and opens SQLite. Everything lives in memory. A watcher tracks changes in content/ and theme directories — the site updates without a rebuild.
Performance
A Rust server starts in milliseconds, uses minimal memory, and keeps all content in memory — no external services. SQLite (WAL, batched writes) is used for the page view counter, sessions, and login audit. Fully rendered HTML is cached (LRU) for logged-out visitors.