<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Homelab</title>
      <link>https://docs.cyclops.painlesswp.com</link>
      <description>Two-server fleet — Claw (primary) + Cyclops (worker)</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://docs.cyclops.painlesswp.com/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Sat, 29 Aug 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Two-Server Fleet: Cyclops Minion Plan</title>
          <pubDate>Sat, 29 Aug 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://docs.cyclops.painlesswp.com/blog/cyclops-minion-plan/</link>
          <guid>https://docs.cyclops.painlesswp.com/blog/cyclops-minion-plan/</guid>
          <description xml:base="https://docs.cyclops.painlesswp.com/blog/cyclops-minion-plan/">&lt;h1 id=&quot;plan-two-server-fleet-claw-primary-cyclops-worker&quot;&gt;PLAN: Two-Server Fleet — Claw (primary) + Cyclops (worker)&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Status: &lt;strong&gt;PROPOSED v1.1&lt;/strong&gt; (not yet executed). Cyclops is already cleaned up and minion-ready.
v1.1 amendments from design review: fingerprint-verified key exchange, base-ubuntu-first isolation,
whole-file Caddy ownership, UNMANAGED contract, backup key chain (3 homes, 2 physical), single write path.
Author: Hermes · Date: 2026-08-29 · Repo: github.com/fakeid30/homelab (mirrored to Forgejo)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-current-state-done&quot;&gt;1. Current state (done)&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Claw (claw.eazyplugins.com)&lt;/th&gt;&lt;th&gt;Cyclops (160.191.163.106)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;AlmaLinux 10.2&lt;/td&gt;&lt;td&gt;Ubuntu 24.04 (keep — no reinstall)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Specs&lt;/td&gt;&lt;td&gt;4 vCPU / 7.5GB / 44GB free&lt;/td&gt;&lt;td&gt;2 vCPU / 3.8GB / &lt;strong&gt;20GB free&lt;/strong&gt; (post-cleanup)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Role&lt;/td&gt;&lt;td&gt;Primary — ingress + user-facing services&lt;/td&gt;&lt;td&gt;Worker — will host Forgejo (+ future heavy apps)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Stack&lt;/td&gt;&lt;td&gt;Caddy → 20× Anubis → 56 rootless quadlets&lt;/td&gt;&lt;td&gt;Caddy (2 vhosts) → forgejo + anubis-cyclops&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;IaC&lt;/td&gt;&lt;td&gt;Masterless salt, 196 states, validated&lt;/td&gt;&lt;td&gt;none yet (cleaned by hand, backup taken)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Running now&lt;/td&gt;&lt;td&gt;59 containers&lt;/td&gt;&lt;td&gt;&lt;strong&gt;openclaw-gateway (bare node, DO NOT TOUCH) + forgejo + anubis-cyclops + caddy&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Access: &lt;code&gt;ssh nirjhor@cyclops.painlesswp.com&lt;/code&gt; works from Claw (key-based). Sudo pass: [REDACTED — user knows it].
Forgejo: HTTP via Caddy (&lt;code&gt;forgejo.cyclops.painlesswp.com&lt;/code&gt;), SSH on port &lt;strong&gt;2222&lt;/strong&gt;, repo &lt;code&gt;chorompotro/homelab&lt;/code&gt; (mirrors GitHub).&lt;/p&gt;
&lt;h2 id=&quot;2-target-architecture&quot;&gt;2. Target architecture&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Users ──► *.eazyplugins.com ──► CLAW (sole ingress, TLS, Anubis chain)
                                    │
                                    ├─ local quadlets (unchanged)
                                    │
                                    └─ WireGuard tunnel 10.0.0.1 ↔ 10.0.0.2
                                              │
                                         CYCLOPS: worker services
                                         (forgejo stays on its own domain,
                                          future: immich, heavy/batch jobs)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DNS: zero changes ever.&lt;/strong&gt; Wildcard &lt;code&gt;*.eazyplugins.com → Claw&lt;/code&gt; covers future services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URLs never change&lt;/strong&gt; for users; only Caddy&#39;s upstream target shows where bytes go.&lt;/li&gt;
&lt;li&gt;Claw keeps all TLS certs; Cyclops never needs Let&#39;s Encrypt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-phase-plan&quot;&gt;3. Phase plan&lt;/h2&gt;
&lt;h3 id=&quot;phase-a-trust-fabric-1h-total&quot;&gt;Phase A — Trust fabric (~1h total)&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;WireGuard&lt;/strong&gt; (~30 min): both nodes; Claw=10.0.0.1, Cyclops=10.0.0.2. Key exchange via each box&#39;s existing SSH session — &lt;strong&gt;never&lt;/strong&gt; via the tunnel being established or any third-party paste/bootstrap channel. Tunnel carries: salt, cross-node upstreams, backups.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Salt master&lt;/strong&gt; on Claw (&lt;code&gt;dnf install salt-master&lt;/code&gt;, bind 4505/4506 to tunnel interface only).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Salt minion&lt;/strong&gt; on Cyclops (&lt;code&gt;apt&lt;/code&gt; from salt repo), master=10.0.0.1.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key acceptance — fingerprint rule&lt;/strong&gt;: &lt;code&gt;auto_accept: False&lt;/code&gt; permanently. Accept only after &lt;code&gt;salt-key -f &amp;lt;minion&amp;gt;&lt;/code&gt; on Claw and &lt;code&gt;salt-call key.finger&lt;/code&gt; (or local &lt;code&gt;salt-key -f mymaster&lt;/code&gt;) on Cyclops produce matching fingerprints, &lt;strong&gt;compared out-of-band&lt;/strong&gt; (each box&#39;s own SSH session — not over the tunnel, not via chat relay of one side only).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;phase-b-state-tree-refactor-3-4h-risk-center-is-the-debian-branch&quot;&gt;Phase B — State tree refactor (3–4h; risk center is the Debian branch)&lt;/h3&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Grains: Claw &lt;code&gt;roles:[primary, ingress, anubis]&lt;/code&gt;; Cyclops &lt;code&gt;roles:[worker, forgejo]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;base-ubuntu.sls FIRST, in isolation&lt;/strong&gt; (the risk item — Debian package/service names, AppArmor paths vs SELinux, Ubuntu caddy repo):
&lt;ul&gt;
&lt;li&gt;Write it, then dry-run &lt;strong&gt;standalone on Cyclops as root&lt;/strong&gt;: &lt;code&gt;sudo salt-call --local state.apply base-ubuntu test=True&lt;/code&gt; — testing what will actually run, not what master-pushed top.sls will do later.&lt;/li&gt;
&lt;li&gt;Gate: 0 failures or it doesn&#39;t exist. Only then does top.sls include it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remaining Cyclops states (after base-ubuntu is known-good):
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;forgejo.sls&lt;/code&gt; — codifies the &lt;strong&gt;container definition only&lt;/strong&gt; (quadlet file, image, port 2222→22 mapping, network). Data dir gets &lt;code&gt;file.directory&lt;/code&gt; (existence + ownership) — &lt;strong&gt;no recurse, no prune, no clean&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;caddy-cyclops.sls&lt;/code&gt; — &lt;strong&gt;owns the whole Caddyfile&lt;/strong&gt; (file.managed, full contents from repo copy). No sed-merges, no partial management. Manual on-disk edits get overwritten on next apply — drift surfaces as a diff, which is the feature. Emergency edits go through the repo (edit state → apply), never on-disk.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pillar per-node: Cyclops never receives Claw&#39;s secrets. OS branches via &lt;code&gt;map.jinja&lt;/code&gt; (&lt;code&gt;os_family: Debian&lt;/code&gt;) — ~20 lines.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;phase-c-first-workloads-optional-later&quot;&gt;Phase C — First workloads (optional, later)&lt;/h3&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;WireGuard-first app to prove the pattern (e.g. Immich on Cyclops: Caddy vhost on Claw → &lt;code&gt;10.0.0.2:2283&lt;/code&gt;, new Anubis instance on Claw, no DNS change).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backups — restic over the tunnel.&lt;/strong&gt; Repo per direction: &lt;code&gt;claw→cyclops&lt;/code&gt; (Claw critical data), &lt;code&gt;cyclops→claw&lt;/code&gt; (forgejo).
&lt;strong&gt;Key chain (decided now, three homes, all independent):&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Repo passwords in salt &lt;strong&gt;pillar on the master&lt;/strong&gt; (delivered per-node)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pen-drive&lt;/strong&gt; copy (offline)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Printed&lt;/strong&gt; copy (offline, different physical location from the pen-drive)
DR chain: machine dies → rebuild from salt → pillar restores restic passwords → restore.
Both machines die → offline copies + GitHub repo rebuild. The key has exactly three homes; this is closed now, not in Phase C.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;phase-d-day-2-optional-when-2-nodes-or-automation-wanted&quot;&gt;Phase D — Day-2 (optional, when &amp;gt;2 nodes or automation wanted)&lt;/h3&gt;
&lt;ol start=&quot;11&quot;&gt;
&lt;li&gt;&lt;code&gt;state.orchestrate&lt;/code&gt; for cross-node ordering; reactors/beacons for event-driven automation.&lt;/li&gt;
&lt;li&gt;Scale rule: 3rd+ server ⇒ this design pays off; at 2 nodes master-minion is &lt;em&gt;architecturally&lt;/em&gt; right but &lt;em&gt;operationally&lt;/em&gt; optional (salt-ssh is the 70% fallback with no master risk).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;4-why-this-design&quot;&gt;4. Why this design&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Claw as sole ingress&lt;/strong&gt; keeps: one Anubis pattern, one Caddyfile, all URLs stable, one TLS story. Cost: Claw is a SPOF for Cyclops-hosted user services (documented trade).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ubuntu stays&lt;/strong&gt;: salt is cross-OS by design; only cost is the Debian-family branch in states. Reinstalling to Alma is &lt;em&gt;not&lt;/em&gt; needed (revisit only if Cyclops gets rebuilt anyway).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory is federated, not pooled&lt;/strong&gt;: Claw RAM serves Claw services; Cyclops&#39; 2.6GB free serves workers. You place services; salt enforces placement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-risks-mitigations&quot;&gt;5. Risks &amp;amp; mitigations&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Risk&lt;/th&gt;&lt;th&gt;Mitigation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Claw down → Cyclops user services dark&lt;/td&gt;&lt;td&gt;Accepted (homelab); document which services die with Claw&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Master down → no convergence (nodes keep running last config)&lt;/td&gt;&lt;td&gt;salt-ssh break-glass; nodes are NOT dependent at runtime&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tunnel down → cross-node services + salt break&lt;/td&gt;&lt;td&gt;Uptime Kuma check on 10.0.0.2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Drift (manual changes on Cyclops)&lt;/td&gt;&lt;td&gt;Whole-file state ownership + re-apply; drift surfaces as diff&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mixed-OS state bugs&lt;/td&gt;&lt;td&gt;base-ubuntu-first isolation; root dry-run standalone before top.sls inclusion&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MITM during key exchange&lt;/td&gt;&lt;td&gt;Fingerprint match out-of-band; auto_accept False permanently&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;6-conventions-binding-also-mirrored-in-repo&quot;&gt;6. CONVENTIONS (binding, also mirrored in repo)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Single write path&lt;/strong&gt;: all applies originate from &lt;strong&gt;Claw&lt;/strong&gt; (&lt;code&gt;salt &#39;cyclops&#39; state.apply ...&lt;/code&gt;). &lt;code&gt;salt-call --local&lt;/code&gt; on Cyclops exists for exactly one purpose: read-only validation (&lt;code&gt;test=True&lt;/code&gt; dry-runs, as root). No local applies, no minion-side cron applies, no on-disk quick fixes — the fix path is edit-state-on-Claw → apply from Claw. One writer = one definition of &quot;applied.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Whole-file ownership&lt;/strong&gt;: salt-managed config files (Caddyfile, quadlets) are generated wholesale from the repo. No merges.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data is never state&lt;/strong&gt;: container definitions are managed; data dirs get existence+ownership only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation gate&lt;/strong&gt;: root dry-run 0 failures before any apply; endpoints 200 after.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unmanaged list&lt;/strong&gt; lives in &lt;code&gt;UNMANAGED.md&lt;/code&gt; (repo root); additions require a commit explaining why.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;7-unmanaged-excluded-from-all-state-see-unmanaged-md&quot;&gt;7. UNMANAGED (excluded from all state, see UNMANAGED.md)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;openclaw-gateway.service&lt;/code&gt; — no state may reference it, stop it, or depend on it. (Root&#39;s salt wouldn&#39;t see user units anyway — the exclusion is deliberate, not incidental.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/forgejo/data&lt;/code&gt; — definition managed, data never.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/saltstack&lt;/code&gt;, &lt;code&gt;~/package.json&lt;/code&gt; — openclaw-adjacent artifacts, outside management.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;8-execution-checklist-when-given-the-go&quot;&gt;8. Execution checklist (when given the GO)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
WireGuard up both sides (SSH-swapped keys), ping 10.0.0.2 ↔ 10.0.0.1&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
salt-master on Claw (bind tunnel interface; file_roots → homelab repo path; &lt;code&gt;auto_accept: False&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
salt-minion on Cyclops; &lt;strong&gt;fingerprints compared out-of-band&lt;/strong&gt;; key accepted&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;salt &#39;cyclops&#39; test.ping&lt;/code&gt; → True&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Grains (roles) set both nodes&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;base-ubuntu.sls&lt;/code&gt; written → &lt;strong&gt;standalone root dry-run on Cyclops → 0 failures&lt;/strong&gt; → then top.sls inclusion&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;forgejo.sls&lt;/code&gt; (definition-only) + &lt;code&gt;caddy-cyclops.sls&lt;/code&gt; (whole-file) written; dry-run → 0 failures&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Real apply &lt;strong&gt;from Claw&lt;/strong&gt; → verify forgejo + openclaw + endpoints still 200 after&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Pillar top.sls per-node split; secrets audited (Cyclops gets only its own)&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;UNMANAGED.md&lt;/code&gt; + this conventions section committed&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
Commit tree changes → push GitHub + Forgejo&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
RUNBOOK.md updated: two-node rebuild procedure&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
(Phase C, later) restic repos + key chain deployed; first tunnel service&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-reference-facts&quot;&gt;9. Reference facts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cyclops SSH from Claw is passwordless (key). Forgejo git push = SSH port 2222, key &lt;code&gt;nirjhor@claw.hackershostel.com&lt;/code&gt; (verified).&lt;/li&gt;
&lt;li&gt;OpenClaw on Cyclops = systemd user service &lt;code&gt;openclaw-gateway.service&lt;/code&gt;, node process, port 18789, fronted by &lt;code&gt;anubis-cyclops&lt;/code&gt; — &lt;strong&gt;never modify&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Pre-cleanup backup of Cyclops (forgejo data + authelia) sits at &lt;code&gt;~/backups/cyclops-preclean-backup.tar.gz&lt;/code&gt; on Claw (192KB, deletable).&lt;/li&gt;
&lt;li&gt;Salt validation convention: full &lt;code&gt;salt-call --local state.apply test=True&lt;/code&gt; as root must be &lt;strong&gt;0 failures&lt;/strong&gt; before any push (Claw baseline: 196/0).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;10-observed-reality-2026-08-29-post-cleanup-inspection-salt-must-codify-this&quot;&gt;10. OBSERVED REALITY (2026-08-29 post-cleanup inspection) — salt must codify THIS&lt;/h2&gt;
&lt;p&gt;The user deployed significant infrastructure by hand after cleanup. Salt states for Cyclops
must codify the following &lt;strong&gt;as-is&lt;/strong&gt; (not the older assumptions):&lt;/p&gt;
&lt;h3 id=&quot;forgejo-significantly-reworked&quot;&gt;Forgejo (significantly reworked)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Image&lt;/strong&gt;: &lt;code&gt;codeberg.org/forgejo/forgejo:16&lt;/code&gt; (v16.0.3) — upgraded from gitea 9.0.3&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quadlet&lt;/strong&gt;: &lt;code&gt;~/.config/containers/systemd/forgejo.container&lt;/code&gt; (rewritten 2026-08-29 17:27)
&lt;ul&gt;
&lt;li&gt;Ports: &lt;code&gt;3026:3000&lt;/code&gt; (HTTP), &lt;code&gt;2222:22&lt;/code&gt; (git SSH)&lt;/li&gt;
&lt;li&gt;Volumes: &lt;code&gt;~/forgejo/data:/data&lt;/code&gt; (unmanaged), &lt;code&gt;/etc/timezone&lt;/code&gt;+&lt;code&gt;/etc/localtime&lt;/code&gt; (ro)&lt;/li&gt;
&lt;li&gt;Env: &lt;code&gt;GITEA_CUSTOM=/data/gitea&lt;/code&gt;, &lt;code&gt;USER_UID/GID=1000&lt;/code&gt;, AutoUpdate=registry, Restart=on-failure&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;app.ini&lt;/strong&gt;: DOMAIN/SSH_DOMAIN = forgejo.cyclops.painlesswp.com, ROOT_URL https, SSH_PORT=2222&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data&lt;/strong&gt;: &lt;code&gt;~/forgejo/data&lt;/code&gt; — gitea+git+ssh dirs, host keys generated, 10MB — UNMANAGED (per UNMANAGED.md)&lt;/li&gt;
&lt;li&gt;Legacy &lt;code&gt;~/forgejo/docker-compose.yml&lt;/code&gt; still on disk (superseded by quadlet; candidate for removal)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;new-forgejo-actions-ci-docs-site&quot;&gt;NEW: Forgejo Actions CI + docs site&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;forgejo-runner&lt;/strong&gt; (&lt;code&gt;~/.local/bin/forgejo-runner&lt;/code&gt; 13.0.0) — systemd &lt;strong&gt;user&lt;/strong&gt; unit
&lt;code&gt;forgejo-runner.service&lt;/code&gt;, WorkingDirectory &lt;code&gt;~/runner&lt;/code&gt;, DOCKER_HOST→podman.sock&lt;/li&gt;
&lt;li&gt;Workflow &lt;code&gt;.forgejo/workflows/docs.yml&lt;/code&gt; in repo: on push→main, zola builds site
→ &lt;code&gt;/mnt_pages/homelab&lt;/code&gt; → runner publishes to &lt;code&gt;~/forgejo-pages/homelab&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;docs.cyclops.painlesswp.com&lt;/strong&gt; — Caddy file_server serving the built site (LIVE, 200)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;new-searxng-back-by-user-decision&quot;&gt;NEW: SearXNG (back, by user decision)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Container &lt;code&gt;searxng&lt;/code&gt; (image 2026.8.29-d226b78bc), started 14:36 via &lt;strong&gt;plain podman run — NO quadlet,
no systemd unit&lt;/strong&gt; (restart=unless-stopped only). ⚠ Not boot-persistent, not auto-updated.
Salt state needed if this stays.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;caddy-on-cyclops-3-vhosts-now-still-no-anubis-on-forgejo-docs-vhosts&quot;&gt;Caddy on Cyclops (3 vhosts now, still NO anubis on forgejo/docs vhosts)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cyclops.painlesswp.com&lt;/code&gt; → anubis-cyclops → openclaw (unchanged)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;forgejo.cyclops.painlesswp.com&lt;/code&gt; → localhost:3026 (direct, no anubis)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs.cyclops.painlesswp.com&lt;/code&gt; → file_server &lt;code&gt;~/forgejo-pages/homelab&lt;/code&gt; (direct, no anubis)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;url-rename-done&quot;&gt;URL rename (done)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;forgeho.&lt;/code&gt; → &lt;code&gt;forgejo.cyclops.painlesswp.com&lt;/code&gt; everywhere: app.ini, Caddyfile, claw-side
ssh config, git remotes, docs. Old hostname dead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;salt-implications-delta-from-v1-1-plan&quot;&gt;Salt implications (delta from v1.1 plan)&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;forgejo.sls&lt;/code&gt; must pin image &lt;code&gt;codeberg.org/forgejo/forgejo:16&lt;/code&gt; + the two PublishPorts + GITEA_CUSTOM env&lt;/li&gt;
&lt;li&gt;NEW &lt;code&gt;forgejo-runner.sls&lt;/code&gt;: user unit + binary + config.yml (runner is CI-critical — definition managed, secrets/registration NOT)&lt;/li&gt;
&lt;li&gt;NEW &lt;code&gt;docs-publish&lt;/code&gt; handling: either manage &lt;code&gt;~/forgejo-pages&lt;/code&gt; as unmanaged output dir (Actions-owned) or exclude — it&#39;s CI-written, salt must never clean it&lt;/li&gt;
&lt;li&gt;Decide: searxng quadlet-ized (recommended) or removed&lt;/li&gt;
&lt;li&gt;Decide: anubis in front of forgejo/docs vhosts (v1.1 plan assumed Anubis universal; current manual Caddyfile has none on these two)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;addendum-same-day-single-searxng-decision&quot;&gt;ADDENDUM (same day): single SearXNG decision&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Cyclops&#39; local searxng container REMOVED (was unit-less, not boot-persistent)&lt;/li&gt;
&lt;li&gt;OpenClaw on Cyclops now uses &lt;strong&gt;claw&#39;s searxng&lt;/strong&gt; via &lt;code&gt;https://search.eazyplugins.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Claw Caddyfile: &lt;code&gt;/search?format=json&lt;/code&gt; from &lt;code&gt;160.191.163.106&lt;/code&gt; (cyclops) bypasses Anubis,
IP-gated handle block; all other traffic still goes through Anubis challenge&lt;/li&gt;
&lt;li&gt;salt delta: caddy.sls (claw) must include this @searx_internal block; openclaw config on
cyclops stays UNMANAGED (part of .openclaw, openclaw rule adjacency)&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    </channel>
</rss>
