<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[🚀 Unseen Servant: Server for Gopher, Gemini, Spartan, Nex, Finger and HTML - Community package now available]]></title><description><![CDATA[<blockquote>
<p dir="auto"><strong>TL;DR:</strong> Unseen Servant publishes one folder of plain text to Gemini, Gopher, Spartan, Nex and Finger at once, and mirrors the same pages to the web. No build step, and nothing executed, ever. Human architected, AI coded. Packaged for Cloudron; unofficial and community-maintained; built and tested on Cloudron 9.x.</p>
</blockquote>
<p dir="auto"><img src="/assets/uploads/files/1788171209056-logo-512.png" alt="logo-512.png" class=" img-fluid img-markdown" width="512" height="512" /></p>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/2728.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--sparkles" style="height:23px;width:auto;vertical-align:middle" title="✨" alt="✨" /> What it does</h3>
<ul>
<li>Six surfaces, one content tree: Gemini on 1965 with Titan uploads on the same listener, the web mirror, and, each off until you switch it on, Gopher, Spartan, Nex and Finger.</li>
<li>Rendering happens when a file changes, not per request. Save a page and it is live everywhere a couple of seconds later, with no second copy to keep in step. The rendered HTML tree is a self-contained static site you can copy anywhere.</li>
<li>The cleartext protocols cannot leak gated content: anything behind a certificate zone is excluded from the Gopher, Spartan, Nex and Finger trees when they are built, because those protocols cannot authenticate a reader at all.</li>
<li>Identity that survives the platform: the certificate is minted once per hostname and never silently replaced, through updates, backups, restores and domain moves, so readers who pinned it stay undisturbed.</li>
<li>Agents are first class: an automated publisher presents a client certificate rather than a password or API key, every read-only command emits JSON, and <code>/llms.txt</code> with Markdown siblings serves machine readers.</li>
<li>What it refuses, permanently: CGI, scripting, proxying, plugin APIs, an admin panel, and visitor address logging by default. Content is data, never code.</li>
<li>The design started by reading the field: Agate's certificate lifecycle, Molly Brown's certificate zones, GmCapsule's Titan handling, gmid's testing discipline and the gopher servers' menu conventions, each credited in the repository with what was declined and why.</li>
</ul>
<h3>Links</h3>
<ul>
<li><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f3e0.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--house" style="height:23px;width:auto;vertical-align:middle" title="🏠" alt="🏠" /> Project site: <a href="https://unseenservant.dev/" target="_blank" rel="noopener noreferrer nofollow ugc">https://unseenservant.dev/</a></li>
<li><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4e6.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--package" style="height:23px;width:auto;vertical-align:middle" title="📦" alt="📦" /> Source and issues: <a href="https://forgejo.unseenservant.dev/unseen-servant/unseen-servant" target="_blank" rel="noopener noreferrer nofollow ugc">https://forgejo.unseenservant.dev/unseen-servant/unseen-servant</a></li>
<li>🪞 GitHub mirror: <a href="https://github.com/OrcVole/unseen-servant" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/OrcVole/unseen-servant</a></li>
</ul>
<p dir="auto">The site is the demonstration: the page you land on is served by the software, from one folder, on every protocol it supports, and its front page opens with the facts (version, licence, packages, networks, lineage) before it asks you to read a word of prose. Swap <code>https://</code> for <code>gemini://</code> on the same address and you are reading the same file.</p>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4e5.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--inbox_tray" style="height:23px;width:auto;vertical-align:middle" title="📥" alt="📥" /> How to install</h3>
<p dir="auto">Click the <strong>Add custom app</strong> dropdown (top right in the App Store) and choose <strong>Community app</strong>, then paste the CloudronVersions.json URL into the box that pops up. Apps installed this way receive automatic updates.</p>
<p dir="auto"><img src="/assets/uploads/files/1782552307466-community-package.jpeg" alt="community-package.jpeg" class=" img-fluid img-markdown" width="1024" height="471" /></p>
<p dir="auto"><img src="/assets/uploads/files/1782552321764-cloudronversions.jpeg" alt="cloudronversions.jpeg" class=" img-fluid img-markdown" width="631" height="249" /></p>
<pre><code class="language-text">https://raw.githubusercontent.com/OrcVole/unseen-servant/main/CloudronVersions.json
</code></pre>
<p dir="auto">Or with the CLI:</p>
<pre><code class="language-bash">cloudron install \
  --versions-url https://raw.githubusercontent.com/OrcVole/unseen-servant/main/CloudronVersions.json \
  --location capsule.example.com
</code></pre>
<p dir="auto"><strong>Minimums:</strong> 256 MiB RAM, <code>localstorage</code> only. No database, no extra subdomain. Cloudron 9.1 or newer.</p>
<p dir="auto"><strong>First run:</strong> there is no login, which is the point: no admin panel means no credential to leak and no login page to probe. The app writes a starter capsule and serves it immediately; you edit the content folder through the dashboard's File Manager. The Gemini port is fixed at 1965 because every client assumes it; the other four protocols are optional ports in the app's settings, served above 1024 because their canonical ports are privileged.</p>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f464.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--bust_in_silhouette" style="height:23px;width:auto;vertical-align:middle" title="👤" alt="👤" /> For users</h3>
<p dir="auto">The small internet is genuinely nice to write for, and the usual barrier is that publishing there means picking one protocol and one server, then maintaining a second copy for people who only have a browser. Here one folder of plain text is the whole workflow: gemtext in, every surface out, within seconds of saving.</p>
<p dir="auto">Good fit if you keep a gemlog, or want one, and would rather not run five daemons. Not a fit if you need a general-purpose web server: this one refuses dynamic anything, permanently and by design, and its own site will tell you which of Agate, gmid, Molly Brown or GmCapsule to run instead.</p>
<p dir="auto">Cloudron specifics worth having: backups include the server identity, so a restore brings back the same certificate your readers pinned; all state is one directory under <code>/app/data</code>.</p>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f916.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--robot_face" style="height:23px;width:auto;vertical-align:middle" title="🤖" alt="🤖" /> On authorship</h3>
<p dir="auto">Human architected, AI coded</p>
<p dir="auto">What is offered instead of trust: every design decision recorded in writing before the code, the research published, a wire-level test suite, eight fuzzed parsers, and a conformance run against the live deployment. It is a first release and not independently audited; Agate and gmid have years of production hardening this does not, and the project's own comparison page says so.</p>
<h3>🧰 For packagers: what we learned</h3>
<p dir="auto"><strong>What helped:</strong> the app is a single static binary with no database and no supervisor, so the whole package is a Dockerfile, a <code>start.sh</code> and the manifest; <code>localstorage</code> covered every persistence need.</p>
<p dir="auto"><strong>What was tricky:</strong> four real ones. The conventional ports for Gopher, Finger and Spartan (70, 79, 300) are privileged and <code>tcpPorts</code> refuses them, so the package publishes 1024, 7979 and 3300 instead. Port 3000 is also refused as reserved, which is not in the manifest documentation and only surfaces as a 400 at install time. <code>tcpPorts</code> entries marked <code>readOnly</code> cannot be moved, which means two installs of this app cannot coexist on one box, correct here but worth knowing. And the health check has to stay green when an admin disables the Gemini port, or the app hangs in "Starting…" because of a protocol-side setting.</p>
<p dir="auto"><strong>Still rough:</strong> the first install from a versions URL onto a fresh subdomain is the path with the least mileage on it, and confirmations from anyone who tries it are welcome.</p>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f6e0.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--hammer_and_wrench" style="height:23px;width:auto;vertical-align:middle" title="🛠" alt="🛠" />️ For the Cloudron team</h3>
<p dir="auto"><strong>Maintenance burden:</strong> light. The package carries no patches, the binary has no runtime dependencies, and the scope is deliberately fixed: new protocols are a versioned decision, not organic growth.</p>
<p dir="auto"><strong>Why it suits the App Store:</strong> the niche, the package is small: 256 MiB and a few megabytes on disk.</p>
<p dir="auto"><strong>Friction worth knowing:</strong> the community-install validator requires <code>iconUrl</code>, <code>mediaLinks</code> and <code>packagerUrl</code>, none of which are in the manifest's own documented field list, and each is discovered as a separate 400 during install. <code>iconUrl</code> additionally forces <code>minBoxVersion</code> to 9.1.0 or newer, a compatibility floor imposed by a metadata field rather than by anything the app does. A single validation pass listing all missing fields at once would have saved several round trips.</p>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f513.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--unlock" style="height:23px;width:auto;vertical-align:middle" title="🔓" alt="🔓" /> Unlocks</h3>
<p dir="auto">A gemlog on your Cloudron that someone in Lagrange, someone in a gopher client from the nineties, and someone who only clicked a link in an email all read from the same files, with no second server and no publishing step.</p>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/1f517.png?v=7ef023c521e" class="not-responsive emoji emoji-android emoji--link" style="height:23px;width:auto;vertical-align:middle" title="🔗" alt="🔗" /> Synergies</h3>
<p dir="auto"><strong>Unseen Servant + Forgejo or Gitea:</strong> keep the content in a git repository, pull it into the content folder, and the same tree is a website, a capsule and a gopherhole with no build between them.</p>
<p dir="auto"><strong>Unseen Servant + Miniflux or FreshRSS:</strong> it writes Atom, so your own gemlog is subscribable in the reader you already run.</p>
<p dir="auto"><strong>Unseen Servant + Surfer:</strong> if you already publish static HTML with Surfer, this adds the small-network surfaces from the same source files rather than replacing anything.</p>
<p dir="auto">Feedback, bug reports, and "works on our install" confirmations all welcome.</p>
]]></description><link>https://forum.cloudron.io/topic/15882/unseen-servant-server-for-gopher-gemini-spartan-nex-finger-and-html-community-package-now-available</link><generator>RSS for Node</generator><lastBuildDate>Mon, 21 Sep 2026 16:55:40 GMT</lastBuildDate><atom:link href="https://forum.cloudron.io/topic/15882.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 31 Aug 2026 10:15:50 GMT</pubDate><ttl>60</ttl></channel></rss>