Migrating from Dokuwiki to Gollum
Intro
Last year at $job
, I joined another sysadmin team. This team used dokuwiki for writing documentations.
I am not a fan of wiki system, because I am writing most of my documentations in markdown and, then, I am generating static html files using gitbook
or mkdocs
.
All my docs are versioned with git, so I am able to search history of a file.
Main problem here is not to use git or not (that is required), but:
- people who like wiki won't use any other system, and they are accustomed to a wysiwyg system,
- people (like me) who like to manage their documentation in markdown won't use any wiki format, and usually do not like wysiwyg.
So, what do we do now ?
There are many options, but the 1st choice should be to use a modern wiki system that handle correctly markdown format and permit flat file storage that can be used with a git backend.
I discovered some wiki systems that tackle correctly those points:
gitit
(but that is written in haskell),gollum
(but that is written in ruby),wikijs
(but it is a nodejs application).
According to Github
, wikijs
is the most popular wiki of that 3 ones. After some tests, it was a well designed application, and fulfills almost all of our requirements. Dockuwiki
to wikijs
is possible with this project. Moreover it is already present in the roadmap for the future versions 3.X. See this post for more informations about it. So, I think it is possible to get a nice wiki up after some work on pages and changing the links to new medias paths, specially in future releases of wikijs
.
I also tested gollum
, which was our second choice. Less popular than wikijs
but most than gitit
. Please also consider that gitit
LDAP provisionning seems to be experimental: it is present in this commit but it was for a previous release.
I thought for a long time that Gollum
won't satisfy our needs, which requires at least LDAP authentication and the management of user permissions on pages.
However, I found some interesting projects around gollum
, including omnigollum
based on ruby omniauth
library. Gollum
looks like a classic nice wiki. IMHO, it is prettier than dokuwiki
, even if there is not much differences.
Gollum installation
I found some really interesting readings on Internet for this purpose. Here are 2 articles quite useful IMHO:
- https://davidplanella.org/gollum-wiki-installation/,
- https://decovar.dev/blog/2021/01/07/gollum-markdown-wiki/.
That being said, bellow are the steps I did to install my gollum instance (ubuntu 20.04
):
# from my history
sudo apt update
# basic packages
sudo apt install -y sudo vim gnupg curl build-essential git make cmake zlib1g-dev libicu-dev libidn11-dev pkg-config libssl-dev openssl
sudo apt install -y python-docutils python3-docutils
sudo apt install -y ruby-full ruby-dev asciidoc
sudo gem install omniauth -v 1.8.1
sudo gem install gollum org-ruby omnigollum github-markup wikicloth RedCloth github-markdown asciidoctor bundle gollum-auth omniauth-ldap
sudo adduser --shell /bin/bash --gecos 'Gollum application' gollum
Then, as the Gollum user:
su - gollum
git config --global user.name "gollum user"
git config --global user.email "<user>@<domain>"
mkdir wiki && cd wiki
# First we need to create the repository on github/gitlab/...
# Then, we need to add this public key to a user [1] in github/gitlab to allow remote SSH push
# [1] a service account would be a better option.
ssh-keygen -o -t rsa -b 4096 -C "gollum@gollum"
cat /home/gollum/.ssh/id_rsa.pub
git init .
# creating some hooks...
cat<<EOF |tee ~gollum/wiki/.git/hooks/post-commit
#!/usr/bin/env bash
git push origin main
DATE=$(date +"%Y%m%d at %HH%M")
echo -e "${DATE}\nUpdating repository..." >> /var/log/gollum_commit.log
exit
EOF
cat<<EOF |tee ~gollum/wiki/.git/hooks/init
#!/usr/bin/env bash
git pull origin main
exit
EOF
# some verifications
gollum --versions
gem list
ssh -T git@<repository server>
exit
Back to our sudoer user:
chsh -s /usr/bin/git-shell gollum
# creating basic Gollum files
sudo mkdir /etc/gollum
# basic configuration
sudo cp /var/lib/gems/2.7.0/gems/gollum-5.2.3/config.rb /etc/gollum/config.rb
cat<<EOF | sudo tee /etc/systemd/system/gollum.service
[Unit]
Description=Gollum wiki server
After=network.target
After=syslog.target
[Service]
Type=simple
User=gollum
Group=gollum
WorkingDirectory=/home/gollum/wiki/
ExecStart=/usr/local/bin/gollum --live-preview --config "/etc/gollum/config.rb"
Restart=on-abort
[Install]
WantedBy=multi-user.target
EOF
# Testing gollum binary
which gollum
# checking gollum user
getent passwd gollum
gollum /home/gollum/wiki
ss -tunelp | grep 4567
# testing service
sudo systemctl daemon-reload
sudo service start gollum
# checking logs
sudo journalctl -xn150 -f -u gollum.service
Configuring Gollum
Now, we need to modify the config.rb
file to fit our needs (LDAP with authorized users, addressing hooks, and adding valid formats for editing):
# Example gollum config with omnigollum authentication
# gollum ../wiki --config config.rb
#
# or run from source with
#
# bundle exec bin/gollum ../wiki/ --config config.rb
# Remove const to avoid
# warning: already initialized constant FORMAT_NAMES
#
# only remove if it's defined.
# constant Gollum::Page::FORMAT_NAMES not defined (NameError)
Gollum::Page.send :remove_const, :FORMAT_NAMES if defined? Gollum::Page::FORMAT_NAMES
# limit to one format
Gollum::Page::FORMAT_NAMES = {:markdown => "Markdown", :rest => "reStructuredText", :asciidoc => "AsciiDoc", :mediawiki => "MediaWiki", :textile => "Textile"}
=begin
Valid formats are:
{ :markdown => "Markdown",
:textile => "Textile",
:rdoc => "RDoc",
:org => "Org-mode",
:creole => "Creole",
:rest => "reStructuredText",
:asciidoc => "AsciiDoc",
:mediawiki => "MediaWiki",
:pod => "Pod" }
=end
# Specify the path to the Wiki.
gollum_path = '/home/gollum/wiki'
Precious::App.set(:gollum_path, gollum_path)
# Specify the wiki options.
wiki_options = {
:ref => "main",
:live_preview => false,
:allow_uploads => true,
:allow_editing => true,
:css => false,
:js => false,
:emoji => true,
:show_all => true,
:h1_title => true,
:user_icons => 'gravatar',
:per_page_uploads => true
}
Precious::App.set(:wiki_options, wiki_options)
# Set as Sinatra environment as production (no stack traces)
Precious::App.set(:environment, :production)
# Setup Omniauth via Omnigollum.
require 'omnigollum'
require 'omniauth-ldap'
# adding gon-sinatra to retrieve session info in js
require 'gon-sinatra'
options = {
# OmniAuth::Builder block is passed as a proc
:providers => Proc.new do
provider :ldap,
:title => 'Active Directory Login',
:host => 'IP.IP.IP.IP',
:port => 389,
:method => :plain,
:base => 'dc=domain,dc=tld',
:uid => 'sAMAccountName',
:bind_dn => 'admin@domain.tld',
:password => 's3cret'
end,
:dummy_auth => false,
# Make the wiki private under any private or editing page
# from https://github.com/arr2036/omnigollum/issues/45
:protected_routes => [
'/private/*',
'/private',
'/revert/*',
'/revert',
'/create/*',
'/create',
'/edit/*',
'/edit',
'/login/*',
'/login',
'/rename/*',
'/rename/',
'/upload/*',
'/upload/',
'/delete/*',
'/delete'
],
# Specify committer name as just the user name
:author_format => Proc.new { |user| user.name },
# Specify committer e-mail as just the user e-mail
:author_email => Proc.new { |user| user.email },
#:authorized_users => nil,
:authorized_users => ENV["OMNIGOLLUM_AUTHORIZED_USERS"].split(","),
}
# :omnigollum options *must* be set before the Omnigollum extension is registered
Precious::App.set(:omnigollum, options)
Precious::App.register Omnigollum::Sinatra
# hook for initialization
Gollum::Hook.register(:post_wiki_initialize, :hook_id) do |wiki|
system('/home/gollum/wiki/.git/hooks/init')
end
Gollum::Hook.unregister(:post_wiki_initialize, :hook_id)
# hook for web edition
Gollum::Hook.register(:post_commit, :hook_id) do |committer, sha1|
# system('/home/gollum/wiki/.git/hooks/post-commit')
system('git pull origin main')
system('git push origin main')
end
Now, I need to add the list of authorized user in a /etc/gollum/.env
file:
OMNIGOLLUM_AUTHORIZED_USERS=foo,bar,joe
After this, you need to tell your service file to source it. Add the following in the [Service]
section :
EnvironmentFile=/etc/gollum/.env
Then, we will modify gollum itself to aget a login and a logout button + a way to check permsissions when a action is done.
Here are the modifications I have done to do so (deeply inspired by this commit from the omnigollum author). Corresponding files are located in /var/lib/gems/2.7.0/gems/gollum-5.2.3/lib/gollum
.
After those modifications, restart gollum.
sudo systemctl daemon-reload
sudo systemctl restart gollum
Modifying Gollum to work with gitlab-ci
First, adjust your ssh config file for the gollum user in git:
cat ~gollum/.ssh/config
Host <Gitlab Server>
User <service account>
Hostname <Gitlab Server>
PreferredAuthentications publickey
IdentityFile ~gollum/.ssh/id_rsa
IdentitiesOnly yes
This section is specific to Gitlab users. We will follow gitlab install.
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner
SERVER=<gitlab server>
PORT=443
CERTIFICATE=/etc/gitlab-runner/certs/${SERVER}.crt
# Create the certificates hierarchy expected by gitlab
sudo mkdir -p $(dirname "$CERTIFICATE")
# Get the certificate in PEM format and store it
openssl s_client -connect ${SERVER}:${PORT} -showcerts </dev/null 2>/dev/null | sed -e '/-----BEGIN/,/-----END/!d' | sudo tee "$CERTIFICATE" >/dev/null
# Here, you need to register your runner first !
# https://docs.gitlab.com/runner/register/index.html
sudo gitlab-runner register --non-interactive --executor shell --tls-ca-file="$CERTIFICATE" --url "https://${SERVER}/" --registration-token "<your gitlab token>" --tag-list "gollum,wiki" --description "gollum wiki autodeploy" --locked="false"
My .gitlab-ci
looks like this:
stages:
- test
- deploy
# tag is needed to select the right gilab-runner
# https://www.bitslovers.com/gitlab-runner-tags/
test:
tags:
- gollum
script:
- whoami
- gollum --versions
deploy:
tags:
- gollum
timeout: 5 minutes
script:
- cd /home/gollum/wiki
- /usr/bin/git pull
- chown -R gollum:gollum /home/gollum/wiki
only: # Only run on main branch
variables:
- $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Nginx configuration
We need a fqdn
for this machine. Let's say you manage your DNS zone and that you can add a A record for our gollum machine "gollum.domain.tld".
sudo apt install -y nginx certbot
sudo mkdir -p /var/www/html/acme-challenge/
sudo chown www-data:www-data /var/www/html/acme-challenge
# for now, we comment all ssl sections
cat<<EOF |sudo tee /etc/nginx/sites-enabled/default
server {
listen 80 default_server;
#listen 443 ssl default_server;
root /var/www/html;
server_name gollum.domain.tld;
location / {
proxy_pass http://127.0.0.1:4567;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 150;
proxy_send_timeout 100;
proxy_read_timeout 100;
proxy_buffers 4 32k;
client_max_body_size 500m;
client_body_buffer_size 128k;
}
location ^~ /.well-known/acme-challenge/ {
root /var/www/html/acme-challenge/;
allow all;
default_type "text/plain";
}
#ssl_certificate /etc/letsencrypt/live/gollum.domain.tld/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/gollum.domain.tld/privkey.pem;
#ssl_session_timeout 5m;
#ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
#ssl_protocols TLSv1.2;
#ssl_prefer_server_ciphers on;
access_log /var/log/nginx/gollum.access.log;
error_log /var/log/nginx/gollum.error.log;
}
EOF
sudo nginx -t
sudo service nginx restart
sudo journalctl -xn150 -u nginx.service
Let's encrypt
I have done a Let's encrypt bash script some time ago. I will download it and execute it. It is mainly based upon certbot
.
sudo mkdir /root/crons/
sudo wget -O /root/crons/letsencrypt https://gist.githubusercontent.com/remyd1/35fdbcb740fa4fdec1a15727ad7e743c/raw/589cec3af3fed440fbb0d38c493cae2fd44440a0/letsencrypt.sh
sudo chmod u+x /root/crons/letsencrypt
sudo /root/crons/letsencrypt initial
Now we can uncomment ssl sections in /etc/nginx/sites-enabled/default
, then, restart the service.
sudo nginx -t
sudo service nginx restart
If it works, you can add a cron to manage let's encrypt certificates:
crontab -e
And add:
@weekly /root/crons/letsencrypt
Convert from dokuwiki
Now, that's the least attractive part. We need to convert each dokuwiki file to a markdown compatible format.
Let's retrieve the dokuwiki pages:
# fix / adapt permissions, then
scp -r user@dokuwiki:/path/to/dokuwiki/data/pages .
We will use the famous pandoc
software.
Here is how you can convert a single wiki file to markdown:
cd pages
pandoc -f dokuwiki -t markdown test.txt -o test.md
And to convert all of your files:
find . -type f -name "*.txt" -exec pandoc -f dokuwiki -t markdown {} -o {}.md \;
Then, we can copy all of this into gollum:
# creating back directory structure
find . -type d | xargs -I{} mkdir /path/to/gollum/{} 2>/dev/null
find . -type f -name "*.md" -exec cp {} /path/to/gollum/{}
Issues that need to be adressed
-
For now, even if you are not login, you can still go to overview, even from
/private
path. So, do not name your files with some confidential data. If you click on the files, then you have to authenticate. Anyway, if I think it is necessary, I will create a.htpasswd
file. Adding/overview/private
in the protected routes does not change anything. -
Considering the part I modified to manage permissions in
gollum
code itself, particularly inlib/gollum/app.rb
, another option would be to have two wiki running gollum:
-
one with
--no-edit
mode, -
another one in read/write.
The other options would be to use a CAS server or HTTP auth.
Main issue with a specific commit is to have a code up to date with the official
gollum
current code. PR is not an option as the main author does not want this kind of auth code in the core ofgollum
.
- Maybe I could try to track users who made some modification through the Gollum frontend in git with the right committer name, and not a system account. See here for more informations.
Other useful resources
Comparison of wiki systems:
Gollum
- official install guide: https://github.com/gollum/gollum/wiki/Installation,
- some basic install tutorials: https://ronnieroller.com/Gollum, https://www.rosehosting.com/blog/install-gollum-wiki-on-ubuntu/, https://computingforgeeks.com/how-to-install-gollum-wiki-on-ubuntu-18-04-lts/, https://lifuzu.com/blog/2014/08/22/install-gollum/,
- install with oauth: https://www.altenburger.io/posts/install_gollum/, https://www.altenburger.io/posts/oauth_apache/,
- another complicated but nice install: https://retifrav.github.io/blog/2021/01/07/gollum-markdown-wiki/
- managing gollum with vim: https://davidyat.es/2017/09/01/vimwiki-plus-gollum/,
- Issue on
omnigollum
about access to some paths: https://github.com/arr2036/omnigollum/issues/45.