We needed to create an internal knowledge base, preferably based on a wiki-engine. The requirements were:

  • in-house hosting
  • simple maintenance
  • no vendor-lock - ideally, storing articles as plain-text files
  • customization and styling
  • not overloaded with gigabytes of fancy JS-frameworks
  • version control
  • Markdown markup

From my own researching and evaluating, there are very few wikis that meet all the requirements, and out of those Gollum seems to be the best.

Gollum wiki (original picture: https://www.deviantart.com/aronimo717/art/Hobbit-Gollum-431742580)

Even though it has its own installation guide, for me that wasn’t enough, so here are my guides for Linux and Mac OS, plus some customizing and tweaking.

At first, before discovering Gollum, I actually decided to create my own wiki-engine, as I didn’t like any of the wikis I found by that moment, and even started prototyping it with .NET Core Blazor (server-side variant). But then I took a closer look at Gollum and abandoned the idea.

Gollum has it all:

  • no mandatory “cloud”, host it anywhere you want, even locally
  • very simple maintenance, especially comparing to Confluence, Redmine, MediaWiki and similar ones that require a database
  • articles source is plain-text files, so you own your knowledge base and free to migrate to something else
  • good customization, including custom CSS and JS
  • version control is in its nature, as content lives in a Git repository
  • Markdown (and additional markups)

By the way, Gollum is what is running wikis on GitHub and GitLab, so you can actually clone wikis from there and run them locally on your machine.

Installation

Linux

The goal is to run Gollum behind NGINX as a reverse proxy, available at http://wiki.your.host.

Packages

Install required packages:

$ sudo apt install ruby ruby-dev make zlib1g-dev libicu-dev build-essential git cmake
$ sudo apt install zlib1g zlib1g-dev libicu-dev
$ sudo apt install pkg-config
$ sudo apt install libssl-dev

and then Gollum gem itself:

$ sudo gem install gollum

User and repository

Create a user to run the wiki from:

$ sudo adduser --shell /bin/bash --gecos 'Gollum application' gollum

Login as this user and create the wiki folder, initialize the Git repository and set the default commits author:

$ sudo --login --user gollum
$ mkdir wiki
$ cd wiki
$ git init --bare .
$ git config user.name "birdperson"
$ git config user.email "birdperson@your.host"
$ exit

Note the --bare option - it is required for users to be able to use this repository as a remote for their local cloned repository, so they could push their commits to it.

Templates

Gollum uses Mustache system for templating. If you’d like to customize default wiki layouts by modifying Gollum’s base templates, don’t edit the default ones - make a copy and work with the copies instead:

$ mkdir -p /usr/local/share/gollum/templates
$ cp -r /var/lib/gems/2.7.0/gems/gollum-VERSION/lib/gollum/templates/* /usr/local/share/gollum/templates/
$ sudo chown -R gollum:gollum /usr/local/share/gollum

You’ll also need to set this path in the config.

Config

Create the wiki config:

$ sudo mkdir -p /etc/gollum
$ sudo nano /etc/gollum/config.rb
# define the wiki options
wiki_options = {
  :h1_title => false,
  :user_icons => 'gravatar',
  :live_preview => false,
  :allow_uploads => true,
  :per_page_uploads => true,
  :allow_editing => true,
  :css => true,
  :js => true,
  :mathjax => true,
  :emoji => true,
  :show_all => true,
  :template_dir => '/usr/local/share/gollum/templates' # if you have custom templates
}

# pass wiki options to the Gollum app
Precious::App.set(:wiki_options, wiki_options)

# if present, undefine the :FORMAT_NAMES constant to avoid the
# "already initialized constant FORMAT_NAMES" warning
Gollum::Page.send :remove_const, :FORMAT_NAMES if defined? Gollum::Page::FORMAT_NAMES
# redefine the :FORMAT_NAMES constant to limit the available
# formats on the editor to only markdown
Gollum::Page::FORMAT_NAMES = { :markdown => "Markdown" }

systemd

Create a systemd service:

$ sudo nano /etc/systemd/system/gollum.service
[Unit]
Description=Gollum wiki
After=network.target

[Service]
Type=simple
User=gollum
Group=gollum
WorkingDirectory=/home/gollum/wiki
ExecStart=/usr/local/bin/gollum --config "/etc/gollum/config.rb" --host localhost
Restart=on-abort

[Install]
WantedBy=multi-user.target

Why localhost? You guessed it right - because we’ll be running it behind a proper reverse-proxy, such as NGINX, so we don’t want Gollum to expose its port to the network.

$ sudo systemctl enable gollum.service
$ sudo systemctl start gollum.service

Verify that it’s bound to 127.0.0.1:

$ sudo ss -lntup

...
tcp    LISTEN  0       4096          127.0.0.1:4567          0.0.0.0:*      users:(("gollum",pid=33932,fd=5))
...

You can also try to open http://your.host:4567 - it should fail.

NGINX

Install and setup NGINX as a reverse proxy:

$ sudo apt install nginx
$ sudo rm /etc/nginx/sites-enabled/default
$ sudo nano /etc/nginx/sites-available/wiki.your.host
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name _;

        location / {
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Scheme $scheme;
                proxy_redirect off;
                proxy_pass http://localhost:4567;
        }
}
$ sudo ln -s /etc/nginx/sites-available/wiki.your.host /etc/nginx/sites-enabled/
$ sudo systemctl restart nginx.service

Now your wiki should be available at http://wiki.your.host. Obviously, first you’d need to add a record for wiki.your.host in your local DNS server or at your hoster control panel (assuming you already have your.host domain registered).

In our case we host wiki in the internal network only, so it’s not exposed to the internet, and there is no real need to restrict access to it. However, in your case you might want to protect it with Basic authentication.

Mac OS

Here the goal is to simply run Gollum locally on demand - to preview your local changes before pushing them to the main repository on server.

Install required packages:

$ brew install icu4c
$ brew install pkg-config
$ brew install ruby

Since Mac OS already has system Ruby, you’ll need to “overwrite” it in your ~/.bash_profile:

export PATH="/usr/local/opt/ruby/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/ruby/lib"
export CPPFLAGS="-I/usr/local/opt/ruby/include"
export PKG_CONFIG_PATH="/usr/local/opt/ruby/lib/pkgconfig"

Update the environment:

$ source ~/.bash_profile

and check the versions:

$ ruby --version
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]

$ gem --version
3.2.3

Try to install Gollum now. In my case it failed:

$ gem install gollum

Building native extensions. This could take a while...
ERROR:  Error installing gollum:
    ERROR: Failed to build gem native extension.

    current directory: /usr/local/lib/ruby/gems/3.0.0/gems/ffi-1.14.2/ext/ffi_c
/usr/local/opt/ruby/bin/ruby -I /usr/local/Cellar/ruby/3.0.0_1/lib/ruby/3.0.0 -r ./siteconf20210104-30597-m0yzw0.rb extconf.rb
checking for ffi_prep_closure_loc() in -lffi... yes
checking for ffi_prep_cif_var()... yes
checking for ffi_raw_call()... yes
checking for ffi_prep_raw_closure()... yes
creating extconf.h
creating Makefile

current directory: /usr/local/lib/ruby/gems/3.0.0/gems/ffi-1.14.2/ext/ffi_c
make "DESTDIR=" clean

current directory: /usr/local/lib/ruby/gems/3.0.0/gems/ffi-1.14.2/ext/ffi_c
make "DESTDIR="
compiling AbstractMemory.c
compiling ArrayType.c
compiling Buffer.c
compiling Call.c
compiling ClosurePool.c
compiling DynamicLibrary.c
compiling Function.c
Function.c:847:17: error: implicit declaration of function 'ffi_prep_closure_loc' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    ffiStatus = ffi_prep_closure_loc(closure->pcl, &fnInfo->ffi_cif, callback_invoke, closure, code);
                ^
Function.c:847:17: note: did you mean 'ffi_prep_closure'?
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/ffi/ffi.h:269:1: note: 'ffi_prep_closure' declared here
ffi_prep_closure(
^
1 error generated.
make: *** [Function.o] Error 1

make failed, exit code 2

Here this error is caused by the obsolete libffi library. To fix it, force the required gem, and this time Gollum should install fine:

$ gem install ffi -- --disable-system-libffi
$ gem install gollum

Make a symlink for Gollum executable somewhere in your PATH, for example:

$ ln -s /usr/local/lib/ruby/gems/3.0.0/gems/gollum-VERSION/bin/gollum /usr/local/bin/

Now do the steps described in local editing and try to run your wiki. It might fail with the following error:

$ cd /path/to/the/clonned/wiki/repository
$ gollum --config config.rb --host localhost
/usr/local/lib/ruby/gems/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb:1755:in `detect_rack_handler': Server handler (thin,puma,reel,HTTP,webrick) not found. (RuntimeError)
    from /usr/local/lib/ruby/gems/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb:1493:in `run!'
    from /Users/YOURNAME/bin/gollum:286:in `<main>'

That means that you have no web-server in your Ruby. Install some, for example webrick, and then you’ll be able to run the wiki:

$ gem install webrick

$ gollum --config config.rb --host localhost
[2021-01-04 16:40:58] INFO  WEBrick 1.7.0
[2021-01-04 16:40:58] INFO  ruby 3.0.0 (2020-12-25) [x86_64-darwin19]
== Sinatra (v2.1.0) has taken the stage on 4567 for production with backup from WEBrick
[2021-01-04 16:40:58] INFO  WEBrick::HTTPServer#start: pid=38628 port=4567

The wiki is now available on http://localhost:4567.

Editing

Web UI

Gollum has a web UI for editing, and that would be the easiest option in most cases.

Sadly, there is no authentication out of the box, which is a minor issue in our case, but for others this could be a serious disadvantage. Although, it seems to be possible to hack it in.

So, by default all the changes made via web UI will be authored by the default user from Git repository config on server.

Local editing

But why edit wiki in web UI, when its content is just plain-text Markdown files in a Git repository? You can work with it as with any other Git repository!

So, every team member can have a local copy of the wiki, author (and sign) their commits and push them to the main repository via SSH. You can even disable editing via web UI, so Git and SSH would be the only way to edit the wiki. How awesome is that.

Establish SSH connection to the wiki host

Create an SSH key on your machine:

$ cd ~/.ssh
$ ssh-keygen -o -t rsa -b 4096 -C "your-name@your.host"

Add the wiki host to your SSH config (~/.ssh/config):

Host wiki.your.host
HostName wiki.your.host
User gollum
IdentityFile ~/.ssh/NAME-OF-THE-PRIVATE-KEY-FILE-YOU-JUST-CREATED

Go the wiki host and add your public key to /home/gollum/.ssh/authorized_keys.

Clone the wiki repository

Now you should be able to clone the wiki repository via SSH. On your local machine go to some /path/to/your/documents/or/whatever and clone the wiki like this:

$ git clone gollum@wiki.your.host:wiki/.git wiki.your.host

Make sure that you have meaningful username and e-mail in your Git config (these values will be used for authoring your changes in the wiki):

$ cd wiki.your.host
$ git config user.name
$ git config user.email

The rest is as with any other Git repository: you do some changes, commit them and push to remote.

Run Gollum

To run Gollum locally, first install it on your machine, create a config in the root of the wiki repository that you’ve just cloned (no need to commit the local config, and actually add it to .gitignore) and then:

$ cd /path/to/wiki.your.host
$ gollum --config config.rb --host localhost

Now you can open http://localhost:4567 in your browser. Note that it will only render what’s already committed, so if you don’t see changes you’ve made, check if you’ve committed them.

The main purpose of running Gollum locally is to preview your changes and amend local commits before pushing to remote. For example, you’ve committed some changes (did not push them yet), previewed them in browser and decided to do some more changes. To preview new changes you’ll need to commit them too, but instead of making a new commit you can just do this:

$ git add . && git commit --amend --no-edit

That will update your last commit (--amend), preserving the original commit message (--no-edit). You can amend your commit countless number of times and push it to the main repository only when you are completely satisfied with the changes.

Customization

As already mentioned, you can customize default wiki layouts by editing Gollum templates.

CSS and JS

Aside from templates, you can also add your customs CSS and JS. To enable those, make sure your wiki config has the following lines:

...
:css => true,
:js => true,
...

Then create custom.css and custom.js files in the wiki root. Now you can either write your custom CSS and JS right there, or use them as “importing points” - for example here’s my custom.css:

@import url("site.css");
@import url("site-tablet.css");
@import url("site-phone.css");
@import url("homepage.css");

and then I do the actual styling in those files.

By the way, even though the pages markup is Markdown, you can just as well use raw HTML blocks. And you can also assign CSS classes to Markdown elements, such as images:

![](/files/some-image.png){:class="some-css-class"}

As an example, our main page is mostly done with raw HTML. And thanks to injected custom styles, it nicely adapts to mobile screens:

Gollum wiki, main page

Also, default Gollum styles define some rather ugly margins for ToC, headers, paragraphs and so on, but you can easily customize that into something nicer like this:

Gollum wiki, article

Note that by default both custom.css and custom.js are included in the <head>. If you would like to move your JS code to the end of <body>, you can do it by modifying the following template: /path/to/gems/gollum-VERSION/lib/gollum/templates/layout.mustache (or rather a copy of it that you made earlier).

But before starting to customize the hell out of default styling, make sure that you have the latest Gollum version. In our case we were on the latest version, but since the moment we did our customization for adaptive layout there were a couple of new Gollum versions released, and there default styling was already addressing that very same thing out of the box, so our effort turned out to be a bit of a waste. Perhaps we should’ve submitted our changes to the Gollum repository.

There are certain special files (subpages) that get injected into pages - you can guess where exactly on a page by looking at their names:

  • _Header.md
  • _Sidebar.md
  • _Footer.md

You can use them for injecting some common blocks, such as table of contents (ToC). Here’s my _Header.md, for instance:

[[_TOC_]]

These blocks affect all the pages in the current and nested folders, unless they are “overwritten” on lower levels. For example, I have an archive folder with its own _Header.md:

├── _Header.md
├── some-article.md
├── archive
   ├── _Header.md
   ├── some-old-article.md
   ├── some-other-old-article.md
...

and it has different contents:

![](/files/archived.png){:class="archived-banner"}

[[_TOC_]]

so, aside from ToC, all the pages in the archive folder (and nested folders) will also have a special banner.

A bit about features

Gollum has quite a number of features, and I won’t describe all of them, but I would like to highlight some, as they are easy to overlook:

  • RSS feed - available at http://wiki.your.host/gollum/feed/ (note the trailing slash)
  • TeX math equations via MathJax
  • YAML frontmatter - much like in Jekyll or Octopress. You can use it to set the page title (and other metadata)
  • Overview - a service page that allows you to navigate the wiki directory tree. Available at http://wiki.your.host/gollum/overview
  • Macros (full list is here), including custom macros
    • Global ToC - you can add <<GlobalTOC()>> macros to the main page and that will generate a list of all the wiki pages (unlike Overview, this will list only content pages)