size: 6 KiB

1<!doctype html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <title>First | loa</title>
6 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
8 <meta property="og:site_name" content="loa" />
9 <meta property="og:title" content="First" />
10 <meta property="og:description" content="khoe (Vietnamese, verb): to show something off
11
12## What
13
14It&#39;s a static site generator for your git repos - think [stagit][1], but `git clone`-able. If you ever wanted to share your plain git repos without the security headaches of hosting a dynamic web ser" />
15
16 <link href="/atom.xml" type="application/atom+xml" rel="alternate" title="Sitewide Atom feed" />
17
18 <link rel="stylesheet" href="/_loa/style.css">
19 <script src="/_loa/script.js"></script>
20 </head>
21 <body>
22 <main>
23<a href="/">« back to home</a>
24<span class="post--published-at">
25 published
26 <time class="relative" datetime="2025-10-09T21:13:03+07:00" title="2025-10-09T21:13:03+07:00">2025-10-09T21:13:03+07:00</time>
27</span>
28<h1 class="post--title">First</h1><p>khoe (Vietnamese, verb): to show something off</p>
29<section id="What">
30<h2>What</h2>
31<p>It&rsquo;s a static site generator for your git repos - think <a href="https://codemadness.org/stagit.html">stagit</a>, but <code>git clone</code>-able. If you ever wanted to share your plain git repos without the security headaches of hosting a dynamic web service, you may like khoe.</p>
32</section>
33<section id="Build">
34<h2>Build</h2>
35<p>We use zig master, which is 0.16.0-dev.393+dd4be26f5 at the time of writing:</p>
36<pre><code class="language-sh"># khoe is hosted on khoe
37git clone https://khoe.thac.loan/khoe
38cd khoe
39zig build -Doptimize=ReleaseSafe
40</code></pre>
41<p>Runtime dependencies (khoe shells out to these commands at runtime):</p>
42<ul>
43<li>
44git
45</li>
46<li>
47<a href="https://github.com/commonmark/cmark">cmark</a>
48</li>
49</ul>
50</section>
51<section id="Use">
52<h2>Use</h2>
53<p>Assuming all of your repos (both normal and bare repos work fine) reside in <code>/srv/git/repos</code>, run:</p>
54<pre><code class="language-sh"># replace 2nd arg with the domain you'll host your site on
55khoe /srv/git/repos http://localhost:8000
56</code></pre>
57<p>Khoe will create 2 things inside this dir:</p>
58<ul>
59<li>
60<code>index.html</code>: the home page
61</li>
62<li>
63<code>_</code> (underscore): the directory that stores the rest of the generated html
64</li>
65</ul>
66<p>This <code>repos</code> dir is now serveable as a static website. For a quick preview, try <code>python3 -m http.server -b localhost -d /srv/git/repos</code>. People can <code>git clone</code> repos from this site too.</p>
67<p>Please <strong>make sure there&rsquo;s nothing sensitive in your repos dir</strong> before exposing it to the unwashed public. Git hooks, config, etc. are the usual suspects.</p>
68<p>You can now either serve the dir as-is using caddy/nginx/etc., or rsync it to a remote server, or serve it on s3 if you like burning your (employer&rsquo;s) money, or even, get this, make it a git repo itself to host on GitHub Pages for free! I&rsquo;m not saying you should, but you could. Static web hosting is cheap, often free even. The world&rsquo;s your oyster.</p>
69</section>
70<section id="Use-as-git-hook">
71<h2>Use as git hook</h2>
72<p>Simplest way is to setup a global post-update hook like this:</p>
73<pre><code class="language-sh">flock /tmp/khoe khoe .. https://your.site
74</code></pre>
75<p>Using <a href="https://manpages.debian.org/trixie/util-linux/flock.1.en.html">flock</a> ensures that only 1 instance of the script could be running at a time, avoiding race conditions when multiple people could be pushing.</p>
76</section>
77<section id="Quirks">
78<h2>Quirks</h2>
79<p>Nothing is cached. Every page is regenerated every time, except for those in /objects/ (which can also be forced to regenerate with <code>KHOE_FULL_REGEN=1</code>). Computers are fast though so performance hasn&rsquo;t been a problem for me. If it is for you, let me know and we can optimize it.</p>
80<p>Worse still, every repo is regenerated every time. This one I&rsquo;ll fix&hellip; sometime. Khoe should allow choosing a specific repo to regenerate so that it can run efficiently as a post-update git hook. See Roadmap.</p>
81<p>Outdated pages, if not overwritten, are left as-is. Since git itself is an append-only paradigm, deletion is rarely necessary. Security-wise, if you&rsquo;ve accidentally pushed a secret on a public repo, you must consider it compromised forever and perform appropriate credential rotation and whatnot. Deleting the offending pages means nothing in this context. If it bothers you still, feel free to write a script to delete-before-generate, or generate-and-swap if you have lots of nines to maintain - you do you.</p>
82</section>
83<section id="Roadmap">
84<h2>Roadmap</h2>
85<ul class="task-list">
86<li class="unchecked">
87Add CLI arg to choose which repo to regen
88</li>
89<li class="checked">
90Browse tree at HEAD
91</li>
92<li class="checked">
93Browse commits from main history
94</li>
95</ul>
96</section>
97<section id="Contribute">
98<h2>Contribute</h2>
99<p>See <a href="https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/git-no-forge/#submissions">How to interact with a bare git repo</a>. I generally agree with his preferences.</p>
100</section>
101<section id="License">
102<h2>License</h2>
103<p>Copyright © 2025 tri@thac.loan</p>
104<p>This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.</p>
105<p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.</p>
106<p>You should have received a copy of the GNU Affero General Public License along with this program (agpl-3.0.txt). If not, see <a href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a>.</p>
107</section>
108 </main>
109 <footer>
110 <div><a href="/atom.xml">rss feed</a></div>
111 <div>made with <a href="https://khoe.thac.loan/_/loa/" target="_blank">loa</a></div>
112 </footer>
113 </body>
114</html>