🚀

Gollum で自宅用の Wiki を作った話

2022/07/05に公開

自宅で個人用 Wiki を Gollum で立てたのでその話を書きます。

Gollum とは

Gollum とは Ruby/Sinatra 製の Wiki です。MediaWiki 等の高機能かつ大人数で使うことを前提としている Wiki と比較すると、かなりシンプルな作りなのが特徴です。 Gollum は GitHub Wiki のエンジンにも使われています。 基本的に markdown で記述することが想定されていますが、それ以外の軽量マークアップ言語も扱えます。例えばorg-rubyの gem をインストールするだけで org-mode も (部分的に) 使うことができる様になります。 また、Wiki の版管理には SQL 等ではなく Git が使われているため、例えば直接 markdown を編集して git commit する、といった編集も可能です。

今回の要求仕様

ところで個人用 Wiki を立てるにあたり、要求仕様は大体以下の様な感じでした。こうしてみると Gollum の選択はなかなか良さそうですね。

  • 個人 Wiki なので、ユーザ登録等の本格的な機能は不要
    • 例えば MediaWiki とかは高機能すぎる
  • ハードウェアの移行が容易な作りが良い
    • ハードウェアは Raspberry Pi + Micro SD カードを使うので、ディスク寿命はそこまで長くない (はず)
  • メンテナンスコストは最小限にしたい
    • できるだけシンプルな作りが良い
    • バージョンアップ等の手間が少ない方が良い
  • (optional) Wiki の外部から編集できると便利
    • Emacs が手に馴染んでいるので、Emacs からも編集できると良い
  • (optional) org-mode の記法も使えると良い
    • Emacs の org-mode が手に馴染んでいるので
  • (optional) Basic 認証はかけられる
    • これは Apache 等 http サーバでも設定可能なのでなくてもよい

こういう感じで作りました

上記の要求仕様を充たすために、以下の感じのシステムを作りました。

以下、各要素について説明していきます。

Docker

ハードウェアの移行をできるだけ容易にするためにDockerを使うことにしました。 本家のDocker イメージおよびDockerfileもありますが、Docker イメージの build が古くて中にある gollum のバージョンが古いのと、org-mode を使うために org-ruby を追加したいのでDockerfileを修正して自前でイメージを build しました。 以下、知っている人には当たり前なことを一応書きます。

Docker イメージの build は Dockerfile のあるディレクトリで以下のコマンドを叩きます。

docker build -t gollum .

Docker image の起動は以下のコマンドで行います。 --restart=unless-stopped を付けておくとマシンの再起動時等に自動でこのイメージも起動するので便利です。 また、今回は Apache で localhost の 4567 番ポートへ転送するので --network=host を付ける必要があります (解説) 。

docker run --init -d  --name gollum --restart=unless-stopped -v ${PWD}:/wiki --network=host gollum --config=config.rb --template-dir=templates

以下 gollum に渡すオプションについて説明します。 まず --config=config.rb ですが、このオプションでは gollum の設定を記述したファイルを指定しています。このファイルでは、例えば自作のマクロの作成や hook の設定などを行うことができます。また、 --template-dir=templates では gollum のカスタムテンプレートを配置したディレクトリを指定しています。Gollum ではテンプレートを mustache で記述します。デフォルトのテンプレートは<https://github.com/gollum/gollum/tree/master/lib/gollum/templates から取得できます>。

Apache

Docker イメージに外部からアクセスするために、Apache のリバースプロキシを使いました。以下、知っている人には当たり前なことを一応書きます。Apache の設定は以下の様になります。以下のファイルを例えば /etc/apache2/sites-available/gollum.conf に保存します。今回は wiki.example.com へのアクセスを localhost に転送する設定をします。

    <VirtualHost *:80>
      ServerName wiki.example.com:80
      RewriteEngine on
      RewriteCond %{HTTP_HOST} ^wiki\.example\.com
      RewriteRule ^/(.*)$ https://wiki.example.com/$1 [R=301,L]
    </VirtualHost>

    <VirtualHost *:443>
      ServerName wiki.example.com
      ProxyPreserveHost On
      ProxyRequests off
      ProxyPass / http://localhost:4567/
      ProxyPassReverse / http://localhost:4567/
    </VirtualHost>

まず以下の部分 HTTP でのアクセスを HTTPS へのアクセスに変更します。より具体的には、Apache の mod<sub>rewrite</sub> を使ってhttp://wiki.example.com/ 以下へのアクセスを HTTP の 301 メッセージ共にhttps://wiki.example.com/ 以下へのアクセスに書き換えます。RewriteCond で書き換え対象の URL のパターンマッチを行い、RewriteRule で書き換えルールを正規表現で指定します。 最後の [R=301,L] の部分がフラグの部分で、ここで 301 メッセージでのリダイレクトであることと、これが最後の書き換えであることを指定しています。

  <VirtualHost *:80>
    ServerName wiki.example.com:80
    RewriteEngine on
    RewriteCond %{HTTP_HOST} ^wiki\.example\.com
    RewriteRule ^/(.*)$ https://wiki.example.com/$1 [R=301,L]
  </VirtualHost>

次にリバースプロキシの部分の設定を行います。

  <VirtualHost *:443>
    ServerName wiki.example.com
    ProxyPreserveHost On
    ProxyRequests off
    ProxyPass / http://localhost:4567/
    ProxyPassReverse / http://localhost:4567/
  </VirtualHost>

なお今回は Let’s encrypt を使って SSL による暗号化を行っているので、本当はその為の設定も記述する必要がありますが、certbot が自動で設定してくれることもあり、今回は省略しています。

上記の設定を有効化するためには、以下の様に a2ensite を実行します。

sudo a2ensite gollum

GitHub

Wiki の内容のバックアップ及び外部からも内容を編集できる様にするために、GitHub のプライベートリポジトリとも同期する様にしました。同期の速度を考えると自前で Git サーバを準備する方が良いですが、前述の通りディスクが Micro SD なので、耐障害性を優先して外部に保存することにしました。基本的な動作としては以下の様になります。なおそもそも利用者が非常に限られている想定なので、ほぼ同時に二箇所で変更が行なわれた場合の動作は考慮していません。例えば git pull する前に git push すると conflict して上手く動かないはずです。

  • Wiki が更新されたとき → system("git push&") で GitHub へ push する。 git push は数秒程度時間がかかるのでバックグラウンド実行させて、ページの読み込み自体はすぐに終わる様にする。
  • GitHub が更新されたとき → GitHub Actions で秘密の webhook にアクセスする。この webhook から git pull を行う。

具体的な設定は以下の様になります。

まず Gollum 側の hook については、以下の設定を config.rb に追加します。ここに記述している通り、Docker 上の /wiki/home_wiki に秘密鍵を置く必要があります。今回は新たに ssh-keygen で秘密鍵を作成し、このリポジトリ用に鍵を登録しました。

  require 'gollum-lib'

  Gollum::Hook.register(:post_commit, :hook_id) do |_, _|
    # Git push after commit
    system 'GIT_SSH_COMMAND="ssh -i /wiki/home_wiki -o IdentitiesOnly=yes -o StrictHostKeyChecking=no" git push origin master &'
  end

GitHub Actions の設定は以下の様になります。GitHub のリポジトリに push されると https://wiki.example.com/path/to/nice/webhook へ webhook が飛ぶ様になっています。

name: Gollum Pull

on: [push]

jobs:
  pull:
    runs-on: ubuntu-latest

    steps:
    - name: Webhook for gollum pull
      uses: joelwmale/webhook-action@master
      with:
        url: https://wiki.example.com/path/to/nice/webhook

まとめ

Gollum、簡単でしょ?

Discussion