git_server.html (10594B)
1 +++ 2 date = '2024-02-15T00:00:00+09:00' 3 draft = false 4 title = 'Gitサーバーの設定 on OpenBSD' 5 +++ 6 <time>2024-02-15</time> 7 8 <h2>はじめに</h2> 9 <p> 10 GitHubがMicrosoft傘下になり久しい。MincraftがMicrosoftアカウントなしでは遊べなくなった。このままではGitHubもそのうちMicrosoftアカウントを要求するようになるかもしれない。ということでGitサーバーを自前で持つことにした。</p> 11 <p> 12 ところでOpenBSDの開発者がGotという別のgit実装を作成しているので、この記事は近いうちにいらなくなりそう。 13 </p> 14 15 <h2>手順</h2> 16 <p> 17 以下ではssh接続によるpull/push及び、httpsによるpullを設定の上、stagitというウェブフロントエンドを導入する。 18 </p> 19 20 <h3>概要</h3> 21 <ol> 22 <li>ドメインの設定(任意)</li> 23 <li><code>httpd(8)</code>の設定</li> 24 <li>gitパッケージのインストールとchroot環境の整備</li> 25 <li>stagitの導入</li> 26 </ol> 27 28 <h3>ドメインの設定(任意)</h3> 29 <p> 30 ドメインを設定する。IPアドレスでアクセスできればいいならこの設定はいらない。</p> 31 <p> 32 今回はgitというサブドメインを登録した: 33 </p> 34 <table> 35 <thead> 36 <tr> 37 <th>サブドメイン</th> 38 <th>種別</th> 39 <th>内容</th> 40 <th>優先度</th> 41 </tr> 42 </thead> 43 <tbody> 44 <tr> 45 <td>git</td> 46 <td>A</td> 47 <td><i>サーバーのIPアドレス</i></td> 48 <td></td> 49 </tr> 50 </tbody> 51 </table> 52 53 <h3><code>httpd(8)</code>の設定</h3> 54 <p> 55 httpsで接続する場合、<code>acme-client(8)</code>を設定する(IPアドレスで接続するなら自己証明書を発行することになる)。まず<code>/etc/acme-client.conf</code>にドメインを追加する: 56 </p> 57 <pre><code>domain git.mtkn.jp { 58 domain key "/etc/ssl/private/git.mtkn.jp.key" 59 domain full chain certificate "/etc/ssl/git.mtkn.jp.fullchain.pem" 60 sign with letsencrypt 61 } 62 </code></pre> 63 64 <p> 65 続いて<code>/etc/httpd.conf</code>を設定する。</p> 66 <pre><code>server "git.mtkn.jp" { 67 listen on * port 80 68 location "/.well-known/acme-challenge/*" { 69 root "/acme" 70 request strip 2 71 } 72 location "*" { 73 block return 302 "https://$HTTP_HOST$REQUEST_URI" 74 } 75 } 76 77 server "git.mtkn.jp" { 78 listen on * tls port 443 79 tls { 80 certificate "/etc/ssl/git.mtkn.jp.fullchain.pem" 81 key "/etc/ssl/private/git.mtkn.jp.key" 82 } 83 location "/.well-known/acme-challenge/*" { 84 root "/acme" 85 request strip 2 86 } 87 location "/*/git-receive-pack" { 88 block 89 } 90 location "/*/git-upload-pack" { 91 fastcgi { 92 param SCRIPT_FILENAME "/usr/local/libexec/git/git-http-backend" 93 param GIT_PROJECT_ROOT "/git" 94 param GIT_HTTP_EXPORT_ALL "true" 95 } 96 } 97 location "/*/info/refs" { 98 fastcgi { 99 param SCRIPT_FILENAME "/usr/local/libexec/git/git-http-backend" 100 param GIT_PROJECT_ROOT "/git" 101 param GIT_HTTP_EXPORT_ALL "true" 102 } 103 } 104 } 105 </code></pre> 106 <p> 107 <code>location "/*/git-receive-pack"</code>はpushの設定。今回はhttpsでのpushを受付けないので<code>block</code>する。</p> 108 <p> 109 <code>location "/*/git-upload-pack"</code>は手元のパソコンから<code>git clone</code>や<code>git pull</code>したときのもの。<code>location "/*/info/refs"</code>は上記を含むアクセスがあったときのもの。ここではCGIを使って<code>git-http-backend</code>を呼んでいるだけである。<code>SCRIPT_FILENAME</code>は<code>httpd(8)</code>のchroot環境でのパスである。必要なファイルは後でこのchroot環境にコピーする。 110 </p> 111 <p> 112 この後同じURLでフロントエンドをホストしたいので、上記のように必要なURLからのみCGIを実行するようにした。gitのhttpクライアントがどのURLを利用しているのかは[2]に書いていた。</p> 113 114 115 116 <p> 117 httpsが必要ない場合は1つ目の<code>server</code>に各<code>location</code>を書くだけでいい。 118 </p> 119 <p> 120 <code>httpd(8)</code>と<code>slowcgi(8)</code>を起動する: 121 </p> 122 <pre><code># echo httpd_flags= >> /etc/rc.conf.local 123 # echo slowcgi_flags= >> /etc/rc.conf.local 124 # rcctl start httpd 125 # rcctl enable httpd 126 # rcctl start slowcgi 127 # rcctl enable slowcgi 128 </code></pre> 129 <p> 130 サーバー証明書の発行: 131 </p> 132 <pre><code># acme-client -v git.mtkn.jp 133 </code></pre> 134 <p> 135 <code>crontab(1)</code>にサーバー証明書の自動更新を登録: 136 </p> 137 <pre><code>#minute hour mday month wday [flags] command 138 ~ 2 * * * acme-client git.mtkn.jp && rcctl reload httpd 139 </code></pre> 140 141 <h3>gitパッケージのインストールとchroot環境の整備</h3> 142 <p> 143 gitパッケージをインストールし、ssh接続用のユーザーを作成する。httpsでも公開するので、gitユーザーのホームディレクトリは<code>/var/www</code>下にする: 144 </p> 145 <pre><code># pkg_add git 146 # useradd -b /var/www -m -s /usr/local/bin/git-shell git 147 </code></pre> 148 <p> 149 ssh接続用の公開鍵を<code>/var/www/git/.ssh/authorized_keys</code>に登録する。ところでこのファイルに公開鍵を書き込むとgitユーザーとしてsshでログインできるので、部外者がこのファイルの編集をできないようにしておく必要がある。一応所有者は<code>git:git</code>、権限は<code>-rw-------</code>なので大丈夫だと思うが、心配なら<code>httpd(8)</code>のchroot環境の外にこのファイルを移動させておいてもいいかもしれない。</p> 150 <p> 151 httpsでアクセスするためにchroot環境を整備する。<code>httpd(8)</code>は既定では<code>/var/www</code>にchrootして実行されるので、CGIに必要なファイルをこのディレクトリ以下に用意する必要がある。まずはgitのコマンドをコピー: 152 </p> 153 <pre><code># mkdir -p /var/www/usr/local/libexec/git 154 # cp /usr/local/libexec/git/git-{http-backend,receive-pack,upload-pack} /var/www/usr/local/libexec/git/ 155 # chown www:www /var/www/usr/local/libexec/git/git-{http-backend,receive-pack,upload-pack} 156 # chmod 0500 /var/www/usr/local/libexec/git/git-{http-backend,receive-pack,upload-pack} 157 # mkdir -p /var/www/usr/local/bin 158 # cp /usr/local/bin/git /var/www/usr/local/bin/ 159 # chown www:www /var/www/usr/local/bin/git 160 # chmod 0500 /var/www/usr/local/bin/git 161 </code></pre> 162 <p> 163 続いてコマンドの実行に必要なライブラリをコピー: 164 </p> 165 <pre><code># mkdir -p /var/www/usr/lib /var/www/usr/local/lib /var/www/usr/libexec 166 # 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 167 </code></pre> 168 <p> 169 <code>/dev/null</code>をコピーする(<code>mknod(8)</code>参照): 170 </p> 171 <pre><code># mkdir /var/www/dev 172 # mknod -m 666 /var/www/dev/null c 2 2 173 </code></pre> 174 <p> 175 最後に、<code>/var/www/dev/null</code>を作成するために<code>/etc/fstab</code>の<code>/var</code>エントリーから<code>nodev</code>オプションを削除し、再起動する。 176 </p> 177 178 <p> 179 gitパッケージやシステムの更新後、chroot環境のコマンドやライブラリも更新しないといけないのでそのためのスクリプトを適当に作った: 180 </p> 181 <pre><code>#!/bin/sh -xe 182 183 oso=$(find /var/www/usr -type f -name '*.so*') 184 rm $oso 185 186 bin=$(find /var/www/bin /var/www/usr -type f ! -name '*.so*' | 187 grep -v bgpctl | 188 sed 's|^/var/www||' 189 ) 190 echo "$bin" | sed 's|.*|cp & /var/www&|' | sh -s 191 echo "$bin" | sed 's|.*|chown www:www /var/www&|' | sh -s 192 echo "$bin" | sed 's|.*|chmod 0500 /var/www&|' | sh -s 193 194 nso=$(echo "$bin" | sed 's|^|/var/www|' | 195 xargs ldd | awk '{print $7}' | 196 grep -v -e '^/var/www/' -e '^$' -e 'Name' | 197 sort | uniq 198 ) 199 echo "$nso" | sed 's|.*|cp & /var/www&|' | sh -s 200 echo "$nso" | sed 's|.*|chown www:www /var/www&|' | sh -s 201 echo "$nso" | sed 's|.*|chmod 0400 /var/www&|' | sh -s 202 </code></pre> 203 204 <h3><code>stagit(1)</code>の導入</h3> 205 <p> 206 ウェブフロントエンドとしてstagitを導入する: 207 </p> 208 <pre><code># pkg_add stagit 209 </code></pre> 210 <p> 211 <code>httpd.conf(5)</code>の<code>server "git.mtkn.jp"</code>の中に以下の設定を追加する(<code>location</code>のマッチは上から順番に評価されるので、上で設定したgitのhttpクライアント用の<code>location</code>よりも下に記入する): 212 </p> 213 <pre><code> location "/" { 214 directory index index.html 215 root "/htdocs/git.mtkn.jp" 216 } 217 location "*" { 218 directory index log.html 219 root "/htdocs/git.mtkn.jp" 220 } 221 </code></pre> 222 <p> 223 stagit用のディレクトリを作成して<code>httpd(8)</code>を再読込する: 224 </p> 225 <pre><code># mkdir /var/www/htdocs/git.mtkn.jp 226 # chown git:git /var/www/htdocs/git.mtkn.jp 227 # rcctl reload httpd 228 </code></pre> 229 230 <p> 231 gitリポジトリが更新されたときにウェブページも更新するように設定する。gitリポジトリはなにか更新があった場合、そのリポジトリのディレクトリの中の<code>hooks/post-receive</code>というファイルを自動で実行する。そのためこのファイルに、stagitの更新をするスクリプトを書いておけばいい: 232 </p> 233 <pre><code>#!/bin/sh 234 235 git_root="/var/www/git" 236 stagit_root="/var/www/htdocs/git.mtkn.jp" 237 repo="$(basename "$(pwd)" | sed 's/\.git$//')" 238 src="$(pwd)" 239 stagit_dst="$stagit_root/$repo" 240 241 mkdir -p "$stagit_dst" 242 (cd "$stagit_dst" && stagit -l 64 "$src") 243 (cd "$stagit_root" && stagit-index $git_root/*.git > index.html) 244 </code></pre> 245 246 <h2>レポジトリの作成</h2> 247 <p> 248 レポジトリを作成するにはサーバーで以下のようにする。</p> 249 <pre><code>$ cd /var/www/git 250 $ doas -u git mkdir <i>repo</i>.git 251 $ cd <i>repo</i>.git 252 $ doas -u git git init --bare 253 </code></pre> 254 255 <p> 256 これで手元のパソコンからクローンできる: 257 </p> 258 <pre><code>$ git clone git@git.mtkn.jp:<i>repo</i>.git 259 </code></pre> 260 <p> 261 または 262 </p> 263 <pre><code>$ git clone https://git.mtkn.jp/<i>repo</i>.git 264 </code></pre> 265 266 <h2>参考</h2> 267 <ul> 268 <li>[1] <a href="https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols">Git - The Protocols.Git</a></li> 269 <li>[2] <a href="https://git-scm.com/docs/http-protocol">Git - http-protocol Documentation.Git</a></li> 270 <li>[3] <a href="https://codemadness.org/stagit.html">Stagit: a static git page generator - Codemadness</a></li> 271 </ul> 272