www.mtkn.jp

Manuscripts for my personal webpage.
git clone https://git.mtkn.jp/www.mtkn.jp
Log | Files | Refs | LICENSE

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= &gt;&gt; /etc/rc.conf.local
    123 # echo slowcgi_flags= &gt;&gt; /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 &quot;cp %s /var/www%s &amp;&amp; chown www:www /var/www%s &amp;&amp; chmod 0400 /var/www%s\n&quot;, $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 &quot;$bin&quot; | sed 's|.*|cp &amp; /var/www&amp;|' | sh -s
    191 echo &quot;$bin&quot; | sed 's|.*|chown www:www /var/www&amp;|' | sh -s
    192 echo &quot;$bin&quot; | sed 's|.*|chmod 0500 /var/www&amp;|' | sh -s
    193 
    194 nso=$(echo &quot;$bin&quot; | 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 &quot;$nso&quot; | sed 's|.*|cp &amp; /var/www&amp;|' | sh -s
    200 echo &quot;$nso&quot; | sed 's|.*|chown www:www /var/www&amp;|' | sh -s
    201 echo &quot;$nso&quot; | sed 's|.*|chmod 0400 /var/www&amp;|' | 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 &quot;/&quot; {
    214 		directory index index.html
    215 		root &quot;/htdocs/git.mtkn.jp&quot;
    216 	}
    217 	location &quot;*&quot; {
    218 		directory index log.html
    219 		root &quot;/htdocs/git.mtkn.jp&quot;
    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=&quot;/var/www/git&quot;
    236 stagit_root=&quot;/var/www/htdocs/git.mtkn.jp&quot;
    237 repo=&quot;$(basename &quot;$(pwd)&quot; | sed 's/\.git$//')&quot;
    238 src=&quot;$(pwd)&quot;
    239 stagit_dst=&quot;$stagit_root/$repo&quot;
    240 
    241 mkdir -p &quot;$stagit_dst&quot;
    242 (cd &quot;$stagit_dst&quot; &amp;&amp; stagit -l 64 &quot;$src&quot;)
    243 (cd &quot;$stagit_root&quot; &amp;&amp; stagit-index $git_root/*.git &gt; 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