A small web server written in Go that builds HTML pages from YAML and Markdown definitions — no template language, no build step. Virtual hosting, automatic HTTPS, server-side scripts (Python, JavaScript, PHP, Shell), reverse proxying, and rate limiting are all built in.
Website / live docs: bserver.info
You need Go 1.24+.
git clone https://github.com/stgnet/bserver.git
cd bserver
go build
./bserver
Open the URL it logs at startup (port 80 if available, otherwise
8000-8099). You'll land on the bundled documentation site — which is
itself a bserver site living in www/default/.
mkdir www/example.com
# www/example.com/index.yaml
main:
- h1: "Hello World"
- p: "Welcome to my site."
That's it. Visit the site and bserver wraps your main: content in a
full HTML document with navigation, footer, Bootstrap 5 styling, and an
auto-generated favicon. Everything outside of main: was inherited from
the shared YAML in www/; override any of it by dropping a same-named
file into your vhost directory.
sudo ./install-service.sh # install + start (systemd or launchd)
sudo ./install-service.sh restart # after `git pull && go build`
sudo ./install-service.sh remove # uninstall
Every page is assembled by following a tree of named references starting
at html:
html.yaml ← <html lang="en"> wrapping head + body
├── head.yaml ← <head> with meta, title, styles
└── body.yaml ← <body> wrapping:
├── header.yaml ← navbar
├── main ← YOUR CONTENT (from index.yaml or .md)
└── footer.yaml ← footer
When bserver sees a name like header, it looks for header.yaml
starting in the request's directory and walking up — so site-specific
files win, shared definitions in www/ are inherited. YAML files are
re-read on every request (with a render cache invalidated by fsnotify),
so there's no restart cycle.
Four prefixes govern every YAML key:
main: # plain key — content
- h1: "Hi"
^card: # ^ — format definition (how a name renders as HTML)
tag: div
params: { class: card }
+headlink: # + — merge into an existing definition
- { rel: stylesheet, href: /extra.css }
$navlinks: # $ — data source (script that produces the value)
script: javascript
code: |
print(JSON.stringify([{key: "/", value: "Home"}]));
Everything else — components, layouts, the navbar, error pages, scripts, proxy mode — composes from these four pieces.
^name) — reusable HTML templates with
variable substitution$name) — script-backed content with JSON output.php filesdefault/ fallback,
symlink aliases.local / .test / .internalindex.yaml turns a vhost into a
proxy (with SSRF guards and optional API-key gating)_favicon.yaml customization?debug emits HTML-comment traces of name resolutionOnce the server is running, the full documentation site is available at
/:
^ system$ systemApache 2.0 — see LICENSE.