www.mtkn.jp

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

git_server.html (11484B)


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