gitoliteで許可されたディレクトリのみをgitwebで表示する(gitolite + gitweb + nginx + Basic認証)

日本語資料がまったくなかったので怒りのQiita初投稿

## 目標/仕様
- gitoliteを用いてGitレポジトリの権限管理を行う。
- Gitに対する接続はSSH,HTTPSともに確保する。
- サーバー上に存在するGitレポジトリをgitwebで表示する。
ただし、閲覧できるレポジトリはgitoliteにより指定されるものとする。
- nginxはGit以外の公開ページにも用いるため、gitolite,gitwebはサブディレクトリに配置する。サブドメインにしなかったのはCertbotでワイルドカード証明書が取れないため。~~サブドメインごとに取るのめんどい~~

## 構成
- git 2.10.0.rc1
- gitolite v3.6.6-3-g72c0238
- nginx 1.10.2

ちなみにCentOS7 on さくらのVPSです

## 前提

- gitがインストールされていること(gitwebが同梱されているため)
- nginxがインストールされており、接続できること

## なにはともあれまずはgitolite
git:gitとしてgitoliteを立ち上げるとする。
gitoliteを公式ドキュメント( http://gitolite.com/gitolite/install.html )に従ってインストールすると/home/git/にもろもろのファイルが配置される。これではパーミッションの関係で、gitへのSSHアクセスかnginxのnginxユーザでの立ち上げのどちらかを諦めなければならない。
そこで、gitoliteのインストールフォルダを変更する(ここでは/path/to/gitolite/とする)

```bash:COMMAND_install-gitolite
$ su - git
$ cd /path/to/gitolite
$ mkdir bin

$ git clone git://github.com/sitaramc/gitolite
$ gitolite/install -ln bin
$ gitolite setup -pk admin.pub
#ユーザ識別用の鍵を指定。公開鍵は事前にSCPかなにかで送っておく
```

注意としてはユーザ識別用の鍵としてSSHログイン用の鍵を**用いないこと**。SSHログインなのかgitolite向けのログインなのか分からねーよと怒られてしまう。

これだけではダメで、SSHとHTTPS両方でアクセス可能にするためには、上で書いたようにgitoliteのフォルダが/home/git以下にあってはならない。そこで/path/to/gitoliteに全部引っ越して、/home/gitからはシンボリックリンクを貼ることで対処する。

```bash:COMMAND_move-gitolite-dir
$ mv ~/.gitolite* /path/to/gitolite/
$ mv ~/repositories /path/to/gitolite/
$ ln -s /path/to/gitolite/.gitolite ~/.gitolite
$ ln -s /path/to/gitolite/.gitolite.rc ~/.gitolite.rc
$ ln -s /path/to/gitolite/repositories ~/repositories
```

また、お引っ越しをしたことにより設定をいじってやる必要がある。具体的には

- nginxが読み書きできるように、パーミッションの変更
- レポジトリの保存フォルダの変更
- gitoliteのバイナリにパスを通す

の3点である。

```diff:/path/to/gitolite/.gitolite.rc
+ $ENV{PATH} .= ":/path/to/gitolite/bin";
  ...
  %RC = (
  ...
- UMASK => 0007
+ UMASK => 0007
  ...
+ GL_REPO_BASE => "/path/to/gitolite/repositories",
  )
```

ここまででとりあえずgitoliteがSSHで通るようになった。
git clone git@hogehoge:testing が通ることを確かめておくと良い。ただしSSH鍵はgitユーザのもの**ではなく**インストールの際に指定したadminの鍵である。

## spawn-fcgiのインストール
gitoliteとnginxを連携させるにはCGIが動かなければならない。そのための下準備としてspawn-fcgiをインストールしておく。

```bash:COMMAND_install-spawn-fcgi
$ sudo yum install fcgi-devel automake autoconf spawn-fcgi
$ git clone https://github.com/gnosek/fcgiwrap
$ cd fcgiwrap
$ autoreconf -i
$ ./configure
$ make
$ sudo make install
```

spawn-fcgiのコンフィグをnginx向けに修正。このとき、CGIを呼び出す際にgitグループとして実行しているため、nginxユーザをgitグループに追加する必要がある。

```bash:COMMAND_add-nginx-into-git
$ usermod -a -G git nginx
```

```diff:/etc/sysconfig/spawn-fcgi
  ...
+ OPTIONS="-u nginx -g git -s /var/run/fcgiwrap.sock -S -M 0660 -F 4 -P /var/run/spawn-fcgi.pid -- /usr/local/sbin/fcgiwrap"
```

## gitolite over HTTPS with nginx

https://hogehoge/git/ にアクセスした際にnginxがspawn-fcgiを呼び出すように設定を行う。この際、Basic認証によってユーザを識別するので、予めhtpasswdファイルを作成しておく。

```bash:COMMAND_make-htpasswd
$ sudo yum install httpd-tools
$ sudo htpasswd -cs /var/www/git/.htpasswd USERNAME
```

```/etc/nginx/default.d/gitrepo.conf
location /git/ {

  auth_basic            "Restricted";
  auth_basic_user_file  /var/www/git/.htpasswd;

  access_log  /var/log/nginx/git_access.log  main;
  error_log   /var/log/nginx/git_error.log;

  proxy_read_timeout    300;
  proxy_connect_timeout 300;
  proxy_redirect        off;

  fastcgi_split_path_info ^(/git)(/[^/]+\.git/.*);

  include /etc/nginx/fastcgi_params;
  fastcgi_param SCRIPT_FILENAME /path/to/gitolite/gitolite/src/gitolite-shell;
  fastcgi_param GITOLITE_HTTP_HOME /path/to/gitolite;
  fastcgi_param GIT_PROJECT_ROOT /path/to/gitolite/repositories;
  fastcgi_param GIT_HTTP_EXPORT_ALL 1;
  fastcgi_param PATH_INFO $fastcgi_path_info;
  fastcgi_param REMOTE_USER $remote_user;

  fastcgi_pass unix:/var/run/fcgiwrap.sock;
}
```

また、Basic認証はそのままだとパスワードが平文で流れるので、HTTPSで通信するよう強制する。サーバー証明書はCertbot/Let's Encryptを用いるとよい。nginxでのHTTPS通信およびCertbot/Let's Encryptについては日本語資料もそこそこあるため適宜参照のこと。

```diff:/etc/nginx/nginx.conf
  ...
- user nginx nginx;
+ user nginx git;
  ...
  http{
    ...
    server{
      listen       80 default_server;
      listen       [::]:80 default_server;
      server_name  hogehoge;
+     return       301 https://$host$request_uri;
      ...
```

ここまででSSH/HTTPSそれぞれでgitoliteにアクセスできるようになったはずである。
git clone https://hogehoge/git/testing.git して試してみると良い。

## gitweb-gitolite連携
コードの基礎は http://gitolite.com/gitolite/gitweb.conf.html にあるとおりである。つまりnginxから受け取ったユーザ名をgitoliteに引き渡してやれば良い。ただしnginxでは少し工夫が必要となる。
まずはnginxの設定である。

```/etc/nginx/default.d/gitweb.conf
location /gitweb/ {

  auth_basic            "Restricted";
  auth_basic_user_file  /var/www/git/.htpasswd;

  root /usr/local/share/;

  access_log  /var/log/nginx/gitweb_access.log  main;
  error_log   /var/log/nginx/gitweb_error.log;

  proxy_read_timeout    300;
  proxy_connect_timeout 300;
  proxy_redirect        off;

  # fastcgi_split_path_info ^(/git)(/[^/]+\.git/.*);

  index /gitweb/index.cgi;
  gzip off;

  include /etc/nginx/fastcgi_params;
  fastcgi_param SCRIPT_FILENAME /usr/local/share/gitweb/gitweb.cgi;
  fastcgi_param GITWEB_CONFIG /usr/local/share/gitweb/gitweb.conf.pl;
  fastcgi_param REMOTE_USER $remote_user;

  if ($uri ~ "/gitweb/index.cgi"){
    fastcgi_pass unix:/var/run/fcgiwrap.sock;
  }
}
```
gitwebで用いられている/etc/gitweb.confの代わりに/usr/local/share/gitweb/gitweb.conf.plを用いるよう指定する点、および\$ENV{REMOTE_USER}に$remote_userを渡してやる点がミソである。そして、そのgitweb.conf.plの内容は以下である。~~ほとんどさっき出したサイトのコピー~~

```/usr/local/share/gitweb/gitweb.conf.pl
BEGIN {
    $ENV{HOME} = "/path/to/gitolite/";
    $ENV{GL_BINDIR} = "/path/to/gitolite/gitolite/src";
    $ENV{GL_LIBDIR} = "/path/to/gitolite/gitolite/src/lib";
}
use lib $ENV{GL_LIBDIR};
use Gitolite::Easy;
$projectroot = $ENV{GL_REPO_BASE};

# Changed from original gitweb.conf.pl
# for nginx
$ENV{GL_USER} = $ENV{REMOTE_USER} || "Anonymous";

$export_auth_hook = sub {
    my $repo = shift;
    return unless $repo =~ s/^\Q$projectroot\E\/?(.+)\.git$/$1/;

    return can_read($repo);
};
```

これでようやく完成。https://hogehoge/gitweb/ にアクセスするとユーザ名とパスワードが要求され、ログインするとそのユーザがRead権限を持っているレポジトリが閲覧できる。はず。

## 参考Web
- http://qiita.com/egnr-in-6matroom/items/2a052339ee0515b31fdf (git+nginxの設定の基礎)
- http://gitolite.com/gitolite/ssh-and-http.html (gitolite+smart httpの設定:公式ドキュメント)
- http://gitolite.com/gitolite/gitweb.conf.html (gitolite+gitweb+Apacheの設定)