A simple self-hosted markdown flat files blog
What is Smallblog
The main goal of this project is to show how easily you can develop a flat file blog with markdown as the primary writing language. It's not perfect, it will never be, some people are already doing great things based on that idea, like Hugo for instance.
Smallblog is a quick project. The goal is to take some markdown files with front matter headers (written in yaml), parse them, render them and store the resulting HTML in memory. Which means, the more markdown files you have, the more memory smallblog will consume. It can also generate a static website, but that's not as fun.
- Filesystem monitoring : Drop a new file or modify a file, bam, your blog is updated
- Automatic syntax highlighting using bfchroma (which uses chroma under the hood)
- No CGO dependencies
- Tag system
- Simple and customizable template and CSS for easy reading
- Comments using gitalk
- Supports global assets for all your articles
- Can generate a static site :
- Tags won't work
- Raw markdown won't work
- Can't test without a proper web server like Caddy or Nginx
First of all you'll need a
pages directory where you'll store all your
articles, so let's create that.
$ mkdir pages
Without configuration, smallblog will try to find a
pages/ directory in your
current working directory. So let's create your very first article, and for that
we'll be using the
new command :
$ mkdir pages $ smallblog new first-article --title "My very first Smallblog article" --draft INFO Successfully generated new article file=pages/first-article.md
This commands takes a single argument : The name of the file this command will
write. It will automatically append the
.md suffix if you don't specify it
and will place it in the configured (or default)
pages directory. Also we're
specifying that this article is a draft. Drafts can be accessed directly using
the slug of the article, or on the
/drafts endpoint. Alternatively you can
start the server with
blog.draft set to true, which will list draft articles
on the homepage.
To check if this is working, simply run the following command :
$ smallblog serve --blog.draft INFO Generated files files=1 took="201.207µs" INFO Starting server host=127.0.0.1 port=8080
That's it, you successfully generated and served your first article.
You can add a
conf.json in your working directory to make your
configuration persistent. You may have noticed the warning about the
configuration file that wasn't found earlier. Here is an example
server: host: 127.0.0.1 port: 8006 debug: true analytics: enabled: true tag: xx-xxxxx-xxx blog: title: Depado's Blog description: A simple blog from a developer who does things. Powered by smallblog. pages: pages/ draft: true author: name: Depado github: Depado twitter: Depado_ site: depado.eu avatar: /assets/avatar.jpg gitalk: enabled: false client_id: xxxx client_secret: xxx repo: articles owner: Depado admins: [Depado] log: format: text level: info line: true
Explanations of these fields will follow. Just note that all these values
can be customized using command line flags which have a higher priority than
the configuration file. For example you might want to turn on the
of the server without changing your configuration file. In which case you can
just pass the flag
--server.debug when starting smallblog.
Server related configuration. Defines on which host/port the server should listen as well as debug mode.
||Host on which the server should listen||"127.0.0.1"|
||Port on which the server should listen||8080|
||Enable debug mode for the router||false|
debug value is especially useful if you modify the HTML templates of
smallblog since you won't need a restart of the service to see your changes
General blog configuration such as the blog title, description, pages directory and code highlighting style.
||Title of your blog||-|
||Description of your blog||-|
||Directory where your articles are stored||"pages/"|
||Style of the syntax highlighting||"monokai"|
||Display articles that are marked as draft||false|
||Name or username of the author||-|
||Github handle of the author||-|
|Twitter handle of the author||-|
||Website of the author||-|
In this section you can customize the global author. If you fill this, smallblog will know that every article that doesn't have author information was written by this author. This will also be displayed on the front page (article list).
Configuration for Google Analytics. Other types or platforms will be supported but for now only GA can be enabled.
||Whether or not the Google Analytics feature is enabled||-|
||Google Analytics tag to use||-|
Please see the documentation of gitalk to see how you can configure gitalk for smallblog.
||Log format, either "text" or "json"||"text"|
||Defines the minimum level of logging that is displayed. One of "debug", "info", "warn", "error" or "fatal"||"info"|
||Show where the log happened in the source code (filename, line number)||false|
There is no naming convention for file names. You can name them whatever you want, it won't change the server's behavior. A post (or page/article) file is divided in two parts. The first part is yaml data. The second part is the actual content of your article. The two parts are separated by a blank line.
Here is the list of yaml values you can fill
||The title of your article.||Yes|
||The date of writing/publication of your article.||Yes|
||The description of your article (sub-title)||No|
||The description of your article (sub-title)||No|
||The link you want for your article. If left empty, will be generated from title.||No|
||URL of the banner (image at the top level of your article)||No|
||An author object (as seen earlier) that overrides the global configured author||No|
||A list of tags you want to apply on the article (useless right now, but still pretty)||No|
If any of the two mandatory values (
title) are omitted, the parser
will complain, output a log, and simply ignore the file.
Note that the slug of the post will be automatically generated from the
post's title if it is omitted.
title: "Example article !" description: "This article is just an example." banner: "" author: name: Depado twitter: Depado_ site: depado.eu github: Depado avatar: "//blog.depado.eu/assets/avatar.jpg" slug: example-article tags: [go,dev,example,hello] date: "2018-04-03 13:28:13" draft: false # Actual Markdown Content Notice the blank line right after the `draft` section. That's how you tell the parser that you are done with yaml format.
This article will be parsed, and available at
It will also be listed at
The directory you define in your
conf.yml file is constantly watched by the
server. Which means several things :
- If you create a new file, it will be parsed and added to your site.
(Also if you
mva file inside the directory)
- If you modify an existing file, it will be parsed and modified.
- If you delete an existing file, the article will be removed. (Also if you
mva file out of the directory)
All these changes are instant. Usually a file takes ~250µs to be parsed. When you restart the server, all the files will be parsed again so they are stored in RAM (which is really efficient unless you have 250MB of markdown file).