<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Guide on KubeClaw</title><link>https://projectious-work.github.io/kubeclaw/docs/guide/</link><description>Recent content in Guide on KubeClaw</description><generator>Hugo</generator><language>en</language><atom:link href="https://projectious-work.github.io/kubeclaw/docs/guide/index.xml" rel="self" type="application/rss+xml"/><item><title>Dev Container</title><link>https://projectious-work.github.io/kubeclaw/docs/guide/dev-container/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://projectious-work.github.io/kubeclaw/docs/guide/dev-container/</guid><description>&lt;p&gt;The project uses an aibox-generated Dev Container (Debian Trixie) as a
self-contained, reproducible environment. Nothing needs to be set up on the
host machine beyond Docker and an IDE with Dev Container support.&lt;/p&gt;
&lt;h2 id="what-the-dev-container-provides"&gt;What the Dev Container Provides&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OpenTofu&lt;/strong&gt; &amp;ndash; infrastructure provisioning (Terraform-compatible)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ansible&lt;/strong&gt; &amp;ndash; server management (runs inside the container, no host install needed)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cloudflared&lt;/strong&gt; &amp;ndash; SSH ProxyCommand via Cloudflare Tunnel&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ssh-agent&lt;/strong&gt; &amp;ndash; start inside the container to use passphrase-protected keys with Ansible&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI CLI tools&lt;/strong&gt; &amp;ndash; Codex and the aibox toolchain&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hugo + Docsy&lt;/strong&gt; &amp;ndash; documentation site (&lt;code&gt;./scripts/serve-docs.sh&lt;/code&gt; at port 1313)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistence&lt;/strong&gt; &amp;ndash; &lt;code&gt;.aibox-home/.ssh/&lt;/code&gt; is bind-mounted read-write by this
project, so &lt;code&gt;setup-ssh.sh&lt;/code&gt; output, SSH config, and exported keys survive
container rebuilds&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-1-prepare-persistent-directories"&gt;Step 1: Prepare Persistent Directories&lt;/h2&gt;
&lt;p&gt;Create the persistent directories before opening the Dev Container:&lt;/p&gt;</description></item><item><title>Infrastructure (OpenTofu)</title><link>https://projectious-work.github.io/kubeclaw/docs/guide/infrastructure/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://projectious-work.github.io/kubeclaw/docs/guide/infrastructure/</guid><description>&lt;p&gt;KubeClaw uses OpenTofu (Terraform-compatible) to provision all infrastructure on Hetzner Cloud. This page walks through the provisioning workflow step by step. See &lt;a href="https://projectious-work.github.io/kubeclaw/docs/reference/variables/"&gt;Variables Reference&lt;/a&gt; for all configurable options.&lt;/p&gt;
&lt;h2 id="step-1-configure-terraformtfvars"&gt;Step 1: Configure terraform.tfvars&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp terraform.tfvars.example terraform.tfvars
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Edit &lt;code&gt;terraform.tfvars&lt;/code&gt; with your settings:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-hcl" data-lang="hcl"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;hcloud_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;your-hcloud-api-token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;root_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;a-strong-root-password&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cluster_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;k8s-cluster&amp;#34;&lt;/span&gt;&lt;span class="c1"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Optional: auto-configure Cloudflare Tunnel on the master control node
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# cloudflare_tunnel_token = &amp;#34;eyJ...&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ssh-key-options"&gt;SSH key options&lt;/h3&gt;



&lt;ul class="nav nav-tabs" id="tabs-1" role="tablist"&gt;
 &lt;li class="nav-item"&gt;
 &lt;button class="nav-link active"
 id="tabs-01-00-tab" data-bs-toggle="tab" data-bs-target="#tabs-01-00" role="tab"
 aria-controls="tabs-01-00" aria-selected="true"&gt;
 Option A: Auto-generated keys (default)
 &lt;/button&gt;
 &lt;/li&gt;&lt;li class="nav-item"&gt;
 &lt;button class="nav-link"
 id="tabs-01-01-tab" data-bs-toggle="tab" data-bs-target="#tabs-01-01" role="tab"
 aria-controls="tabs-01-01" aria-selected="false"&gt;
 Option B: Custom keys
 &lt;/button&gt;
 &lt;/li&gt;
&lt;/ul&gt;

&lt;div class="tab-content" id="tabs-1-content"&gt;
 &lt;div class="tab-pane fade show active"
 id="tabs-01-00" role="tabpanel" aria-labelled-by="tabs-01-00-tab" tabindex="1"&gt;
 &lt;pre tabindex="0"&gt;&lt;code&gt;No configuration needed. OpenTofu generates ED25519 keys and stores them in the state file.

| Advantage | Disadvantage |
|-----------|--------------|
| No manual key creation | State file contains private keys |
| Works out of the box | Keys lost if state is lost |&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;
 &lt;div class="tab-pane fade"
 id="tabs-01-01" role="tabpanel" aria-labelled-by="tabs-01-01-tab" tabindex="1"&gt;
 &lt;pre tabindex="0"&gt;&lt;code&gt;Create your own keys and reference them in `terraform.tfvars`:

```bash
ssh-keygen -t ed25519 -f ~/.ssh/k8s-cluster_control-node_key -C &amp;#34;control-node&amp;#34;
ssh-keygen -t ed25519 -f ~/.ssh/k8s-cluster_worker-node_key -C &amp;#34;worker-node&amp;#34;
```

```hcl
control_node_public_key = &amp;#34;ssh-ed25519 AAAA... control-node&amp;#34;
worker_node_public_key = &amp;#34;ssh-ed25519 AAAA... worker-node&amp;#34;
```

| Advantage | Disadvantage |
|-----------|--------------|
| Full control over key storage | Manual key management |
| State has no private keys | Must create keys before provisioning |
| Easy password manager integration | |&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="step-2-provision-infrastructure"&gt;Step 2: Provision Infrastructure&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tofu init &lt;span class="c1"&gt;# First time only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tofu apply
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates:&lt;/p&gt;</description></item><item><title>Cloudflare Tunnel Setup</title><link>https://projectious-work.github.io/kubeclaw/docs/guide/cloudflare-tunnel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://projectious-work.github.io/kubeclaw/docs/guide/cloudflare-tunnel/</guid><description>&lt;p&gt;This guide walks through creating and configuring a Cloudflare Tunnel that provides secure SSH access to your KubeClaw cluster. The tunnel replaces the temporary admin node as the permanent access path &amp;ndash; no open ports, no public SSH, outbound-only connectivity.&lt;/p&gt;
&lt;h2 id="why-cloudflare-tunnel"&gt;Why Cloudflare Tunnel?&lt;/h2&gt;
&lt;p&gt;KubeClaw nodes have no public IPv4 and no inbound SSH ports. Access works through one of two paths:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Path&lt;/th&gt;
					&lt;th&gt;When to use&lt;/th&gt;
					&lt;th&gt;How it works&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Admin node&lt;/strong&gt; (temporary)&lt;/td&gt;
					&lt;td&gt;Initial setup, before tunnel is ready&lt;/td&gt;
					&lt;td&gt;Jump host with public IPv6; SSH via &lt;code&gt;ProxyJump&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Cloudflare Tunnel&lt;/strong&gt; (permanent)&lt;/td&gt;
					&lt;td&gt;After tunnel is configured&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cloudflared&lt;/code&gt; on the master node connects outbound to Cloudflare&amp;rsquo;s edge; SSH proxied via &lt;code&gt;ProxyCommand cloudflared access ssh&lt;/code&gt; on your local machine&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;After the tunnel is working, you disable the admin node (&lt;code&gt;enable_admin_node = false&lt;/code&gt; in &lt;code&gt;terraform.tfvars&lt;/code&gt;) and all SSH flows through Cloudflare.&lt;/p&gt;</description></item><item><title>Server Management (Ansible)</title><link>https://projectious-work.github.io/kubeclaw/docs/guide/ansible/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://projectious-work.github.io/kubeclaw/docs/guide/ansible/</guid><description>&lt;p&gt;Ansible handles ongoing server management: system updates, security hardening, NAT64 configuration, and Kubernetes prerequisites. All playbooks run from the Dev Container.&lt;/p&gt;
&lt;h2 id="step-1-set-up-ansible"&gt;Step 1: Set Up Ansible&lt;/h2&gt;
&lt;h3 id="11-generate-inventory"&gt;1.1 Generate inventory&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./scripts/generate-ansible-inventory.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The inventory (&lt;code&gt;ansible/inventory.ini&lt;/code&gt;) is auto-generated. It defines three groups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;control_nodes&lt;/code&gt; &amp;ndash; all control plane nodes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker_nodes&lt;/code&gt; &amp;ndash; all worker nodes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k8s_cluster&lt;/code&gt; &amp;ndash; union of control and worker nodes&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-primary" role="alert"&gt;&lt;div class="h4 alert-heading" role="heading"&gt;Warning&lt;/div&gt;


Never hand-edit `inventory.ini`. Regenerate after infrastructure changes with `./scripts/generate-ansible-inventory.sh`.

&lt;/div&gt;

&lt;h3 id="12-load-ssh-keys"&gt;1.2 Load SSH keys&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ./scripts/ssh-agent-setup.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="alert alert-primary" role="alert"&gt;&lt;div class="h4 alert-heading" role="heading"&gt;Important&lt;/div&gt;


The ssh-agent must be running with the cluster keys loaded before Ansible can connect. Run `source ./scripts/ssh-agent-setup.sh` in every new terminal session.

&lt;/div&gt;

&lt;h3 id="13-test-connectivity"&gt;1.3 Test connectivity&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ansible
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ansible all -m ping
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-apply-system-updates"&gt;Step 2: Apply System Updates&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ansible-playbook playbooks/update-system.yml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Target specific node groups or enable automatic reboots:&lt;/p&gt;</description></item><item><title>Kubernetes (kubeadm)</title><link>https://projectious-work.github.io/kubeclaw/docs/guide/kubernetes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://projectious-work.github.io/kubeclaw/docs/guide/kubernetes/</guid><description>&lt;p&gt;After provisioning the infrastructure with OpenTofu and configuring SSH access, deploy a standard Kubernetes cluster using &lt;a href="https://kubernetes.io/docs/reference/setup-tools/kubeadm/"&gt;kubeadm&lt;/a&gt; with &lt;a href="https://cilium.io/"&gt;Cilium&lt;/a&gt; as the CNI.&lt;/p&gt;
&lt;h2 id="why-kubeadm--cilium"&gt;Why kubeadm + Cilium?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;kubeadm&lt;/strong&gt;: The official Kubernetes bootstrapper. Produces a standard, upstream cluster &amp;ndash; exactly what the CKA exam expects. Full control over every component (etcd, kube-apiserver, kube-scheduler, kube-controller-manager).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cilium&lt;/strong&gt;: eBPF-based CNI providing advanced network policies with FQDN-based egress filtering &amp;ndash; critical for restricting outbound traffic per namespace.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-1-initialize-the-control-plane-dual-stack"&gt;Step 1: Initialize the Control Plane (Dual-Stack)&lt;/h2&gt;
&lt;p&gt;SSH into the master control node. Prerequisites (containerd, kubeadm, kubelet, kubectl) are already installed via cloud-init when &lt;code&gt;enable_k8s_prereqs = true&lt;/code&gt; (default).&lt;/p&gt;</description></item><item><title>OpenClaw Deployment</title><link>https://projectious-work.github.io/kubeclaw/docs/guide/openclaw/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://projectious-work.github.io/kubeclaw/docs/guide/openclaw/</guid><description>&lt;p&gt;A step-by-step guide to deploying OpenClaw as an isolated AI assistant on the KubeClaw cluster, accessible via Telegram, WhatsApp, or Signal, with a web-based Control UI exposed through Cloudflare Tunnel.&lt;/p&gt;
&lt;h2 id="architecture-overview"&gt;Architecture Overview&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────────┐
│ Hetzner Private Network │
│ (10.0.0.0/24) │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Kubernetes Cluster (kubeadm) + Cilium │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ control-01 │ │ worker-01 │ │ │
│ │ │ (control plane)│◄─────►│ (worker node) │ │ │
│ │ │ 10.0.0.2 │ │ 10.0.0.3 │ │ │
│ │ │ │ │ │ │ │
│ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │
│ │ │ │Block Vol │ │ │ │Block Vol │ │ │ │
│ │ │ │ 10 GB │ │ │ │ 10 GB │ │ │ │
│ │ │ └───────────┘ │ │ └───────────┘ │ │ │
│ │ └────────┬────────┘ └─────────────────┘ │ │
│ │ │ │ │
│ │ system-unrestricted namespace: │ │
│ │ └─ cloudflared (egress: ANY) │ │
│ │ │ │
│ │ apps-restricted namespace: │ │
│ │ └─ OpenClaw (Cilium FQDN egress whitelist) │ │
│ │ ├─ Telegram / WhatsApp / Signal │ │
│ │ └─ Control UI (:18789) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ cloudflared │
│ (outbound only) │
└──────────────────────────────┼──────────────────────────────────────┘
 │
 ▼
 ┌───────────────────┐
 │ Cloudflare │
 │ Edge + Access │
 └─────────┬─────────┘
 │
 ┌─────────┼─────────┐
 │ │ │
 ▼ ▼ ▼
 [Telegram] [WhatsApp] [Signal]
 │
 ▼
 [Control UI]
 (browser dashboard)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A running KubeClaw cluster (see &lt;a href="https://projectious-work.github.io/kubeclaw/docs/guide/kubernetes/"&gt;Kubernetes guide&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Anthropic API key (&lt;a href="https://console.anthropic.com"&gt;console.anthropic.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;At least one messaging channel:&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Channel&lt;/th&gt;
					&lt;th&gt;What You Need&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Telegram&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Bot Token from &lt;a href="https://t.me/BotFather"&gt;@BotFather&lt;/a&gt;, your Telegram User ID&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;WhatsApp&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;A phone number with WhatsApp, access to scan a QR code&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Signal&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;A dedicated phone number, &lt;code&gt;signal-cli&lt;/code&gt; installed in the container&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="alert alert-primary" role="alert"&gt;&lt;div class="h4 alert-heading" role="heading"&gt;Start with Telegram&lt;/div&gt;


Telegram is the simplest channel to set up — it only requires a bot token and user ID, with no interactive pairing or additional dependencies.

&lt;/div&gt;

&lt;h2 id="step-1-infrastructure-setup"&gt;Step 1: Infrastructure Setup&lt;/h2&gt;
&lt;p&gt;If you haven&amp;rsquo;t already set up the Hetzner Cloud infrastructure, follow the &lt;a href="https://projectious-work.github.io/kubeclaw/docs/quick-start/"&gt;Quick Start&lt;/a&gt; and &lt;a href="https://projectious-work.github.io/kubeclaw/docs/guide/kubernetes/"&gt;Kubernetes guide&lt;/a&gt;.&lt;/p&gt;</description></item></channel></rss>