Heavy Watal

Gollum — MarkdownとGitで動くWikiエンジン

https://github.com/gollum/gollum

研究室内の連絡・情報共有は、フロー型の情報ならSlackで、ストック型の情報ならWikiで。 という方針になったので、学内ネットワークで閲覧編集可能な自前Wikiサーバーを立てる。 開発環境は macOS, 本番環境は Ubuntu 18.04 → 20.04 → 22.04 LTS.

ソフトウェア選定

pukiwiki
学生のときの研究室で使ってたので馴染み深い。 でも独自記法だしphpとか文字コードとか考えたくないので却下。
crowi
Node.js + MongoDB で動くモダンな Markdown wiki。
生のファイルが見えないデータベースっぽいので管理が難しそう。
growi はこれをフォークしたもので、 機能もドキュメントも強化されてるし、 docker-compose とかですぐ使えるのも楽ちん。
日本語の人しか使わなそう…?
gitit
pandoc + git で動くのでかなり手堅い感じ。
Haskell の勉強を兼ねていじくり回す時間があれば…
gollum
Ruby + git で動く Markdown wiki。
GitHubやGitLabのWikiにも採用されているのでコミュニティが大きそう。
自前サーバーを管理できる人が抜けても内部データを簡単に再利用可能。
Rubyはよく知らないけど理解しなくても雰囲気でいじれそう。
Hugo
静的ウェブサイトを作る用途には最高だけどWiki機能は無い。
Netlify CMS でWiki-likeなガワを取り付けることは可能だけど、 編集内容のpush先がGitHubとかになるので、 それを学内サーバーに即時反映させるのが難しい。

gollumインストールとWiki新規作成

  1. rbenvを設定してRubyを入れる。 MacならHomebrewでもいいけどLinuxではHomebrewを混ぜるとエラーになりがちなので避け、 管理者たちが出入りできるところに RBENV_ROOT を置く:

    sudo apt install autoconf patch build-essential rustc libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev
    export RBENV_ROOT=/home/local/.rbenv
    PATH="${PATH}:${RBENV_ROOT}/bin"
    git clone https://github.com/rbenv/rbenv.git $RBENV_ROOT
    git clone https://github.com/rbenv/ruby-build.git ${RBENV_ROOT}/plugins/ruby-build
    rbenv init
    eval "$(rbenv init -)"
    rbenv install -l
    rbenv install 3.3.5
    

    eval "$(rbenv init -)" はここでインストールした rubybundle にPATHを通すコマンド。 新しいシェルを起動するたびに実行する必要があるので .zshrc, .bashrc 等の設定ファイルに記述しておく。

    rbenv global 3.3.5 とするか、 次に作るWikiリポジトリ内で rbenv local 3.3.5 とすることで使用するRubyのバージョンを設定する。

  2. Wiki用のリポジトリ(ここではlabwiki)を作成して空コミット:

    git init labwiki
    cd labwiki/
    git commit --allow-empty -m ":beer: Create repository"
    
  3. Gemfile を作成してコミット:

    source 'https://rubygems.org'
    gem 'commonmarker'
    gem 'gollum'
    

    gollum本体をいろいろいじくる場合は自分のフォークを使う:

    gem 'gollum-rugged_adapter', :github => 'heavywatal/rugged_adapter', :branch => 'custom'
    gem 'gollum-lib', :github => 'heavywatal/gollum-lib', :branch => 'custom'
    gem 'gollum', :github => 'heavywatal/gollum', :branch => 'custom'
    

    開発環境ではローカルのクローンを使うように設定:

    SRCDIR=${HOME}/fork
    git clone https://github.com/heavywatal/gollum.git ${SRCDIR}/gollum -b custom
    git clone https://github.com/heavywatal/gollum-lib.git ${SRCDIR}/gollum-lib -b custom
    git clone https://github.com/heavywatal/rugged_adapter.git ${SRCDIR}/rugged_adapter -b custom
    bundle config local.gollum ${SRCDIR}/gollum
    bundle config local.gollum-lib ${SRCDIR}/gollum-lib
    bundle config local.gollum-rugged_adapter ${SRCDIR}/rugged_adapter
    
  4. bundle install で gollum 及び依存パッケージをまとめてインストール。 --local を付けてこのプロジェクト専用にしてもよい。

  5. bundle exec gollum でとりあえず走らせる。 手元のコンピュータなら http://localhost:4567 で確認。

設定

基本

config.rb を作成して bundle exec gollum -c config.rb のように指定して読ませる。

require 'gollum/app'

wiki_options = {
  allow_uploads: true,
  base_path: '/wiki',
  css: true,
  page_file_dir: 'source',
}
Precious::App.set(:wiki_options, wiki_options)

例えばこの場合、 ページのソースファイルはリポジトリのルートではなく source/ から読まれるようになる。

css: true により custom.css を読み込まれるようになるが、 残念ながらリポジトリルートではなく source/custom.css に置かなければならない。 また、ローカルファイルではなくコミット済みのものが読まれることに注意。

ポート番号なしでアクセスする

デフォルトでは http://example.com:4567 のように4567番ポートのルートで動く。 これを80番ポートの/wiki以下で動くように調整して http://example.com/wiki/ のようにアクセスできるようにする。

  1. Apacheの設定ファイルを新規作成:

    sudo vim /etc/apache2/sites-available/gollum-wiki.conf
    
    ProxyRequests Off
    <Proxy *>
      Order deny,allow
      Allow from all
    </Proxy>
    <Location /wiki>
      ProxyPass http://localhost:4567/wiki
      ProxyPassReverse http://localhost:4567/wiki
    </Location>
    
  2. その設定ファイルを有効化してApache再起動:

    sudo a2ensite gollum-wiki.conf
    sudo systemctl restart apache2
    
  3. bundle exec gollum で起動。

BASIC認証でやんわりパスワードをかける

config.rb にこんな感じで書くだけ:

module Precious
  class App < Sinatra::Base
    use Rack::Auth::Basic, 'Private Wiki' do |username, password|
      users = File.open(File.expand_path('users.json', __dir__)) do |file|
        JSON.parse(file.read, symbolize_names: true)
      end
      name = username.to_sym
      digested = Digest::SHA256.hexdigest(password)
      if users.key?(name) && digested == users[name][:password]
        Precious::App.set(:author, users[name])
      end
    end

    before do
      session['gollum.author'] = settings.author
    end
  end
end

session['gollum.author'] にハッシュを渡しておくとコミッターに反映してもらえる。 ユーザー情報は別ファイル(ここではusers.json)に分離しといたほうが見通しがいい。

{
  "user1": {
    "name": "First User",
    "email": "user1@example.com",
    "password": "0b14d501a594442a01c6859541bcb3e8164d183d32937b851835442f69d5c94e"
  },
  "user2": {
    "name": "Second User",
    "email": "user2@example.com",
    "password": "6cf615d5bcaac778352a8f1f3360d23f02f34ec182e259897fd6ce485d7870d4"
  }
}

もっとちゃんとした認証システムにしたほうがいいのかもしれないけど、 大学のファイアウォール内なのでとりあえずこれくらいで…

パスワードのハッシュ値は sha256sum <(pbpaste) とか echo -n 'greatpassword' | sha256sum のようなコマンドで計算できる。

Markdownパーサー/レンダラを変更する

https://github.com/gollum/gollum/wiki/Custom-rendering-gems

Markdownを読んでHTMLに変換するライブラリは github-markup を通して選択できるようになっている。 デフォルトでは kramdown が利用されるらしいが、 なるべくCommonMark/GFM準拠で高速なのが良いので、 commonmarker を使うことにする。 例によって config.rb に追記:

module Gollum
  class Markup
    GitHub::Markup::Markdown::MARKDOWN_GEMS.clear
    GitHub::Markup::Markdown::MARKDOWN_GEMS['commonmarker'] = proc do |content|
      exts = %i[
        table
        tasklist
        strikethrough
        autolink
      ]
      parse_opts = %i[
        UNSAFE
        SMART
      ]
      render_opts = %i[
        UNSAFE
        GITHUB_PRE_LANG
      ]
      doc = CommonMarker.render_doc(content, parse_opts, exts)
      doc.to_html(render_opts)
    end
  end
end

Gollum::Markup.formats.select! { |k, _| k == :markdown }

ほかにどんなのが利用可能かはこちらを参照: https://github.com/github/markup/blob/master/lib/github/markup/markdown.rb

systemd で自動的に開始

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

[Service]
Type=simple
User=YOURNAME
WorkingDirectory=/path/to/your/labwiki
ExecStart=bundle exec gollum -c config.rb
Restart=on-abort
StandardOutput=file:/var/log/gollum.log
StandardError=file:/var/log/gollum.log

[Install]
WantedBy=multi-user.target
sudo systemctl start gollum.service
sudo systemctl enable gollum.service