Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cloud.html
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,18 @@ <h3>Cloud advanced</h3>

<section id="mesh" aria-labelledby="mesh-title">
<h2 id="mesh-title">The mesh is the base, not an extra</h2>
<p><span class="badge badge-partial">WireGuard in Core; the rest decided, 0024</span></p>
<p><span class="badge badge-live">Two nodes joined, in testing</span> <span class="badge badge-partial">WireGuard in Core; the rest decided, 0024</span></p>
<ul class="checks">
<li><strong>WireGuard ships in Keel Core,</strong> so every appliance can join a mesh, even when it is alone. <code>keel network wireguard key</code> prints this node's public key and never the private one.</li>
<li><strong>Tunnels are initiated from inside to outside,</strong> so a node behind NAT or a firewall needs only outbound UDP.</li>
<li><strong>IPv6 first.</strong> Native IPv6 goes direct between nodes, <code>2001:db8:a::10</code> to <code>2001:db8:c::10</code>. IPv4-only nodes enter through a rendezvous point that translates, with NAT64.</li>
<li><strong>Rendezvous points</strong> are nodes with a real edge and fixed addressing.</li>
<li><strong>A service address on the mesh,</strong> for database appliances only for now. WireGuard is layer 3 with no ARP, so the address is a <code>/128</code> route in <code>AllowedIPs</code> that a controller moves to the active node. Replication and node-to-node traffic always use the nodes' real addresses.</li>
</ul>
<div class="callout">
<strong>Where it stands, 3 October 2026</strong>
<p>Phase 5 has started. Two Keel Web nodes in different locations are joined over a WireGuard overlay, declared in each node's instance spec and confirmed through the network safety window. Next is a one-command join, <code>keel mesh invite</code> on a node of the mesh then <code>keel mesh join</code> on the new one (decision 0048, in review), and etcd forms when the third node joins.</p>
</div>
<p class="hint">Open: the successor to HubDNS for nodes behind NAT whose IPv6 prefix changes. A PowerDNS overlay fed from etcd is the likely shape, not yet decided.</p>
</section>

Expand Down Expand Up @@ -185,7 +189,7 @@ <h2 id="directories-title">Directory replication</h2>
<h2 id="backup-title">Backup and object storage</h2>
<p><span class="badge badge-decided">Decided, 0037 and 0038; Phase 7</span></p>
<ul>
<li><strong>Keel Backup</strong> is an appliance: a storage backend and a key service, installable as an LXC or a VM. TKLBAM stays as the client, with a backend abstraction so that it targets Keel Backup.</li>
<li><strong>Keel Backup</strong> is an appliance: a storage backend and a key service, installable as an LXC or a VM. TKLBAM stays as the client, with a backend abstraction so that it targets Keel Backup. The current testing images ship neither TKLBAM nor the TurnKey Hub agent; Keel Backup and Keel Cloud replace them later.</li>
<li><strong>Off-site by rule.</strong> A backup destination is never in the same site as its data: it refuses, or in a simple installation warns loudly.</li>
<li><strong>Taken from the standby,</strong> so the primary does not pay for it.</li>
<li><strong>Restores are tested</strong> periodically into a throwaway container, and the result is reported to etcd.</li>
Expand Down
56 changes: 48 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<section class="hero" id="top" aria-labelledby="hero-title">
<div class="wrap hero-grid">
<div>
<a class="status-pill" href="#status"><strong>Early</strong> No end-user release yet. Read the status</a>
<a class="status-pill" href="#status"><strong>Testing</strong> Pre-release images, not for production. Read the status</a>
<h1 id="hero-title">Composable, <span class="accent">mesh-native</span> appliances on Debian.</h1>
<p class="promise">Every appliance is secure by default and can join a private cloud on day one.</p>
<p class="sub">A fork of TurnKey Linux 19 (Debian 13) that turns single-machine appliances into building blocks of a real cloud: small components that run alone or together, replicate across sites, fail over, and are upgraded with apt. IPv6-first, so every node has a routable address of its own, and declarative, so every machine is described by one YAML file that Keel applies and re-applies to the same result.</p>
Expand Down Expand Up @@ -382,12 +382,52 @@ <h2 id="standards-title">Rules every change follows</h2>
</div>
</section>

<section class="section" id="status" aria-labelledby="status-title">
<section class="section" id="progress" aria-labelledby="progress-title">
<div class="wrap">
<div class="section-head" data-reveal>
<span class="eyebrow">Progress, 2 and 3 October 2026</span>
<h2 id="progress-title">Signed testing images, and the first two mesh nodes</h2>
<p class="lead">What landed in two days of work. Everything here is on the testing channel and not meant for production.</p>
</div>
<ul class="grid grid-3">
<li class="card" data-reveal>
<h3>Shared default keys, withdrawn and fixed</h3>
<p>The earlier test images and layers carried keys made at build time, so every machine made from one shared them. They were withdrawn and rebuilt. A scan on every layer and image now checks that none carries SSH host keys, TLS private keys, a Webmin certificate or snakeoil keys, and every machine generates its own at first boot.</p>
<p class="refs"><a href="security.html#identity">Keys and identity</a><a href="https://mirror.keellinux.org/WITHDRAWN.txt">The withdrawal notice</a></p>
</li>
<li class="card" data-reveal data-reveal-delay="1">
<h3>A signed archive with two tracks</h3>
<p><a href="https://archive.keellinux.org/">archive.keellinux.org</a> is signed and has two tracks: <code>trixie-testing</code>, where everything lands first, and <code>trixie</code>, the stable track. Promotion to stable is a maintainer's act.</p>
<p class="refs"><a href="https://archive.keellinux.org/keel-archive-keyring.asc">The archive keyring</a><a href="security.html#supply">Where packages come from</a></p>
</li>
<li class="card" data-reveal data-reveal-delay="2">
<h3>Debian and the Keel archive, nothing else</h3>
<p>Images are built from Debian and the Keel archive only, with no TurnKey archive. The TurnKey tools Keel still uses, turnkey-ssl, netinfo, conffile, sysinfo, version, tkl-installer and the dhcpcd glue, are now Keel forks, and turnkey-ssl no longer ships a key. TKLBAM and the TurnKey Hub agent are gone; Keel Backup and Keel Cloud replace them later.</p>
</li>
<li class="card" data-reveal>
<h3>Keel Web serves HTTPS from the start</h3>
<p>In simple mode Keel Web serves HTTPS out of the box with the machine's own certificate, a Keel placeholder page and Keel error pages. Let's Encrypt is set up from the console, prefilled from the instance spec. Cloud mode adds the Coraza WAF and the Anubis bot challenge.</p>
</li>
<li class="card" data-reveal data-reveal-delay="1">
<h3>A first boot that finishes</h3>
<p>First boot asks for the FQDN and offers to keep a root password the hypervisor already set. Unattended, it runs to the end without hanging, and it installs security updates from Debian Security without ever blocking the boot. <code>systemctl --failed</code> is clean in containers.</p>
</li>
<li class="card" data-reveal data-reveal-delay="2">
<h3>The mesh: two nodes so far</h3>
<p>Phase 5 has started. Two Keel Web nodes in different locations are joined over a WireGuard overlay, declared in each node's instance spec and confirmed through the network safety window. Next is a one-command join, <code>keel mesh invite</code> then <code>keel mesh join</code> (decision 0048, in review), and etcd forms at the third node.</p>
<p class="refs"><a href="cloud.html#mesh">How the mesh works</a></p>
</li>
</ul>
</div>
</section>

<section class="section section-alt" id="status" aria-labelledby="status-title">
<div class="wrap status-grid">
<div data-reveal>
<span class="eyebrow">Status</span>
<h2 id="status-title">Early, and plain about it</h2>
<p>There is no release for end users. Layers, Proxmox templates and packages are served from mirror.keellinux.org and archive.keellinux.org for testing, and the test images are not meant for production.</p>
<h2 id="status-title">In testing, and plain about it</h2>
<p>There is no release for end users. The current images are signed testing pre-releases, not meant for production: <a href="https://github.com/Keel-Linux/keel-core/releases/tag/testing-19.0-8-step10-20261003">Keel Core 19.0-8</a> and <a href="https://github.com/Keel-Linux/keel-web/releases/tag/testing-19.0-3-step10-20261003">Keel Web 19.0-3</a>, built on 3 October 2026. Each is a <code>.tar.zst</code> for LXC, on its GitHub release and on <a href="https://mirror.keellinux.org/images/">mirror.keellinux.org</a>, and listed in the <a href="https://releases.keellinux.org/pve/aplinfo.dat">Proxmox template index</a>. Decision 0043 makes the ISO the second release format.</p>
<p>Packages come from <a href="https://archive.keellinux.org/">archive.keellinux.org</a>, signed, on a testing track that everything reaches first and a stable track the maintainer promotes to.</p>
<p>The build host reproduces unmodified TurnKey 19.0 from the forked repositories, which is the baseline every change is measured against. <code>keel inspect</code>, <code>keel diff</code> and <code>keel spec apply</code> run on the test images, and a MariaDB pair, with seeding and a read-only replica, is mostly done in keel 0.11.</p>
<p>The composition architecture on this site was decided on 30 September 2026. Where a point says <em>decided</em> or <em>goal</em>, it is on the roadmap and not yet in the code.</p>
<div class="actions" style="margin-top:1.5rem">
Expand All @@ -398,16 +438,16 @@ <h2 id="status-title">Early, and plain about it</h2>
<div data-reveal data-reveal-delay="1">
<h3>The focus now</h3>
<ol class="focus-list">
<li><span class="num">P1</span><div><strong>Keel Core</strong><p>WireGuard is in Core. Next: CrowdSec installed and disabled, etcd present and stopped, the YAML always emitted, overlays shipped as <code>.deb</code>.</p></div></li>
<li><span class="num">P3</span><div><strong>Keel Web</strong><p>Nginx, Coraza and Anubis packaged in the Keel repository; plain Nginx in a simple installation, the full pipeline in an advanced one.</p></div></li>
<li><span class="num">0041</span><div><strong>The appliance manifest</strong><p>Version 1 is decided. The first step is its reader, <code>keel manifest validate</code> and <code>keel manifest show</code>, with Core and Web as fixtures.</p></div></li>
<li><span class="num">P5</span><div><strong>The mesh</strong><p>Two Keel Web nodes are joined over WireGuard, declared in each node's spec. Next: a one-command join, and etcd at the third node.</p></div></li>
<li><span class="num">P1</span><div><strong>Keel Core and Keel Web</strong><p>In testing as signed pre-releases, with the appliance manifest. Keel Web serves HTTPS in simple mode; Coraza and Anubis come with cloud mode.</p></div></li>
<li><span class="num">P4</span><div><strong>WordPress on Keel PHP</strong><p>The first application built from a manifest, with no Apache in the image.</p></div></li>
</ol>
<p class="hint" style="margin-top:1rem">Decisions: <a href="https://github.com/Keel-Linux/tracker/issues?q=is%3Aissue+ADR">0023 to 0040 on the tracker</a>, and <a href="https://github.com/Keel-Linux/tracker/issues/39">the manifest, tracker#39</a>.</p>
</div>
</div>
</section>

<section class="section" aria-labelledby="cta-title" style="padding-top:0">
<section class="section" aria-labelledby="cta-title">
<div class="wrap">
<div class="cta" data-reveal>
<h2 id="cta-title">Read how it fits together</h2>
Expand Down
9 changes: 7 additions & 2 deletions roadmap.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
<span class="eyebrow">Roadmap</span>
<h1 id="page-title">One layer at a time</h1>
<p class="lead">Every phase ships something testable, and a phase is done only when its criterion holds on a built image, not on a machine assembled by hand. The focus now is Keel Core and Keel Web.</p>
<p class="hint">A copy of <a href="https://github.com/Keel-Linux/tracker/issues/46">tracker#46</a> as of 2026-09-30. The tracker is the source; where the two differ, the tracker is right. Decision numbers link to their issue on the tracker.</p>
<p class="hint">A copy of <a href="https://github.com/Keel-Linux/tracker/issues/46">tracker#46</a> as of 2026-09-30, with progress notes from 2026-10-03. The tracker is the source; where the two differ, the tracker is right. Decision numbers link to their issue on the tracker.</p>
</div>
</section>

Expand All @@ -103,6 +103,7 @@ <h2>Phase 0: sharpen the axe</h2>
<li>The maintainer validates the WordPress test image for simple and cloud simple</li>
<li>An attended release replaces the published layers that still carry private keys</li>
</ul>
<p class="hint"><strong>Progress.</strong> The layers and images that carried shared keys were withdrawn on 2 October, and signed rebuilds replaced them on the testing channel: <a href="https://github.com/Keel-Linux/keel-core/releases/tag/testing-19.0-8-step10-20261003">Keel Core 19.0-8</a> and <a href="https://github.com/Keel-Linux/keel-web/releases/tag/testing-19.0-3-step10-20261003">Keel Web 19.0-3</a>.</p>
<p class="done-when"><strong>Done when</strong> the manifest schema is reviewed with WordPress, Odoo and Mastodon examples, the WordPress test image passes the maintainer's test, and no published layer carries a shared key.</p>
</div>
</li>
Expand All @@ -123,6 +124,7 @@ <h2>Phase 1: Keel Core</h2>
<li>Overlays shipped as <code>.deb</code> from the Keel repository (<a href="https://github.com/Keel-Linux/tracker/issues/41">0036</a>, <a href="https://github.com/Keel-Linux/tracker/issues/44">0039</a>)</li>
<li>Simple and advanced mode screen (<a href="https://github.com/Keel-Linux/tracker/issues/33">0028</a>)</li>
</ul>
<p class="hint"><strong>Progress.</strong> Keel Core is in testing as a signed pre-release, built from Debian and the Keel archive only. First boot asks for the FQDN, runs unattended without hanging, and installs security updates without blocking the boot.</p>
<p class="done-when"><strong>Done when</strong> a Core image boots in simple installation, emits a YAML that re-applies as a no-op, runs no etcd and no active CrowdSec, and upgrades one overlay with <code>apt upgrade</code> on the testing track.</p>
</div>
</li>
Expand Down Expand Up @@ -157,6 +159,7 @@ <h2>Phase 3: Keel Web</h2>
<li>Anubis packaged in the Keel repository</li>
<li>nginx overlay and the Keel Web recipe; Coraza and Anubis disabled in simple</li>
</ul>
<p class="hint"><strong>Progress.</strong> Keel Web is in testing as a signed pre-release. In simple mode it serves HTTPS with the machine's own certificate; cloud mode adds Coraza and Anubis.</p>
<p class="done-when"><strong>Done when</strong> Keel Web in advanced mode blocks a Core Rule Set test payload, challenges a browser through Anubis, lets exempt crawlers through, and in simple mode is plain Nginx.</p>
</div>
</li>
Expand All @@ -177,7 +180,7 @@ <h2>Phase 4: runtimes, and WordPress on Keel PHP</h2>
</div>
</li>

<li class="phase" id="phase-5" data-reveal>
<li class="phase is-current" id="phase-5" data-reveal>
<span class="phase-dot" aria-hidden="true">5</span>
<div class="card">
<div class="phase-head">
Expand All @@ -193,6 +196,7 @@ <h2>Phase 5: mesh control plane</h2>
<li>Syncthing overlay, send-only and receive-only flipped on promotion (<a href="https://github.com/Keel-Linux/tracker/issues/37">0032</a>)</li>
<li>Monit summary to etcd, mesh alerting by watch (<a href="https://github.com/Keel-Linux/tracker/issues/45">0040</a>)</li>
</ul>
<p class="hint"><strong>Progress.</strong> Under way. Two Keel Web nodes in different locations are joined over a WireGuard overlay, declared in each node's instance spec. Next: a one-command join, <code>keel mesh invite</code> and <code>keel mesh join</code> (decision 0048, in review), and etcd at the third node.</p>
<p class="done-when"><strong>Done when</strong> a three-container gate installs the second and third node by discovery, fails over automatically, moves the service address, flips the Syncthing folders, fails back after catch-up, and reports each node's Monit summary through etcd.</p>
</div>
</li>
Expand Down Expand Up @@ -239,6 +243,7 @@ <h2>Open architecture items</h2>
<ul class="tasks">
<li>DNS successor for nodes behind NAT with changing IPv6 prefixes; PowerDNS fed from etcd is likely, not decided (<a href="https://github.com/Keel-Linux/tracker/issues/29">0024</a>)</li>
<li>Elasticsearch or OpenSearch (<a href="https://github.com/Keel-Linux/tracker/issues/38">0033</a>)</li>
<li>MongoDB and CouchDB: deferred</li>
</ul>
</div>
</li>
Expand Down
Loading
Loading