Gollum: 轻量级基于Git的Wiki系统
最近准备搭建一个wiki,看了维基百科上的wiki软件列表后觉得可用的实在太少。我希望架设一个轻量级的wiki,至少能满足以下条件:
- 非PHP
- 支持MarkDown语法
- 最好能支持OAuth2认证
其实GitHub自带的wiki系统能很好满足我的需求。后来看到GitHub用的wiki叫做Gollum,简单试用了一下发现效果很不错,能满足绝大部分需求,并且还有额外赠送的基于git的存储。
其实Gollum本身的安装很简单,一个gem install
就能搞定,不过想支持OAuth2认证以及服务器配置比较麻烦。所以下面着重从这两方面介绍。
OAuth2认证
要想做OAuth2认证首先要选一家认证服务,我选择了Google。其他OAuth2用到的包可能会稍有不同。
登录到Google Developer Console,新建一个Project,然后打开该Project,从左侧菜单中选择”APIs & auth” → “APIs”,启用”Google+ API”。后面的认证需要用到这个API。
之后选择”APIs & auth” → “Credentials”,单击”Create new Client ID”,然后填入以下值:
- Application type: Web application
- Authorized JavaScript origins:
http://服务器域名
- Authorized redirect URIs:
http://服务器域名/__omnigollum__/auth/google_oauth2/callback
建好之后从中找出Client ID和Client secret两个值,稍后配置Gollum时会用到。
接下来要安装Gollum。我在这里没有使用rvm,因为最初安装时遇到一点问题怀疑是rvm导致的(后证实与rvm无关)从而选择了全局安装ruby。下次安装时可以尝试下rvm。首先安装必要的gems:
sudo gem install gollum omniauth omnigollum omnigollum-google-oauth2
其中:
gollum
:wiki系统omniauth
:通用的认证中间件omnigollum
:连接gollum
和omniauth
的桥梁omniauth-googleo-oauth2
:为omniauth
提供Google OAuth2的认证策略
为了方便配置,我们要将gollum的主目录放在/opt/gollum
,并为其单独建一个用户,用这个用户来启动gollum进程。这也是rvm建议的做法。
$ sudo useradd -d /opt/gollum gollum
$ sudo mkdir -p /opt/gollum
$ sudo chown gollum:gollum /opt/gollum
切换到gollum
用户:
$ sudo su - gollum
创建git仓库,作为Gollum的存储:
$ cd /opt/gollum
$ mkdir wiki
$ cd wiki
$ git init
创建其他必要的目录:
$ cd /opt/gollum
$ mkdir log run
我们稍后会使用unicorn来运行gollum,所以需要为unicorn创建Rack配置文件/opt/gollum/config.ru
:
#!/usr/bin/env ruby
require 'rubygems'
require 'gollum/app'
# Specify the path to the Wiki.
gollum_path = File.join(File.expand_path(File.dirname(__FILE__)), 'wiki')
puts gollum_path
Precious::App.set(:gollum_path, gollum_path)
# Specify markup language
Precious::App.set(:default_markup, :markdown)
# Specify the wiki options
wiki_options = {
:live_preview => false, # 禁用实时预览
:allow_uploads => true, # 允许文件上传
:per_page_uploads => true, # 文件上传到每页的子目录中
:h1_title => true, # 页面中的首个h1作为页面标题
:allow_editing => true # 允许所有人编辑
}
Precious::App.set(:wiki_options, wiki_options)
# Add Google OAuth2 authentication to all urls
require 'omnigollum'
require 'omniauth/strategies/google_oauth2'
GOOGLE_CLIENT_ID = '<Google提供的Client ID>'
GOOGLE_CLIENT_SECRET = '<Google提供的Client Secret>'
options = {
:providers => Proc.new do
provider :google_oauth2, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, {
:scope => 'email,profile',
:hd => '允许登录的用户的域',
:redirect_uri => 'http://服务器域名/__omnigollum__/auth/google_oauth2/callback'
}
end,
:dummy_auth => false,
:protected_routes => ['/*'],
:author_format => Proc.new { |user| user.name },
:author_email => Proc.new { |user| user.email }
}
Precious::App.set(:omnigollum, options)
Precious::App.register Omnigollum::Sinatra
# limit to some formats
Gollum::Page::FORMAT_NAMES = {
:markdown => "Markdown",
:mediawiki => "MediaWiki",
:rdoc => "RDoc"
}
# Run
run Precious::App
上述配置中的:providers
部分是OAuth2的认证,文档参考omni-google-oauth2的文档。wiki_options
是Gollum本身的认证,详细配置可以参考Gollum的文档。
运行Gollum
我们将使用nginx + unicorn运行Gollum,用supervisord做系统监视。
首先创建unicorn的配置文件/opt/gollum/unicorn.conf.rb
:
app_directory = "/opt/gollum"
worker_processes 2
working_directory app_directory
listen "unix:#{app_directory}/run/gollum.sock", :backlog => 1024
timeout 60
user 'gollum', 'gollum'
File.umask(027)
preload_app true
pid "#{app_directory}/run/gollum.pid"
stderr_path "#{app_directory}/log/gollum-stderr.log"
stdout_path "#{app_directory}/log/gollum-stdout.log"
然后配置nginx(/etc/nginx/conf.d/gollum.conf
,基于CentOS 6):
upstream unicorn {
server unix:/opt/gollum/run/gollum.sock;
}
server {
listen 80;
server_name 服务器域名;
access_log /opt/gollum/log/nginx_access_log;
error_log /opt/gollum/log/nginx_error_log info;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_pass http://unicorn;
}
}
试着启动服务器:
$ cd /opt/gollum
$ unicorn -c unicorn.conf.rb
到这一步应该可以通过浏览器访问wiki了。
接下来配置supervisord。首先安装supervisord:
$ sudo pip install supervisor
创建/etc/supervisord.conf
:
[unix_http_server]
file=/var/tmp/supervisor.sock
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=debug ; (logging level;default info; others: debug,warn)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/tmp/supervisor.sock ; use a unix:// URL for a unix socket
[include]
files=/etc/supervisord.d/*.conf
创建目录/etc/supervisord.d/
并创建以下配置文件/etc/supervisord.d/gollum.conf
:
[program:gollum]
directory=/opt/gollum
command=/usr/local/bin/unicorn -c unicorn.conf.rb
user=gollum
umask=022
autostart=true
autorestart=true
startretries=3
redirect_stderr=true
创建initscript以启动supervisord(/etc/init.d/supervisord
):
#!/bin/bash
#
# supervisord Startup script for the Supervisor process control system
#
# Author: Mike McGrath <mmcgrath@redhat.com> (based off yumupdatesd)
# Jason Koppe <jkoppe@indeed.com> adjusted to read sysconfig,
# use supervisord tools to start/stop, conditionally wait
# for child processes to shutdown, and startup later
# Erwan Queffelec <erwan.queffelec@gmail.com>
# make script LSB-compliant
#
# chkconfig: 345 83 04
# description: Supervisor is a client/server system that allows \
# its users to monitor and control a number of processes on \
# UNIX-like operating systems.
# processname: supervisord
# config: /etc/supervisord.conf
# config: /etc/sysconfig/supervisord
# pidfile: /var/run/supervisord.pid
#
### BEGIN INIT INFO
# Provides: supervisord
# Required-Start: $all
# Required-Stop: $all
# Short-Description: start and stop Supervisor process control system
# Description: Supervisor is a client/server system that allows
# its users to monitor and control a number of processes on
# UNIX-like operating systems.
### END INIT INFO
# Source function library
. /etc/rc.d/init.d/functions
# Source system settings
if [ -f /etc/sysconfig/supervisord ]; then
. /etc/sysconfig/supervisord
fi
# Path to the supervisorctl script, server binary,
# and short-form for messages.
supervisorctl=/usr/bin/supervisorctl
supervisord=${SUPERVISORD-/usr/bin/supervisord}
prog=supervisord
pidfile=${PIDFILE-/var/run/supervisord.pid}
lockfile=${LOCKFILE-/var/lock/subsys/supervisord}
STOP_TIMEOUT=${STOP_TIMEOUT-60}
OPTIONS="${OPTIONS--c /etc/supervisord.conf}"
RETVAL=0
start() {
echo -n $"Starting $prog: "
daemon --pidfile=${pidfile} $supervisord $OPTIONS
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
touch ${lockfile}
$supervisorctl $OPTIONS status
fi
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc -p ${pidfile} -d ${STOP_TIMEOUT} $supervisord
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -rf ${lockfile} ${pidfile}
}
reload() {
echo -n $"Reloading $prog: "
LSB=1 killproc -p $pidfile $supervisord -HUP
RETVAL=$?
echo
if [ $RETVAL -eq 7 ]; then
failure $"$prog reload"
else
$supervisorctl $OPTIONS status
fi
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status -p ${pidfile} $supervisord
RETVAL=$?
[ $RETVAL -eq 0 ] && $supervisorctl $OPTIONS status
;;
restart)
restart
;;
condrestart|try-restart)
if status -p ${pidfile} $supervisord >&/dev/null; then
stop
start
fi
;;
force-reload|reload)
reload
;;
*)
echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|reload}"
RETVAL=2
esac
exit $RETVAL
最后启动supervisord:
$ sudo service supervisord start
$ sudo supervisorctl status