Light Sites is a Go-powered, no-JavaScript, template-friendly, lightweight markdown parser and server. It aims to combine Bootstrap CSS (and other customizable CSS if you choose) with Markdown with minimal configuration.

About the project

This was written as a coding project. I wanted to create a minimalistic server to parse markdown files and manipulate them according to some essential customizations. It’s more of reference code than an actual production-ready solution. For the purposes of a proper website deployment, I recommend Hugo.

Go itself also has templating capabilities built in that are more powerful than Light Sites, offering conditionals, looping, and more efficiencies and optimizations than I cared to put into Light Sites.

Static website generators are preferred over a live API. I did not architect this program to statically generate content, but I should have. Instead, it acts as a live web server that will require occasional CPU cycles on whatever system you’re running.


You can see a full example here:

At this time, I don’t provide a live version of the site because it requires uptime. The example screenshots below should be all you really need.


To deploy the example Light Sites repository, use a lean Docker compose file:

version: "3"
    container_name: light-sites-cmk-blog
    hostname: light-sites-cmk-blog
    image: light-sites:latest
      - ./cmk-blog/src:/src
      - ./cmk-blog/config.yml:/config.yml:ro
      - ""
    restart: unless-stopped
    user: "1000:1000"
      driver: "json-file"
        max-size: "200k"
        max-file: "10"


Here are a couple screenshots from the example deployment.

Landing page

The landing page is a markdown document found here:

Landing page

Blog post

This blog post page is a markdown document found here:

Blog post

Further reading

The remainder of this blog post is essentially a copy-paste of the documentation from the readme at Light Sites GitHub repo file.


Light Sites was created to bring together a few different niches into a single package:

  • No-JavaScript, inspired by:
    • The Tor Browser, and how JavaScript is used to violate privacy when browsing the web - we should be able to acquire all the information we need from a website without running JS
    • The
  • Lightweight, Go-based codebase
  • Docker-first deployment
  • Markdown-based static blog tool
  • HTML Template rendering engine
  • Slightly opinionated preference to a common responsiveBootstrap layout

Due to its youth, it only boasts a couple features, but simple templating is probably its most useful feature. See templating for more info.

Code unit test coverage is currently at 96.7% (for packages with code worth testing).


Simply create an file in ./src/content. The only requirement is that the markdown document requires the <attributes> tag to be defined with a title="Home" attribute (change as desired). Everything else can be normal markdown.

Continue to the deployment steps next.


You need:

  • GNU Make
  • Docker or Go 1.15

For Docker, run:

make build # make gobuild, if using Go
make run   # make gorun, if using Go

Finally, navigate to http://localhost:8099/index.html to view src/content/ in its rendered form.

*Note: If you change the configured listenAddr in config.yml, or want to change the port mapping in the docker run command, please update the Makefile accordingly.

To add new documents, ensure that the <attributes title="Hello World!"></attributes> tag is placed preferably at the top of your Markdown document.


Edit config.yml to meet your needs.

Special Tags/Behavior

There are a few custom HTML tags that are processed by the Light Sites rendering engine.

Special Behavior

Route Prefix, and index.html

If navigating to the root URL, i.e. http://localhost:8099/, Light Sites will act as if the user navigated to http://localhost:8099/index.html (the .html suffix will change depending on config.yml). If, in config.yml, routing.routePrefix is set to /content/, for example, then navigating to http://localhost:8099/content/ will yield the same result, but http://localhost:8099/ will yield 404.


Every 30 minutes (configurable), the documents are reloaded. This means that documents are served from memory for fastest performance, but are potentially outdated if a recent change was made.

Important Tags

Before spending a lot of time creating markdown files, take a look at the following tags and see if they are useful.

attributes Tag (Required)

The <attributes> tag must be placed in the first line of the document. Currently, the title attribute must be set or else the document may not function correctly. Example:

<attributes title="Hello World!"></attributes>

directory Tag

Use the <directory> tag to render links to all documents in the src/content directory as a <ul><li>...</li></ul> tree. To hide a document, prefix it with a ., such as src/content/ To visit a hidden page, visit http://localhost:8099/.page2.html. Traversing folders is supported. This behavior may change in the future.

To avoid issues and ensure smoothest functionality, ensure that your config.yml specifies directories.documents as src/content for example, and NOT as ./src/content.

template Tag

Templating is the most useful part of Light Sites. It allows you to reuse HTML elements and pass-in custom variables. Example:

<template file="alert.html" alert-text="Heads up!"></template>

And the contents of src/templates/alert.html are:

<div class="alert alert-primary">

{{alert-text}} wil render the text Heads up! when the static HTML document is produced.

Recursive/nested templating is currently not tested and likely does not work.

Behind the Scenes Tags

The following tags are all handled by the Light Sites engine, and do not require any interaction. Consider this a behavioral documentation section rather than actual instructions.

title Tag

The <title>Page Title</title> tag is created automatically and inserted into the <head> node. Its value is equivalent to whatever you specify for <attributes title="xyz">.

body Tag

When the <body> tag is encountered, its first child is given a parent of:

<main role="main">
    <div class="container">
        <div class="row">
            <div class="col-lg-12">

For example, if at first the HTML content looks like this…

        Some text

… it will become:

    <main role="main">
        <div class="container">
            <div class="row">
                <div class="col-lg-12">
                        Some text

It is worth noting that the markdown-to-HTML engine automatically produces a <body> tag, whose children are the rendered HTML contents of your markdown document. You don’t need to worry about this behavior at all, but it helps to understand how the markdown document is manipulated to the result that you see on screen.

head Tag

When encountered, the <head> tag is given a standard Bootstrap CSS import, using <link href="/assets/bootstrap.min.css> with a few other attributes. Additionally, it imports /assets/custom.css the same way. These are configurable in the config.yml.

table Tag

<table> tags are updated to use Bootstrap’s responsive table classes, as well as adding zebra striping and active mouse hover highlighting to row elements. Tables are always wrapped in a <div class="table-responsive"></div> element. Currently, this behavior is not configurable.

img Tag

All <img> tags should be given a max-width of 100%, as shown in the default config.yml. This is to prevent occasional issues where the image may not respect the width of the parent container(s).

Source code

View the source code here on GitHub.

Final note

Thanks for reading!