Gitサーバーの設定 on OpenBSD
はじめに
GitHubがMicrosoft傘下になり久しい。MincraftがMicrosoftアカウントなしでは遊べなくなった。このままではGitHubもそのうちMicrosoftアカウントを要求するようになるかもしれない。ということでGitサーバーを自前で持つことにした。
ところでOpenBSDの開発者がGotという別のgit実装を作成しているので、この記事は近いうちにいらなくなりそう。
手順
以下ではssh接続によるpull/push及び、httpsによるpullを設定の上、stagitというウェブフロントエンドを導入する。
概要
- ドメインの設定(任意)
httpd(8)
の設定- gitパッケージのインストールとchroot環境の整備
- stagitの導入
ドメインの設定(任意)
ドメインを設定する。IPアドレスでアクセスできればいいならこの設定はいらない。
今回はgitというサブドメインを登録した:
サブドメイン | 種別 | 内容 | 優先度 |
---|---|---|---|
git | A | サーバーのIPアドレス |
httpd(8)
の設定
httpsで接続する場合、acme-client(8)
を設定する(IPアドレスで接続するなら自己証明書を発行することになる)。まず/etc/acme-client.conf
にドメインを追加する:
domain git.mtkn.jp {
domain key "/etc/ssl/private/git.mtkn.jp.key"
domain full chain certificate "/etc/ssl/git.mtkn.jp.fullchain.pem"
sign with letsencrypt
}
続いて/etc/httpd.conf
を設定する。
server "git.mtkn.jp" {
listen on * port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
location "*" {
block return 302 "https://$HTTP_HOST$REQUEST_URI"
}
}
server "git.mtkn.jp" {
listen on * tls port 443
tls {
certificate "/etc/ssl/git.mtkn.jp.fullchain.pem"
key "/etc/ssl/private/git.mtkn.jp.key"
}
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
location "/*/git-receive-pack" {
block
}
location "/*/git-upload-pack" {
fastcgi {
param SCRIPT_FILENAME "/usr/local/libexec/git/git-http-backend"
param GIT_PROJECT_ROOT "/git"
param GIT_HTTP_EXPORT_ALL "true"
}
}
location "/*/info/refs" {
fastcgi {
param SCRIPT_FILENAME "/usr/local/libexec/git/git-http-backend"
param GIT_PROJECT_ROOT "/git"
param GIT_HTTP_EXPORT_ALL "true"
}
}
}
location "/*/git-receive-pack"
はpushの設定。今回はhttpsでのpushを受付けないのでblock
する。
location "/*/git-upload-pack"
は手元のパソコンからgit clone
やgit pull
したときのもの。location "/*/info/refs"
は上記を含むアクセスがあったときのもの。ここではCGIを使ってgit-http-backend
を呼んでいるだけである。SCRIPT_FILENAME
はhttpd(8)
のchroot環境でのパスである。必要なファイルは後でこのchroot環境にコピーする。
この後同じURLでフロントエンドをホストしたいので、上記のように必要なURLからのみCGIを実行するようにした。gitのhttpクライアントがどのURLを利用しているのかは[2]に書いていた。
httpsが必要ない場合は1つ目のserver
に各location
を書くだけでいい。
httpd(8)
とslowcgi(8)
を起動する:
# echo httpd_flags= >> /etc/rc.conf.local
# echo slowcgi_flags= >> /etc/rc.conf.local
# rcctl start httpd
# rcctl enable httpd
# rcctl start slowcgi
# rcctl enable slowcgi
サーバー証明書の発行:
# acme-client -v git.mtkn.jp
crontab(1)
にサーバー証明書の自動更新を登録:
#minute hour mday month wday [flags] command
~ 2 * * * acme-client git.mtkn.jp && rcctl reload httpd
gitパッケージのインストールとchroot環境の整備
gitパッケージをインストールし、ssh接続用のユーザーを作成する。httpsでも公開するので、gitユーザーのホームディレクトリは/var/www
下にする:
# pkg_add git
# useradd -b /var/www -m -s /usr/local/bin/git-shell git
ssh接続用の公開鍵を/var/www/git/.ssh/authorized_keys
に登録する。ところでこのファイルに公開鍵を書き込むとgitユーザーとしてsshでログインできるので、部外者がこのファイルの編集をできないようにしておく必要がある。一応所有者はgit:git
、権限は-rw-------
なので大丈夫だと思うが、心配ならhttpd(8)
のchroot環境の外にこのファイルを移動させておいてもいいかもしれない。
httpsでアクセスするためにchroot環境を整備する。httpd(8)
は既定では/var/www
にchrootして実行されるので、CGIに必要なファイルをこのディレクトリ以下に用意する必要がある。まずはgitのコマンドをコピー:
# mkdir -p /var/www/usr/local/libexec/git
# cp /usr/local/libexec/git/git-{http-backend,receive-pack,upload-pack} /var/www/usr/local/libexec/git/
# chown www:www /var/www/usr/local/libexec/git/git-{http-backend,receive-pack,upload-pack}
# chmod 0500 /var/www/usr/local/libexec/git/git-{http-backend,receive-pack,upload-pack}
# mkdir -p /var/www/usr/local/bin
# cp /usr/local/bin/git /var/www/usr/local/bin/
# chown www:www /var/www/usr/local/bin/git
# chmod 0500 /var/www/usr/local/bin/git
続いてコマンドの実行に必要なライブラリをコピー:
# mkdir -p /var/www/usr/lib /var/www/usr/local/lib /var/www/usr/libexec
# find /var/www/{bin,usr} -type f | grep git | xargs ldd | awk '{print $7}' | grep -v -e '^/var/www/' -e '^$' -e 'Name' | sort | uniq | awk '{printf "cp %s /var/www%s && chown www:www /var/www%s && chmod 0400 /var/www%s\n", $1, $1, $1, $1}' | sh -s
/dev/null
をコピーする(mknod(8)
参照):
# mkdir /var/www/dev
# mknod -m 666 /var/www/dev/null c 2 2
最後に、/var/www/dev/null
を作成するために/etc/fstab
の/var
エントリーからnodev
オプションを削除し、再起動する。
gitパッケージやシステムの更新後、chroot環境のコマンドやライブラリも更新しないといけないのでそのためのスクリプトを適当に作った:
#!/bin/sh -xe
oso=$(find /var/www/usr -type f -name '*.so*')
rm $oso
bin=$(find /var/www/bin /var/www/usr -type f ! -name '*.so*' |
grep -v bgpctl |
sed 's|^/var/www||'
)
echo "$bin" | sed 's|.*|cp & /var/www&|' | sh -s
echo "$bin" | sed 's|.*|chown www:www /var/www&|' | sh -s
echo "$bin" | sed 's|.*|chmod 0500 /var/www&|' | sh -s
nso=$(echo "$bin" | sed 's|^|/var/www|' |
xargs ldd | awk '{print $7}' |
grep -v -e '^/var/www/' -e '^$' -e 'Name' |
sort | uniq
)
echo "$nso" | sed 's|.*|cp & /var/www&|' | sh -s
echo "$nso" | sed 's|.*|chown www:www /var/www&|' | sh -s
echo "$nso" | sed 's|.*|chmod 0400 /var/www&|' | sh -s
stagit(1)
の導入
ウェブフロントエンドとしてstagitを導入する:
# pkg_add stagit
httpd.conf(5)
のserver "git.mtkn.jp"
の中に以下の設定を追加する(location
のマッチは上から順番に評価されるので、上で設定したgitのhttpクライアント用のlocation
よりも下に記入する):
location "/" {
directory index index.html
root "/htdocs/git.mtkn.jp"
}
location "*" {
directory index log.html
root "/htdocs/git.mtkn.jp"
}
stagit用のディレクトリを作成してhttpd(8)
を再読込する:
# mkdir /var/www/htdocs/git.mtkn.jp
# chown git:git /var/www/htdocs/git.mtkn.jp
# rcctl reload httpd
gitリポジトリが更新されたときにウェブページも更新するように設定する。gitリポジトリはなにか更新があった場合、そのリポジトリのディレクトリの中のhooks/post-receive
というファイルを自動で実行する。そのためこのファイルに、stagitの更新をするスクリプトを書いておけばいい:
#!/bin/sh
git_root="/var/www/git"
stagit_root="/var/www/htdocs/git.mtkn.jp"
repo="$(basename "$(pwd)" | sed 's/\.git$//')"
src="$(pwd)"
stagit_dst="$stagit_root/$repo"
mkdir -p "$stagit_dst"
(cd "$stagit_dst" && stagit -l 64 "$src")
(cd "$stagit_root" && stagit-index $git_root/*.git > index.html)
レポジトリの作成
レポジトリを作成するにはサーバーで以下のようにする。
$ cd /var/www/git
$ doas -u git mkdir repo.git
$ cd repo.git
$ doas -u git git init --bare
これで手元のパソコンからクローンできる:
$ git clone git@git.mtkn.jp:repo.git
または
$ git clone https://git.mtkn.jp/repo.git