diff options
| author | Collin Williams <96917990+bluedragon1221@users.noreply.github.com> | 2026-05-04 09:40:42 -0500 |
|---|---|---|
| committer | Collin Williams <96917990+bluedragon1221@users.noreply.github.com> | 2026-05-04 09:40:42 -0500 |
| commit | 85a2a330f729d70dfce1b81dc69ec15436a3d44c (patch) | |
| tree | c96214d08cf397efbb98c5e67292604395933093 /forgejno.html | |
Initial clean commit
Diffstat (limited to 'forgejno.html')
| -rw-r--r-- | forgejno.html | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/forgejno.html b/forgejno.html new file mode 100644 index 0000000..71246e7 --- /dev/null +++ b/forgejno.html @@ -0,0 +1,148 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>You don't need Forgejo</title> + + <link rel="stylesheet" href="style.css"> + <link rel="stylesheet" href="prose.css"> + <style> + summary { + font-family: 'Gelasio'; + color: #888; + } + summary::marker { + color: #888; + } + + code { + font-size: 1rem; + color: #00ff78; + } + </style> + <script> + function htmlTableOfContents() { + var toc = document.getElementById('toc-list'); + var headings = document.body.querySelectorAll('h1, h2, h3, h4, h5, h6'); + headings.forEach(function (heading, index) { + var link = document.createElement('a'); + link.setAttribute('href', '#'+heading.id.toLowerCase()); + link.textContent = heading.textContent; + + var li = document.createElement('li'); + li.appendChild(link); + + toc.appendChild(li); + }); + } + </script> + </head> + <body onload="htmlTableOfContents();"> + <div class="toc"> + <ul id="toc-list"></ul> + </div> + + <div class="content"> + <h1 id="title">You Don't Need Forgejo</h1> + <p><a href="https://mitchellh.com/writing/ghostty-leaving-github">People</a> + <a href="https://vinyl-cache.org/organization/moving.html">ditching</a> + GitHub after <a href="https://github.blog/news-insights/company-news/an-update-on-github-availability">recent issues</a> + are looking to self-hosting Forgejo as an alternative.</p> + <p>Despite some (poorly disclosed) <a href="https://dustri.org/b/carrot-disclosure-forgejo.html">security issues</a>, I think there's a more fundemental reason why you shouldn't use Forgejo.</p> + <p>If you're just a single person trying to publish your independent coding projects, why do you need: CI, Issue Tracking, Pull Requests, Multi-user account management, etc?</p> + <p>just use <a href="https://git.zx2c4.com/cgit">cgit</a>.</p> + + <h2 id="forge">How do git forges (like GitHub) even work?</h2> + <p>A git forge is basically just a directory of git repositories, served over http or ssh, with a fancy web frontend.</p> + <p>On the server, since the repos don't need to store mutable state (local commits, staged files, etc) they're stored in a special format that's basically just the <code>.git</code> + directory of a normal git repository.</p> + <p>This is called a bare repository.</p> + + <h2 id="cgit">What is cgit?</h2> + <p>cgit is essentially just a web-based frontend for these bare repos.</p> + <p>While full-on software forges (like GitHub or Forgejo) give you many extra features, cgit is just the read-only frontend, with nothing else included.</p> + <p>Interested?</p> + + <h2 id="guide">cgit Setup Guide</h2> + <p>The cgit setup process is fairly involved, but if you were planning on self-hosting Forgejo, then you can handle it.</p> + <p class="comment">I'll be using Caddy as the webserver for this setup, but I'll link tutorials for NGINX and Apache if prefer xml configuration files and manual https certificates ;)</p> + + <p>To keep everything organized, I'll run cgit under a user called "git". Our git repos will be stored in this directory.</p> + <p><code>$ useradd -r -d /var/lib/cgit -s /usr/bin/git-shell git</code></p> + + <h3 id="cfg-fcgiwrap">fcgiwrap</h3> + <p>cgit is served as a <a href="https://en.wikipedia.org/wiki/Common_Gateway_Interface">cgi application</a>.</p> + <p>A long time ago in a galaxy far far away, web servers had builtin support for cgi, but now its often delegated to <a href="https://github.com/gnosek/fcgiwrap">fcgiwrap</a>.</p> + <p>So our first step will be setting up fcgiwrap.</p> + + <ol> + <li><p>Install fcgiwrap with a package manager. This will create two systemd files: fcgiwrap.service and fcgiwrap.socket.</p></li> + <li><p>Open fcgiwrap.service in a text editor (<code>$ systemctl edit fcgiwrap.service</code>) and set the User and Group to be our "git" user.</p></li> + <li><p>Open fcgiwrap.socket (<code>$ systemctl edit fcgiwrap.socket</code>) and add "SocketUser=caddy" and "SocketGroup=caddy" under the [Socket] section. (replace with the correct Caddy user for your system)</p></li> + </ol> + + <h3 id="cfg-cgit">cgit</h3> + <p>Since cgit is a cgi application, it does not run as its own service. It is simply a script that gets executed by Caddy and piped into fcgiwrap. As such, the setup is pretty simple:</p> + <ol> + <li><p>Install cgit with a package manager. This will place the cgit files at /var/www/htdocs/cgit</p></li> + <li> + <p>Make sure that location is owned by "git", but is readable by all users:</p> + <p><code>$ chown -R git /var/www/htdocs/cgit && chmod -R 764 /var/www/htdocs/cgit</code></p> + </li> + </ol> + + <h3 id="cfg-caddy">Caddy</h3> + <p>To complete the set up, add this block to the Caddyfile to serve cgit.</p> + <pre><code>git.my.tld { + @assets path /cgit.css /cgit.js /favicon.svg /robots.txt + handle @assets { + root * /var/www/htdocs/cgit + file_server + } + + reverse_proxy unix//run/fcgiwrap-cgit.sock { + transport fastcgi { + env SCRIPT_FILENAME /var/www/htdocs/cgit/cgit.cgi + } + } +}</code></pre> + + <h3 id="cfg-shell">Lock down SSH access</h3> + <p>Using <code>git-shell</code> + blocks normal shell access and allows only git-style SSH commands.</p> + <ol> + <li><p>Create an SSH directory for the <code>git</code> + user: <code>$ install -d -o git -g git -m 700 /var/lib/cgit/.ssh</code></p></li> + <li><p>Add your public key to <code>/var/lib/cgit/.ssh/authorized_keys</code> + with mode <code>600</code>.</p></li> + </ol> + + <h3 id="cfg-repos">Create some repos</h3> + <p>Create a bare repository:</p> + <p><code>$ sudo -u git git init --bare /var/lib/cgit/example</code></p> + <p>Push to it from your local machine:</p> + <pre><code>$ git remote add origin git@git.my.tld:example +$ git push -u origin main</code></pre> + + <h3 id="cfg-cgitrc">cgitrc</h3> + <p>A clean default /etc/cgitrc file might look like this:</p> + <pre><code>css=/cgit.css +logo= +virtual-root=/ + +enable-index-owner=0 +enable-http-clone=1 +scan-path=/var/lib/cgit + +root-title=git.my.tld +root-desc=Personal git repositories +snapshots=tar.gz zip</code></pre> + + <h2 id="tradeoffs">Tradeoffs</h2> + <p>You lose integrated issues, pull requests, built-in CI, orgs, and a social graph.</p> + <p>In return, you get a tiny stack, fewer moving parts, lower attack surface, lower resource use, and a setup you can understand.</p> + <p>For my personal projects, that trade is acceptable.</p> + </div> + </body> +</html> |
