Splux Linux

source-based Linux using SPS

splux-site · log · files · refs · tags · releases · people · languages · GitHub · commit

e9f0f6d


Make Splux Git the official source on the public site.

Date
Commite9f0f6d670c42f6b9c5500047f2b469b50301827
GitHubmirror

Parents

Stat

 README.md                   | 17 +++++++++----
 forgejo/README.md           | 14 ++++++----
 forgejo/import-repos.sh     | 62 +++++++++++++++++++++++++++++++++++++++++++++
 site/assets/git.js          |  9 ++++---
 site/assets/live.js         | 26 +++++++++++++++----
 site/docs/images/index.html |  2 +-
 site/docs/index.html        | 12 ++++-----
 site/docs/sps/index.html    | 12 ++++++---
 site/download/index.html    |  2 +-
 site/git/index.html         | 28 ++++++++++----------
 site/index.html             | 29 +++++++++++----------
 site/install/index.html     |  2 +-
 site/news/index.html        |  4 +--
 site/packages/index.html    |  2 +-
 site/source/index.html      | 18 ++++++-------
 tools/build-site.sh         | 17 +++++++------
 tools/collect-news.sh       | 19 ++++++++------
 tools/packages.awk          | 19 +++++++++++---
 18 files changed, 202 insertions(+), 92 deletions(-)

Diff

diff --git a/README.md b/README.md
index 2f233b2..c9a0a6b 100644
--- a/README.md
+++ b/README.md
@@ -42,12 +42,13 @@ registered in `tools/build-site.sh` with the correct `../../../../` depth.
 
 ## News
 
-`news/` is generated at build time from GitHub, not edited by hand:
+`news/` is generated at build time from GitHub metadata and local git
+history, not edited by hand:
 
 - every published SPS live ISO release (`RobertFlexx/SPS` GitHub Releases)
 - every commit on SPS, sps-core, sps-extra, and this repository that
   Git or the GitHub API can see, with author and whether GitHub verified
-  the signature
+  the signature. Commit links point at Splux Git.
 
 The news feed splits into pages of twenty items. Each page is a real
 URL (`/news/`, `/news/2/`, ...). Times in the page HTML are UTC; the
@@ -77,11 +78,17 @@ repository there. `SITE_PREFIX` stays empty so links are rooted at `/`.
 ## Git
 
 `/git/` is the public forge page. Canonical clone, accounts, and pull
-requests belong on Splux Git (`git.splux.robertflexx.dev` once that name
-has DNS and TLS). GitHub stays a mirror of git history. The Forgejo
-theme and installer live in `forgejo/`.
+requests belong on Splux Git (`https://git.splux.robertflexx.dev`).
+GitHub stays a mirror of git history. Live ISO files stay on GitHub
+Releases. The Forgejo theme and installer live in `forgejo/`.
+
+Point a DNS A or AAAA record for `git.splux` at the host that runs
+Forgejo, then put TLS in front of port 3000 (or a tunnel) and set
+`ROOT_URL` to `https://git.splux.robertflexx.dev/`. Until that name
+answers, the handbook page still lists GitHub clone URLs.
 
 ```sh
 sh forgejo/install.sh
+sh forgejo/import-repos.sh
 ```
 
diff --git a/forgejo/README.md b/forgejo/README.md
index c9e074e..7ad5031 100644
--- a/forgejo/README.md
+++ b/forgejo/README.md
@@ -18,12 +18,16 @@ the admin account yourself (the installer does not set a password):
   --admin --password 'your-password'
 ```
 
-Then in the web UI, migrate SPS, sps-core, sps-extra, and splux-site
-from GitHub.
+Then import SPS, sps-core, sps-extra, and splux-site from GitHub:
 
-The public handbook page is `/git/`. Clone URLs on the internet still
-use GitHub until `git.splux.robertflexx.dev` has DNS and TLS in front of
-this process. LAN:
+```sh
+sh forgejo/import-repos.sh
+```
+
+The public handbook page is `/git/`. That page is official on the
+site. Clone URLs on the internet still use GitHub until
+`git.splux.robertflexx.dev` has DNS and TLS in front of this process.
+LAN:
 
 ```sh
 git clone http://10.0.0.139:3000/RobertFlexx/SPS.git
diff --git a/forgejo/import-repos.sh b/forgejo/import-repos.sh
new file mode 100755
index 0000000..70cb588
--- /dev/null
+++ b/forgejo/import-repos.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Import official GitHub trees into Splux Git. No tokens.
+# Usage: sh forgejo/import-repos.sh
+set -eu
+
+FORGE=${FORGE:-/home/robert/splux-forge}
+BIN=$FORGE/bin/forgejo
+DATA=$FORGE/data
+DUMP=${DUMP:-/tmp/fj-dump}
+FJ() {
+	"$BIN" -w "$DATA" "$@"
+}
+
+already() {
+	curl -sf -o /dev/null "http://127.0.0.1:3000/api/v1/repos/RobertFlexx/$1"
+}
+
+import_one() {
+	name=$1
+	url=$2
+	if already "$name"
+	then
+		printf '%s\n' "already in forge: $name" >&2
+		return 0
+	fi
+	unitdir=$DUMP/RobertFlexx/$name
+	if [ ! -f "$unitdir/repo.yml" ]; then
+		workdir=$(mktemp -d "$DUMP/work.XXXXXX")
+		printf '%s\n' "dumping $name" >&2
+		FJ dump-repo \
+			--git_service github \
+			--clone_addr "$url" \
+			--owner_name RobertFlexx \
+			--repo_name "$name" \
+			--repo_dir "$workdir" \
+			--units labels,releases,milestones
+		mkdir -p "$DUMP/RobertFlexx"
+		if [ -d "$workdir/RobertFlexx/$name" ]; then
+			rm -rf "$unitdir"
+			mv "$workdir/RobertFlexx/$name" "$unitdir"
+		fi
+		rm -rf "$workdir"
+	fi
+	[ -f "$unitdir/repo.yml" ] || {
+		printf '%s\n' "dump missing $unitdir/repo.yml" >&2
+		return 1
+	}
+	printf '%s\n' "restoring $name" >&2
+	FJ restore-repo \
+		--owner_name RobertFlexx \
+		--repo_name "$name" \
+		--repo_dir "$unitdir" \
+		--units labels,releases,milestones
+	printf '%s\n' "imported $name" >&2
+}
+
+mkdir -p "$DUMP"
+import_one SPS https://github.com/RobertFlexx/SPS.git
+import_one sps-core https://github.com/RobertFlexx/sps-core.git
+import_one sps-extra https://github.com/RobertFlexx/sps-extra.git
+import_one splux-site https://github.com/RobertFlexx/splux-site.git
+printf '%s\n' "import done" >&2
diff --git a/site/assets/git.js b/site/assets/git.js
index 19d65d2..bee9d2c 100644
--- a/site/assets/git.js
+++ b/site/assets/git.js
@@ -50,16 +50,17 @@
 		}).then(function (v) {
 			var ver = (v && (v.version || v.forgejo)) || "up";
 			status.innerHTML = "reachable (" + esc(String(ver)) + ")";
+		}).catch(function () {
+			status.textContent =
+				"not reachable from this browser yet; clone GitHub until DNS and TLS exist";
 			var rows = document.querySelectorAll("#git-repos tr[data-repo]");
 			for (var j = 0; j < rows.length; j++) {
 				var name = rows[j].getAttribute("data-repo");
 				var a = rows[j].querySelector("a.name");
 				if (a && name)
-					a.setAttribute("href", gitHost + "/RobertFlexx/" + name);
+					a.setAttribute("href",
+						"https://github.com/RobertFlexx/" + name);
 			}
-		}).catch(function () {
-			status.textContent =
-				"not reachable from this browser yet; clone GitHub until DNS and TLS exist";
 		});
 	}
 
diff --git a/site/assets/live.js b/site/assets/live.js
index 520c63f..ce633ae 100644
--- a/site/assets/live.js
+++ b/site/assets/live.js
@@ -20,6 +20,9 @@
 	var thisScript = document.currentScript ||
 		document.querySelector("script[src*=\"live.js\"]");
 	var dataRoot = (thisScript && thisScript.getAttribute("data-root")) || "./";
+	var gitHost = (thisScript && thisScript.getAttribute("data-git")) ||
+		"https://git.splux.robertflexx.dev";
+	gitHost = String(gitHost).replace(/\/+$/, "");
 	if (!feed && !brief && !isoEl && !tagEl)
 		return;
 
@@ -118,7 +121,7 @@
 				author: a.getAttribute("data-author") || "",
 				verified: a.getAttribute("data-verified") === "yes",
 				avatar: a.getAttribute("data-avatar") || "",
-				url: link.getAttribute("href") || "",
+				url: forgeCommitHref(link.getAttribute("href") || ""),
 				title: link.textContent || "",
 				summary: summary ? summary.textContent : ""
 			});
@@ -141,7 +144,7 @@
 				author: it.author || "",
 				verified: !!it.verified,
 				avatar: it.avatar || "",
-				url: it.url,
+				url: forgeCommitHref(it.url),
 				title: it.title || "",
 				summary: it.summary || ""
 			});
@@ -316,12 +319,25 @@
 		return sha.length > 7 ? sha.slice(0, 7) : sha;
 	}
 
+	function commitHref(repoPath, sha, htmlUrl) {
+		if (gitHost && repoPath && sha)
+			return gitHost + "/RobertFlexx/" + repoPath + "/commit/" + sha;
+		return htmlUrl || "";
+	}
+
+	function forgeCommitHref(url) {
+		var m = /^https:\/\/github\.com\/RobertFlexx\/([^/]+)\/commit\/([0-9a-fA-F]+)/.exec(String(url || ""));
+		if (m && gitHost)
+			return gitHost + "/RobertFlexx/" + m[1] + "/commit/" + m[2];
+		return url;
+	}
+
 	function setSha(id, repoPath, sha) {
 		var el = document.getElementById(id);
 		if (!el || !sha)
 			return;
-		el.innerHTML = "<a href=\"https://github.com/RobertFlexx/" +
-			esc(repoPath) + "/commit/" + esc(sha) + "\">" +
+		el.innerHTML = "<a href=\"" +
+			esc(commitHref(repoPath, sha, "")) + "\">" +
 			esc(shortSha(sha)) + "</a>";
 	}
 
@@ -468,7 +484,7 @@
 				author: author,
 				verified: !!ver.verified,
 				avatar: (c.author && c.author.avatar_url) || "",
-				url: c.html_url || "",
+				url: forgeCommitHref(c.html_url || commitHref(label, c.sha, "")),
 				title: firstLine(commit.message),
 				summary: ""
 			});
diff --git a/site/docs/images/index.html b/site/docs/images/index.html
index f702d12..2048e52 100644
--- a/site/docs/images/index.html
+++ b/site/docs/images/index.html
@@ -17,7 +17,7 @@
 <main id="main">
 <h2>Live images</h2>
 <hr class="rule">
-<p>Images are hybrid ISOs from <a href="https://github.com/RobertFlexx/SPS">RobertFlexx/SPS</a>. Filenames stay the same; the current tag is <a href="https://github.com/RobertFlexx/SPS/releases/latest">live-2026-09-06-1</a> (2026-09-06). Verify against <a href="https://github.com/RobertFlexx/SPS/releases/latest/download/SHA256SUMS">SHA256SUMS</a>.</p>
+<p>Images are hybrid ISOs from <a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS">RobertFlexx/SPS</a>. Filenames stay the same; the current tag is <a href="https://github.com/RobertFlexx/SPS/releases/latest">live-2026-09-06-1</a> (2026-09-06). Verify against <a href="https://github.com/RobertFlexx/SPS/releases/latest/download/SHA256SUMS">SHA256SUMS</a>.</p>
 <p>Every image includes SPS (<code>src</code>, <code>sget</code>, <code>mkpkg</code>, <code>pkin</code>, <code>setup</code>, <code>mkiso</code>, and the rest), <code>dialog</code>, disk tools, <code>dhcpcd</code>, <code>grub-install</code>, and <code>grub-mkconfig</code>. Live PID 1 is busybox init on published snapshots. <code>/bin/sh</code> is busybox. Login is <code>root</code> with an empty password.</p>
 
 <table class="docs">
diff --git a/site/docs/index.html b/site/docs/index.html
index d8c940b..d37ac0e 100644
--- a/site/docs/index.html
+++ b/site/docs/index.html
@@ -55,12 +55,12 @@
 <h3>Reference trees</h3>
 <ul class="plain">
 <li><a href="../../../../packages/">Package browser</a> (1474 packages)</li>
-<li><a href="https://github.com/RobertFlexx/SPS/blob/main/README.md">SPS README</a></li>
-<li><a href="https://github.com/RobertFlexx/SPS/blob/main/DESIGN.md">SPS 1.0 formats and behavior</a></li>
-<li><a href="https://github.com/RobertFlexx/SPS/blob/main/man/setup.1">setup(1)</a></li>
-<li><a href="https://github.com/RobertFlexx/SPS/blob/main/PACKAGE-MAINTAINER.md">Package maintainer guide</a></li>
-<li><a href="https://github.com/RobertFlexx/sps-core/blob/main/README.md">core collection</a></li>
-<li><a href="https://github.com/RobertFlexx/sps-extra/blob/main/README.md">extra collection</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/README.md">SPS README</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/DESIGN.md">SPS 1.0 formats and behavior</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/man/setup.1">setup(1)</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/PACKAGE-MAINTAINER.md">Package maintainer guide</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-core/src/branch/main/README.md">core collection</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-extra/src/branch/main/README.md">extra collection</a></li>
 <li><a href="../../../../git/">Splux Git</a></li>
 <li><a href="../../../../source/">Source repositories</a></li>
 </ul>
diff --git a/site/docs/sps/index.html b/site/docs/sps/index.html
index b746272..674527a 100644
--- a/site/docs/sps/index.html
+++ b/site/docs/sps/index.html
@@ -56,9 +56,13 @@ unset SPS_DB SPS_CACHE SPS_BUILD SPS_CONFIG SPS_REPOS_CONFIG SPS_REPO_ROOT</pre>
 <p>Leaving those unset is required so they resolve under the target, not under the live root.</p>
 
 <h3>Repositories</h3>
-<p><code>/etc/sps/repos.conf</code> lists trees. Higher priority wins.</p>
+<p><code>/etc/sps/repos.conf</code> lists trees. Higher priority wins. Splux Git is official. Until that name answers, use the GitHub mirrors, not both at once.</p>
 <pre class="block">dir core /usr/src/sps/core 100
 dir extra /usr/src/sps/extra 80
+
+git core https://splux.robertflexx.dev/git/RobertFlexx/sps-core.git 100
+git extra https://splux.robertflexx.dev/git/RobertFlexx/sps-extra.git 80
+
 git core https://github.com/RobertFlexx/sps-core.git 100
 git extra https://github.com/RobertFlexx/sps-extra.git 80</pre>
 <p>On tty and Plasma images the live <code>repos.conf</code> uses <code>dir</code> entries pointing at the bundled trees. Slim images have no recipes, so they use the git lines. <code>src update</code> for a git repo needs <code>git</code>, which slim does not ship.</p>
@@ -92,9 +96,9 @@ sget install curl</pre>
 
 <h3>Further reading</h3>
 <ul class="plain">
-<li><a href="https://github.com/RobertFlexx/SPS/blob/main/README.md">SPS README</a></li>
-<li><a href="https://github.com/RobertFlexx/SPS/blob/main/DESIGN.md">DESIGN.md</a></li>
-<li><a href="https://github.com/RobertFlexx/SPS/blob/main/PACKAGE-MAINTAINER.md">Recipe format</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/README.md">SPS README</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/DESIGN.md">DESIGN.md</a></li>
+<li><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/PACKAGE-MAINTAINER.md">Recipe format</a></li>
 <li><a href="../../../../packages/">Package browser</a></li>
 </ul>
 </main>
diff --git a/site/download/index.html b/site/download/index.html
index 806be2d..94ae8c2 100644
--- a/site/download/index.html
+++ b/site/download/index.html
@@ -15,7 +15,7 @@
 <main id="main">
 <h2>Download</h2>
 <hr class="rule">
-<p>Images are hybrid ISOs from <a href="https://github.com/RobertFlexx/SPS">RobertFlexx/SPS</a>. The filenames below are stable. This page names the current <code>live-*</code> ISO tag and links to that GitHub release.</p>
+<p>Images are hybrid ISOs from <a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS">RobertFlexx/SPS</a>. The filenames below are stable. This page names the current <code>live-*</code> ISO tag and links to that GitHub release.</p>
 <div class="dl-row"><span class="muted">Latest tag</span><span id="live-tag">live-2026-09-06-1</span></div>
 <div class="dl-row"><span class="muted">Released</span><span id="live-date">2026-09-06</span></div>
 <div class="dl-row"><span class="muted">Architecture</span><span>x86_64</span></div>
diff --git a/site/git/index.html b/site/git/index.html
index 93934b5..1bb2df4 100644
--- a/site/git/index.html
+++ b/site/git/index.html
@@ -30,32 +30,40 @@
 </thead>
 <tbody>
 <tr data-repo="SPS">
-<td><a class="name" href="https://github.com/RobertFlexx/SPS">SPS</a></td>
+<td><a class="name" href="https://splux.robertflexx.dev/git/RobertFlexx/SPS">SPS</a></td>
 <td>package system, installer, live ISO builder</td>
 <td class="lang muted">Shell</td>
 <td class="pushed muted"></td>
 </tr>
 <tr data-repo="sps-core">
-<td><a class="name" href="https://github.com/RobertFlexx/sps-core">sps-core</a></td>
+<td><a class="name" href="https://splux.robertflexx.dev/git/RobertFlexx/sps-core">sps-core</a></td>
 <td>official base recipes</td>
 <td class="lang muted">Shell</td>
 <td class="pushed muted"></td>
 </tr>
 <tr data-repo="sps-extra">
-<td><a class="name" href="https://github.com/RobertFlexx/sps-extra">sps-extra</a></td>
+<td><a class="name" href="https://splux.robertflexx.dev/git/RobertFlexx/sps-extra">sps-extra</a></td>
 <td>official extra recipes</td>
 <td class="lang muted">Shell</td>
 <td class="pushed muted"></td>
 </tr>
 <tr data-repo="splux-site">
-<td><a class="name" href="https://github.com/RobertFlexx/splux-site">splux-site</a></td>
+<td><a class="name" href="https://splux.robertflexx.dev/git/RobertFlexx/splux-site">splux-site</a></td>
 <td>this website</td>
 <td class="lang muted">HTML</td>
 <td class="pushed muted"></td>
 </tr>
 </tbody>
 </table>
-<p class="note">If the forge link does not answer yet, use the GitHub clone URLs below. The trees are the same commits.</p>
+<p class="note">Splux Git is the official clone URL. If that name does not answer yet, use the GitHub mirrors. The trees are the same commits.</p>
+
+<h2>Clone (Splux Git)</h2>
+<hr class="rule">
+<p>Official URLs. They need DNS and TLS on <code>git.splux.robertflexx.dev</code>, or a host on the LAN that already runs the forge.</p>
+<pre class="block">git clone https://splux.robertflexx.dev/git/RobertFlexx/SPS.git
+git clone https://splux.robertflexx.dev/git/RobertFlexx/sps-core.git
+git clone https://splux.robertflexx.dev/git/RobertFlexx/sps-extra.git
+git clone https://splux.robertflexx.dev/git/RobertFlexx/splux-site.git</pre>
 
 <h2>Clone (GitHub mirror)</h2>
 <hr class="rule">
@@ -65,14 +73,6 @@ git clone https://github.com/RobertFlexx/sps-core.git
 git clone https://github.com/RobertFlexx/sps-extra.git
 git clone https://github.com/RobertFlexx/splux-site.git</pre>
 
-<h2>Clone (Splux Git)</h2>
-<hr class="rule">
-<p>Use these when <code>git.splux.robertflexx.dev</code> has DNS and TLS, or from the LAN that runs the forge.</p>
-<pre class="block">git clone https://splux.robertflexx.dev/git/RobertFlexx/SPS.git
-git clone https://splux.robertflexx.dev/git/RobertFlexx/sps-core.git
-git clone https://splux.robertflexx.dev/git/RobertFlexx/sps-extra.git
-git clone https://splux.robertflexx.dev/git/RobertFlexx/splux-site.git</pre>
-
 <h2>Pull requests</h2>
 <hr class="rule">
 <p>Open them on Splux Git. GitHub does not receive pull requests, issues, or accounts. A push mirror copies commits, branches, and tags only.</p>
@@ -83,7 +83,7 @@ git clone https://splux.robertflexx.dev/git/RobertFlexx/splux-site.git</pre>
 <ul class="plain">
 <li>Live ISO files and SHA256SUMS</li>
 <li>This handbook (GitHub Pages)</li>
-<li>The news feed GitHub API calls</li>
+<li>News metadata from the GitHub API (commit links still point at Splux Git)</li>
 </ul>
 </main>
 @@FOOTER@@
diff --git a/site/index.html b/site/index.html
index 3784f59..10fd030 100644
--- a/site/index.html
+++ b/site/index.html
@@ -69,34 +69,35 @@ pkin: installed curl 8.21.0-2</pre>
 
 <h2 id="repos"><span class="num">[004]</span> Repositories</h2>
 <hr class="rule">
-<p><a href="../../../../git/">core</a><br>
-Base system, toolchain, libraries, boot, filesystems, and networking. 119 packages.</p>
-<p><a href="../../../../git/">extra</a><br>
-Desktop software, graphics, multimedia, development tools, and other packages. 1355 packages.</p>
-<p>SPS also supports administrator-maintained local repositories in addition to the official trees.</p>
+<p><a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-core">sps-core</a><br>
+Base system, toolchain, libraries, boot, filesystems, and networking. 119 packages. GitHub mirror: <a href="https://github.com/RobertFlexx/sps-core">RobertFlexx/sps-core</a>.</p>
+<p><a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-extra">sps-extra</a><br>
+Desktop software, graphics, multimedia, development tools, and other packages. 1355 packages. GitHub mirror: <a href="https://github.com/RobertFlexx/sps-extra">RobertFlexx/sps-extra</a>.</p>
+<p>SPS also supports administrator-maintained local repositories in addition to the official trees. Browse recipes from <a href="../../../../git/">Splux Git</a>.</p>
 
 <h2 id="docs"><span class="num">[005]</span> Documentation</h2>
 <hr class="rule">
 <p><a href="../../../../docs/">Handbook</a><br>
 <a href="../../../../install/">Install</a> (setup, manual tty, slim)<br>
 <a href="../../../../docs/images/">Live images</a><br>
-<a href="https://github.com/RobertFlexx/SPS/blob/main/README.md">SPS README</a><br>
-<a href="https://github.com/RobertFlexx/SPS/blob/main/DESIGN.md">SPS 1.0 formats</a></p>
+<a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/README.md">SPS README</a><br>
+<a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/DESIGN.md">SPS 1.0 formats</a></p>
 
 <h2 id="source"><span class="num">[006]</span> Source</h2>
 <hr class="rule">
 <p>
 <a href="../../../../git/">Splux Git</a>
 canonical forge<br>
-<a href="https://github.com/RobertFlexx/SPS">SPS</a>
-the package system (GitHub mirror)<br>
-<a href="https://github.com/RobertFlexx/sps-core">sps-core</a>
+<a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS">SPS</a>
+the package system<br>
+<a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-core">sps-core</a>
 official base recipes<br>
-<a href="https://github.com/RobertFlexx/sps-extra">sps-extra</a>
+<a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-extra">sps-extra</a>
 official extra recipes<br>
-<a href="https://github.com/RobertFlexx/splux-site">splux-site</a>
+<a href="https://splux.robertflexx.dev/git/RobertFlexx/splux-site">splux-site</a>
 this website
 </p>
+<p class="note">GitHub holds a read-only mirror of the same history. Live ISO files still come from GitHub Releases.</p>
 
 <h2 id="status"><span class="num">[007]</span> Project status</h2>
 <hr class="rule">
@@ -109,11 +110,11 @@ this website
 @@NEWS_BRIEF@@
 </div>
 <p><a href="../../../../news/">Full news feed</a> · <a href="../../../../news/atom.xml">Atom</a></p>
-<p class="note">The feed is filled from GitHub when this site builds, and this page also asks GitHub for anything newer when you open it.</p>
+<p class="note">The feed is filled from git history when this site builds. Commit links go to Splux Git. This page also asks GitHub for anything newer when you open it. ISO files stay on GitHub Releases.</p>
 
 </main>
 @@FOOTER@@
 </div>
-<script src="../../../../assets/live.js?v=4c4f12c-20261019130111" data-root="../../../../"></script>
+<script src="../../../../assets/live.js?v=4c4f12c-20261019130111" data-root="../../../../" data-git="https://splux.robertflexx.dev/git"></script>
 </body>
 </html>
diff --git a/site/install/index.html b/site/install/index.html
index 0c19273..300abba 100644
--- a/site/install/index.html
+++ b/site/install/index.html
@@ -106,7 +106,7 @@ setup --non-interactive \
 
 <h4>What setup does</h4>
 <p>It writes hostname, timezone, keymap, locale, and <code>/etc/sps/init</code>, copies bundled recipe trees when they exist, writes <code>sps.conf</code>, runs <code>src update</code>, then <code>sget install</code>. Users land after packages so <code>filesystem</code>'s passwd file is already there. If you passed <code>--install-bootloader</code>, it runs live <code>grub-install</code> (EFI removable <code>EFI/BOOT/BOOTX64.EFI</code>, then NVRAM via <code>efibootmgr</code> when that binary exists; BIOS uses <code>i386-pc</code>). It does not run <code>grub-mkconfig</code>. See <code>/root/sps-bootloader.txt</code> on the target.</p>
-<p>A Plasma install compiles Qt and KDE and takes a long time. See <a href="https://github.com/RobertFlexx/SPS/blob/main/man/setup.1">setup(1)</a> for every flag.</p>
+<p>A Plasma install compiles Qt and KDE and takes a long time. See <a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS/src/branch/main/man/setup.1">setup(1)</a> for every flag.</p>
 </section>
 
 <section class="tabpanel" role="tabpanel" id="panel-manual" aria-labelledby="tab-manual">
diff --git a/site/news/index.html b/site/news/index.html
index 575cdb8..beb9db0 100644
--- a/site/news/index.html
+++ b/site/news/index.html
@@ -16,7 +16,7 @@
 <main id="main">
 <h2>News</h2>
 <hr class="rule">
-<p>This page is filled from GitHub: every published SPS live ISO release, plus commits on SPS, sps-core, sps-extra, and this website. Nobody has to edit it for a new snapshot or commit to show up.</p>
+<p>This page is filled from git history: every published SPS live ISO release on GitHub, plus commits on SPS, sps-core, sps-extra, and this website. Commit links go to Splux Git. Nobody has to edit it for a new snapshot or commit to show up.</p>
 <p class="note">Times are shown in your local timezone. Commits name the author and whether GitHub verified the signature. Long feeds split into pages of twenty. <a href="../../../../news/atom.xml">Atom feed</a>.</p>
 @@NEWS_INFO@@
 <h2>Feed</h2>
@@ -28,6 +28,6 @@
 </main>
 @@FOOTER@@
 </div>
-<script src="../../../../assets/live.js?v=4c4f12c-20261019130111" data-root="../../../../"></script>
+<script src="../../../../assets/live.js?v=4c4f12c-20261019130111" data-root="../../../../" data-git="https://splux.robertflexx.dev/git"></script>
 </body>
 </html>
diff --git a/site/packages/index.html b/site/packages/index.html
index a0aa6aa..20f7989 100644
--- a/site/packages/index.html
+++ b/site/packages/index.html
@@ -15,7 +15,7 @@
 <main id="main">
 <h2>Packages</h2>
 <hr class="rule">
-<p>Generated from the official <a href="https://github.com/RobertFlexx/sps-core">sps-core</a> and <a href="https://github.com/RobertFlexx/sps-extra">sps-extra</a> recipe trees. 1474 packages (119 core, 1355 extra). Updated 2026-10-19 13:01 UTC. Browse them from <a href="../../../../git/">Splux Git</a>.</p>
+<p>Generated from the official <a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-core">sps-core</a> and <a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-extra">sps-extra</a> recipe trees. 1474 packages (119 core, 1355 extra). Updated 2026-10-19 13:01 UTC. Browse them from <a href="../../../../git/">Splux Git</a>.</p>
 <form id="pkg-search" role="search">
 <label class="search" for="q">Search
 <input id="q" name="q" type="search" autocomplete="off" spellcheck="false">
diff --git a/site/source/index.html b/site/source/index.html
index e97de3e..6ecffd2 100644
--- a/site/source/index.html
+++ b/site/source/index.html
@@ -15,15 +15,15 @@
 <main id="main">
 <h2>Source</h2>
 <hr class="rule">
-<p>Canonical trees belong on <a href="../../../../git/">Splux Git</a>. Until that host has a public name, clone the GitHub mirrors. License for SPS and the package collections is ISC. See each repository.</p>
-<p><a href="https://github.com/RobertFlexx/SPS">SPS</a><br>
-Source Package System. POSIX shell and AWK. Installer and live ISO builder live here too.</p>
-<p><a href="https://github.com/RobertFlexx/sps-core">sps-core</a><br>
-Official base recipe collection.</p>
-<p><a href="https://github.com/RobertFlexx/sps-extra">sps-extra</a><br>
-Official extra recipe collection.</p>
-<p><a href="https://github.com/RobertFlexx/splux-site">splux-site</a><br>
-This website. Static HTML generated from the recipe trees.</p>
+<p>Canonical trees belong on <a href="../../../../git/">Splux Git</a>. GitHub is a read-only mirror of the same history. License for SPS and the package collections is ISC. See each repository.</p>
+<p><a href="https://splux.robertflexx.dev/git/RobertFlexx/SPS">SPS</a><br>
+Source Package System. POSIX shell and AWK. Installer and live ISO builder live here too. GitHub: <a href="https://github.com/RobertFlexx/SPS">RobertFlexx/SPS</a>.</p>
+<p><a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-core">sps-core</a><br>
+Official base recipe collection. GitHub: <a href="https://github.com/RobertFlexx/sps-core">RobertFlexx/sps-core</a>.</p>
+<p><a href="https://splux.robertflexx.dev/git/RobertFlexx/sps-extra">sps-extra</a><br>
+Official extra recipe collection. GitHub: <a href="https://github.com/RobertFlexx/sps-extra">RobertFlexx/sps-extra</a>.</p>
+<p><a href="https://splux.robertflexx.dev/git/RobertFlexx/splux-site">splux-site</a><br>
+This website. Static HTML generated from the recipe trees. GitHub: <a href="https://github.com/RobertFlexx/splux-site">RobertFlexx/splux-site</a>.</p>
 </main>
 @@FOOTER@@
 </div>
diff --git a/tools/build-site.sh b/tools/build-site.sh
index e9c12a3..48d5707 100755
--- a/tools/build-site.sh
+++ b/tools/build-site.sh
@@ -72,7 +72,6 @@ write_header() {
 <a href="${root}git/">git</a>
 <a href="${root}source/">source</a>
 <a href="${root}news/">news</a>
-<a class="gh" href="${SPS_GIT}"><img src="${root}assets/github.svg" width="14" height="14" alt=""> SPS</a>
 </nav>
 EOF
 }
@@ -83,7 +82,7 @@ write_footer() {
 <footer>
 <p>Splux Linux</p>
 <p><a href="${root}">home</a> · <a href="${root}packages/">packages</a> · <a href="${root}git/">git</a> · <a href="${root}docs/">documentation</a></p>
-<p>This site was fully handmade by <a href="https://github.com/RobertFlexx">RobertFlexx</a>.</p>
+<p>This site was fully handmade by <a href="${GIT_HOST}/RobertFlexx">RobertFlexx</a>.</p>
 </footer>
 EOF
 }
@@ -126,6 +125,7 @@ scan_tree() {
 	repo=$1
 	rootdir=$2
 	github=$3
+	mirror=${4-}
 	find "$rootdir" -name recipe -type f | LC_ALL=C sort | while IFS= read -r rec
 	do
 		rel=${rec#"$rootdir"/}
@@ -138,6 +138,7 @@ scan_tree() {
 			-v repo="$repo" \
 			-v pkgpath="$pkgpath" \
 			-v github="$github" \
+			-v mirror="$mirror" \
 			-v outdir="$OUT" \
 			"$rec" >>"$tsv"
 		then
@@ -148,8 +149,8 @@ scan_tree() {
 }
 
 printf '%s\n' "reading recipes" >&2
-scan_tree core "$CORE" "$CORE_GIT"
-scan_tree extra "$EXTRA" "$EXTRA_GIT"
+scan_tree core "$CORE" "$GIT_HOST/RobertFlexx/sps-core" "https://github.com/RobertFlexx/sps-core"
+scan_tree extra "$EXTRA" "$GIT_HOST/RobertFlexx/sps-extra" "https://github.com/RobertFlexx/sps-extra"
 
 LC_ALL=C sort -t "$(printf '\t')" -k1,1 -k5,5 "$tsv" >"$tmp/sorted.tsv"
 mv "$tmp/sorted.tsv" "$tsv"
@@ -247,7 +248,7 @@ short_sha() {
 	git -C "$1" rev-parse --short HEAD 2>/dev/null || printf '%s\n' unknown
 }
 
-export CORE EXTRA SPS SITE
+export CORE EXTRA SPS SITE GIT_HOST
 if ! sh tools/collect-news.sh >"$tmp/news.tsv"
 then
 	printf '%s\n' "warning: news collection failed" >&2
@@ -281,9 +282,9 @@ livesig=${site_sha}-$(date -u '+%Y%m%d%H%M%S' 2>/dev/null || date +%Y%m%d%H%M%S)
 cat >"$tmp/news-info.html" <<EOF
 <div class="info">
 <div class="dl-row"><span class="muted">Latest ISO</span><span id="live-iso"><a href="$notes_url">$tag</a> ($date)</span></div>
-<div class="dl-row"><span class="muted">SPS</span><span id="live-sps"><a href="$SPS_GIT/commit/$sps_sha">$sps_sha</a></span></div>
-<div class="dl-row"><span class="muted">sps-core</span><span id="live-core"><a href="$CORE_GIT/commit/$core_sha">$core_sha</a></span></div>
-<div class="dl-row"><span class="muted">sps-extra</span><span id="live-extra"><a href="$EXTRA_GIT/commit/$extra_sha">$extra_sha</a></span></div>
+<div class="dl-row"><span class="muted">SPS</span><span id="live-sps"><a href="$GIT_HOST/RobertFlexx/SPS/commit/$sps_sha">$sps_sha</a></span></div>
+<div class="dl-row"><span class="muted">sps-core</span><span id="live-core"><a href="$GIT_HOST/RobertFlexx/sps-core/commit/$core_sha">$core_sha</a></span></div>
+<div class="dl-row"><span class="muted">sps-extra</span><span id="live-extra"><a href="$GIT_HOST/RobertFlexx/sps-extra/commit/$extra_sha">$extra_sha</a></span></div>
 <div class="dl-row"><span class="muted">Packages</span><span>$npkgs ($ncore core, $nextra extra)</span></div>
 <div class="dl-row"><span class="muted">Site build</span><span>$generated ($site_sha)</span></div>
 </div>
diff --git a/tools/collect-news.sh b/tools/collect-news.sh
index 7b78130..a42c44f 100755
--- a/tools/collect-news.sh
+++ b/tools/collect-news.sh
@@ -1,10 +1,11 @@
 #!/bin/sh
 # Collect Splux releases and git history into TSV for the news page.
 # Fields: epoch iso kind repo url title summary author verified avatar
-# Env: CORE EXTRA SPS SITE (git work trees). GH_TOKEN optional via gh.
+# Env: CORE EXTRA SPS SITE GIT_HOST (git work trees). GH_TOKEN optional via gh.
 # Pulls every non-draft SPS release and every commit available from the
-# local clones and from the GitHub API. Duplicate URLs keep the last row
-# so GitHub author and verified data win over local git.
+# local clones and from the GitHub API. Commit URLs point at Splux Git.
+# Duplicate URLs keep the last row so GitHub author and verified data
+# win over local git.
 
 set -eu
 
@@ -12,6 +13,8 @@ CORE=${CORE:-vendor/core}
 EXTRA=${EXTRA:-vendor/extra}
 SPS=${SPS:-vendor/sps}
 SITE=${SITE:-.}
+GIT_HOST=${GIT_HOST:-https://git.splux.robertflexx.dev}
+GIT_HOST=${GIT_HOST%/}
 
 tab=$(printf '\t')
 tmp=$(mktemp -d "${TMPDIR:-/tmp}/splux-news.XXXXXX") || exit 1
@@ -100,10 +103,10 @@ read_commit_tsv() {
 	done <"$file"
 }
 
-git_commits "$SPS" SPS https://github.com/RobertFlexx/SPS
-git_commits "$CORE" sps-core https://github.com/RobertFlexx/sps-core
-git_commits "$EXTRA" sps-extra https://github.com/RobertFlexx/sps-extra
-git_commits "$SITE" splux-site https://github.com/RobertFlexx/splux-site
+git_commits "$SPS" SPS "$GIT_HOST/RobertFlexx/SPS"
+git_commits "$CORE" sps-core "$GIT_HOST/RobertFlexx/sps-core"
+git_commits "$EXTRA" sps-extra "$GIT_HOST/RobertFlexx/sps-extra"
+git_commits "$SITE" splux-site "$GIT_HOST/RobertFlexx/splux-site"
 
 if command -v gh >/dev/null 2>&1; then
 	if gh api --paginate "repos/RobertFlexx/SPS/releases?per_page=100" --jq \
@@ -134,7 +137,7 @@ if command -v gh >/dev/null 2>&1; then
 		if gh api --paginate "repos/${path}/commits?per_page=100" --jq \
 			'.[] | [
 				.commit.committer.date,
-				.html_url,
+				("'"$GIT_HOST"'/'"$path"'/commit/" + .sha),
 				((.commit.message // "") | split("\n")[0] | gsub("[\r\t]"; " ")),
 				((.author.login // .commit.author.name // "") | gsub("[\r\t]"; " ")),
 				(if .commit.verification.verified == true then "yes" else "no" end),
diff --git a/tools/packages.awk b/tools/packages.awk
index f5c4c6d..56d92df 100644
--- a/tools/packages.awk
+++ b/tools/packages.awk
@@ -140,9 +140,20 @@ function write_page(    dir, ncomp, i, prefix, parts, cat, page, gh_dir) {
 	list_html(page, "optional dependencies", val["optional"])
 	list_html(page, "conflicts", val["conflict"])
 	print "<p>recipe<br>" > page
-	print "<a href=\"" github "/blob/main/" gh_dir "/recipe\">view recipe</a><br>" > page
-	print "<a href=\"" github "/tree/main/" gh_dir "\">repository directory</a><br>" > page
-	print "<a href=\"" github "/commits/main/" gh_dir "\">history</a></p>" > page
+	if (github ~ /github\.com/) {
+		print "<a href=\"" github "/blob/main/" gh_dir "/recipe\">view recipe</a><br>" > page
+		print "<a href=\"" github "/tree/main/" gh_dir "\">repository directory</a><br>" > page
+		print "<a href=\"" github "/commits/main/" gh_dir "\">history</a>" > page
+	} else {
+		print "<a href=\"" github "/src/branch/main/" gh_dir "/recipe\">view recipe</a><br>" > page
+		print "<a href=\"" github "/src/branch/main/" gh_dir "\">repository directory</a><br>" > page
+		print "<a href=\"" github "/commits/branch/main/" gh_dir "\">history</a>" > page
+	}
+	if (mirror != "") {
+		print "<br>" > page
+		print "<a href=\"" mirror "/blob/main/" gh_dir "/recipe\">GitHub mirror</a>" > page
+	}
+	print "</p>" > page
 	print "</main>" > page
 	print "@@FOOTER@@" > page
 	print "</div></body></html>" > page
@@ -151,7 +162,7 @@ function write_page(    dir, ncomp, i, prefix, parts, cat, page, gh_dir) {
 
 BEGIN {
 	if (repo == "") repo = "unknown"
-	if (github == "") github = "https://github.com/RobertFlexx/sps-core"
+	if (github == "") github = "https://git.splux.robertflexx.dev/RobertFlexx/sps-core"
 	if (pkgpath == "") pkgpath = "unknown"
 }