diff options
| -rw-r--r-- | forgejno.html | 148 | ||||
| -rw-r--r-- | index.html | 99 | ||||
| -rw-r--r-- | prose.css | 119 | ||||
| -rw-r--r-- | style.css | 32 | ||||
| -rw-r--r-- | writing.html | 18 |
5 files changed, 416 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> diff --git a/index.html b/index.html new file mode 100644 index 0000000..5a7ac62 --- /dev/null +++ b/index.html @@ -0,0 +1,99 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Collin Williams</title> + + <link rel="stylesheet" href="style.css"> + <style> + body { + align-items: center; + } + + .content { + width: 47ch; + } + + h1 { + text-align: center; + } + + #bg { + position: fixed; + inset: 0; + pointer-events: none; + } + + .star { + position: absolute; + width: 3px; + height: 3px; + border-radius: 50%; + background: white; + box-shadow: 0 0 4px white; + } + + .cards { + display: flex; + flex-direction: row; + justify-content: space-around; + width: 100%; + } + + .card { + font-family: 'Roboto Mono'; + color: white; + text-decoration: none; + transition: color 0.1s ease; + } + + .card:hover { + color: #4DA3FF; + } + </style> + </head> + <body> + <div id="bg"></div> + <script> + const bg = document.querySelector("#bg"); + for (let i = 0; i < 100; i++) { + const star = document.createElement("div"); + star.classList.add("star"); + + star.x = Math.random() * window.innerWidth; + star.y = Math.random() * window.innerHeight; + + star.vx = (Math.random() - 0.5) * 0.1; + star.vy = (Math.random() - 0.5) * 0.1; + + star.style.left = `${star.x}px`; + star.style.top = `${star.y}px`; + + bg.appendChild(star); + } + + function animate() { + for (const s of bg.children) { + s.x += s.vx; + s.y += s.vy; + + s.style.left = `${s.x}px`; + s.style.top = `${s.y}px`; + } + + requestAnimationFrame(animate); + } + + animate(); + </script> + <div class="content"> + <h1>Collin Williams</h1> + <div class="cards"> + <a class="card" href="https://bsky.app/profile/cwilliams1221.bsky.social">Bluesky</a> + <a class="card" href="https://tangled.org/cwilliams1221.bsky.social">Tangled</a> + <a class="card" href="./writing.html">Writing</a> + </div> + </div> + </body> +</html> diff --git a/prose.css b/prose.css new file mode 100644 index 0000000..a9f6dc1 --- /dev/null +++ b/prose.css @@ -0,0 +1,119 @@ +@import url('https://fonts.googleapis.com/css2?family=Gelasio:ital,wght@0,400..700;1,400..700&display=swap'); + +html, +body { + overflow-x: hidden; + overflow-y: auto; +} + +body { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 75ch) minmax(0, 1fr); + align-items: start; + column-gap: 2rem; + padding: 2rem 1.25rem 4rem; +} + +.toc { + grid-column: 1; + width: min(17rem, 22vw); + position: fixed; + top: 32px; + left: max(0.75rem, calc(50vw - 37.5ch - 20rem)); + max-height: calc(100vh - 2rem); + overflow-y: auto; + padding-right: 0.75rem; + z-index: 1; +} + +.toc ul { + margin: 0; + padding-left: 1rem; +} + +.toc li { + margin-bottom: 0.35rem; +} + +.content { + grid-column: 2; + width: 100%; + margin: 0 auto; + padding: 0 0 2rem; + max-width: 75ch; + height: auto; + flex-grow: 0; + flex-shrink: 1; + overflow: visible; +} + +p { + color: #e6e6e6; + font-family: 'Gelasio'; + line-height: 1.3; + font-size: 1.1rem; +} + +a { + color: #4DA3FF; + transition: color 0.2s ease, background-color 0.2s ease; +} + +a:hover { + background-color: #4DA3FF; + color: #121212; + text-decoration: none; +} + +li::marker { + color: #e6e6e6; +} + +h1 { + color: #e6e6e6; + line-height: 1; + margin-bottom: 0; + font-family: 'Gelasio'; + font-weight: 600; +} + +h2 { + color: #e6e6e6; + line-height: 1; + margin-top: 3rem; + margin-bottom: 0; + font-family: 'Gelasio'; + font-weight: 600; +} + +h3 { + color: #e6e6e6; + line-height: 1; + margin-top: 2rem; + margin-bottom: 0; + font-family: 'Gelasio'; + font-weight: 600; +} + +p.comment { + color: #888; +} + +@media (max-width: 1000px) { + body { + display: block; + padding: 1rem 1rem 3rem; + } + + .toc { + position: static; + width: auto; + max-height: none; + margin-bottom: 1.25rem; + padding-right: 0; + } + + .content { + padding: 0; + } +} diff --git a/style.css b/style.css new file mode 100644 index 0000000..43a6973 --- /dev/null +++ b/style.css @@ -0,0 +1,32 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap'); + +*, *::before, *::after { + box-sizing: border-box; +} + +html, body { + background-color: #121212; + margin: 0; + padding: 0; + min-height: 100vh; + overflow: hidden; +} + +body { + display: flex; + justify-content: center; + align-items: flex-start; +} + +h1 { + font-family: 'Roboto Mono'; + color: #e6e6e6; + line-height: 1; + margin: 0; + margin-bottom: 1.5rem; +} + +p { + font-family: 'Roboto Mono'; + color: #e6e6e6; +} diff --git a/writing.html b/writing.html new file mode 100644 index 0000000..d95ba16 --- /dev/null +++ b/writing.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Writing</title> + + <link rel="stylesheet" href="style.css"> + <link rel="stylesheet" href="prose.css"> + </head> + <body> + <div class="content"> + <ul> + <li><p><a href="./forgejno.html">You Don't Need Forgejo</a></p></li> + </ul> + </div> + </body> +</html> |
