Skip to content

RFC — Homelab Plans & Notes

Last updated: 2026-03-24


10. LXC resource management as IaC

Tracked in chizuru-v2 issue #15. Design notes (pct set approach, resource table) moved to the issue.


1. Can I do all this with Ollama?

Short answer: partially, not as a replacement for Claude Code.

Your Ollama instance runs llama3.2:3b and qwen2.5:14b. For the kind of work we do (multi-file Ansible edits, Forgejo API calls, Proxmox MCP, long YAML playbooks), you need:

  • Large context window (we regularly load 5-10 files simultaneously)
  • Strong tool use (file read/edit/bash in a feedback loop)
  • Precise instruction following on complex IaC changes

qwen2.5:14b can handle simpler tasks but struggles with multi-step infrastructure changes across many files. llama3.2:3b is too small for this work.

What Ollama/Open WebUI IS good for: - Learning concepts ("explain Vault namespaces") - Quick questions about CLI tools, Docker, Linux - Drafting config templates to paste and refine yourself - Rubber duck debugging when you understand the problem space

To give a local model context about your homelab: 1. Create a homelab-context.md file with: network topology, service IPs, conventions 2. Upload it to Open WebUI as a document for RAG 3. Use a system prompt with the key facts (see section 2)

Better local models to try for code tasks: - qwen2.5-coder:14b — code-optimized variant, much better than base qwen for YAML/Ansible - deepseek-coder-v2:16b — strong code model if LXC 107 has RAM headroom - Check pct config 107 for memory allocation first

The right split: Use Claude Code for infrastructure changes, use Open WebUI/Ollama for learning, ideation, and documentation drafting.


2. Best way to use Open WebUI

System prompt (set this as your default for the homelab model):

You are a homelab assistant for a Proxmox-based setup.
Network: 192.168.1.x subnet. Proxmox host: chizuru (192.168.1.125).
Key services: Forgejo (100/192.168.1.69), Runner (101/192.168.1.211),
Docker host (103/192.168.1.22), Vault (106/192.168.1.106),
Ollama (107/192.168.1.107), Observability (108/192.168.1.108).
Domain: *.eva-00.network. Auth: PocketID OIDC.
IaC: Ansible + Forgejo Actions. All changes go through git → push → workflow.

Workflows that work well: - RAG: Upload runbook.md and key playbooks as documents → ask questions against them - Model per task: Switch between models (3b for quick, 14b for complex) - Conversation history: Use named conversations per topic so you can return to them - Image analysis: llava model for reading screenshots of logs/dashboards

Models to pull:

ollama pull qwen2.5-coder:14b    # better for YAML/Ansible
ollama pull nomic-embed-text     # enables RAG embeddings in Open WebUI
ollama pull llava:13b            # image analysis

RAG setup in Open WebUI: Settings → Documents → set embedding model to nomic-embed-text, then upload docs and enable RAG in conversations with #doc-name.


3. How to use Claude tokens more efficiently

High-impact habits:

  1. New conversation per task — don't drag a Minecraft debugging session into a Vaultwarden SSO session. Context from unrelated work wastes tokens on every message.

  2. Reference, don't paste — say "look at the vaultwarden playbook" instead of pasting it. Claude Code reads files directly.

  3. Be specific upfront — "change SSO_ONLY to true in services/vaultwarden/docker-compose.yml" costs far fewer tokens than "make Vaultwarden SSO-only" followed by clarification rounds.

  4. Use CLAUDE.md — already doing this. It front-loads context without per-message cost.

  5. Memory system — already set up. Persistent facts (your stack, preferences, ongoing projects) don't need to be re-explained.

  6. /compact — run this in long sessions before a major task to summarize the conversation so far and free up context window.

  7. Targeted questions — "what's the correct Grafana env var for OIDC auto-login?" costs far less than "explain all Grafana auth options and their tradeoffs."


4. MCP vs learning skills/docs

When MCP is worth it: - Stateful or authenticated connections Claude literally can't replicate: Proxmox API, Vault API, GitHub/Forgejo with token auth - Real-time data: cluster status, container metrics, live logs - Actions with side effects that need to be reliable: starting VMs, creating snapshots

When built-in skills/learning is better: - Standard CLI tools (git, docker, ansible) — Claude already knows these deeply - Reading documentation — Claude can fetch and parse docs on demand - APIs with simple curl-style auth — just tell Claude the endpoint and token format

Your current Proxmox MCP: high value — gives real-time cluster visibility and VM/container management that would otherwise require SSH to chizuru for every check.

MCPs worth adding for your stack: - Forgejo MCP (if one exists): trigger workflows, read PR/issue state programmatically - Vault MCP: read/write secrets without needing the token in every conversation - Filesystem MCP: more powerful than built-in Read/Write — can handle binary files, directory trees, symlinks

MCPs to skip: - Generic web search — Claude handles this with WebFetch - Database MCPs for SQLite — overkill for your scale - Anything that duplicates what Ansible already does well


5. Host Docker images and artifacts — using Forgejo registry

Decision: use Forgejo's built-in package/container registry. No separate registry needed.

Forgejo's package registry is enabled by default (no [packages] section needed in app.ini). Confirmed working — GET /api/v1/packages/holo returns 200.

Harbor was evaluated and ruled out — it's overkill for a single-user homelab (5+ containers, multi-tenancy, RBAC). Forgejo covers all needed use cases at zero extra cost.

Push a container image:

docker login git.eva-00.network   # username: holo, password: Forgejo token
docker tag myimage git.eva-00.network/holo/myimage:latest
docker push git.eva-00.network/holo/myimage:latest

Push a generic artifact/binary:

curl -X PUT "https://git.eva-00.network/api/packages/holo/generic/<package>/<version>/<file>" \
  -H "Authorization: token <token>" -T <file>

In Forgejo Actions:

- name: Build and push image
  run: |
    echo "${{ secrets.GITHUB_TOKEN }}" | docker login git.eva-00.network -u holo --password-stdin
    docker build -t git.eva-00.network/holo/myimage:${{ github.sha }} .
    docker push git.eva-00.network/holo/myimage:${{ github.sha }}

Packages UI: https://git.eva-00.network/holo/-/packages


6. Sync code-server for remote work

Goal: continue homelab work from code-server at code.eva-00.network seamlessly.

The setup: - Your repos are at /Users/gabriel/git on your Mac - code-server workspace is at /workspace volume on LXC 103 - Forgejo at git.eva-00.network is the source of truth

Recommended approach: git-based sync

  1. In code-server: clone your repos from Forgejo

    git clone https://git.eva-00.network/holo/homelab.git
    git clone https://git.eva-00.network/holo/homelab-docs.git
    

  2. Set up SSH key in code-server so you can push without password:

    ssh-keygen -t ed25519 -C "code-server"
    # Add the public key to your Forgejo account → Settings → SSH Keys
    
    Then switch remotes to SSH:
    git remote set-url origin [email protected]:holo/homelab.git
    

  3. Workflow: commit on Mac → push to Forgejo → pull in code-server (and vice versa)

To run Claude Code in code-server:

npm install -g @anthropic-ai/claude-code
# Set ANTHROPIC_API_KEY in code-server environment
Add to code-server's .bashrc or via docker-compose env:
ANTHROPIC_API_KEY=<your-key>
Note: Claude Code in code-server will have its OWN memory/project context separate from your Mac. The ~/.claude/ directory is inside the code-server container.

To share Claude memory between Mac and code-server: - Mount a shared volume or sync ~/.claude/projects/ via Syncthing (optional, complex) - Simpler: keep a homelab-context.md in the repo that both environments can reference

Action items: 1. Open code-server, clone repos from Forgejo 2. Generate SSH key, add to Forgejo 3. Install Claude Code: npm install -g @anthropic-ai/claude-code 4. Set ANTHROPIC_API_KEY in the environment


7. Halo Online (ElDewrito) server — ON HOLD

What it is: ElDewrito is a community mod for the cancelled Halo Online. v0.7.1 released May 2024 by a new team — actively developed and maintained. Community organises games via HaloBase and ElDewrito Main on Discord.

Current version: 0.7.1 (May 2024) — changelog available at eldewrito.org

Recommended approach: Docker on existing LXC 103 (no Windows VM needed)

Use domistyle/eldewrito — a Docker image that runs the ElDewrito dedicated server headlessly on Linux via Wine + xvfb internally. No Windows license required.

  • Docker Hub: domistyle/eldewrito (latest: v0.7.0-c1.1, April 2024, 11 releases)
  • GitHub: https://github.com/DomiStyle/docker-eldewrito
  • Requires SYS_PTRACE capability (add to docker-compose or use privileged LXC)
  • Game files (~2GB zip) must be downloaded separately and mounted into the container

Ports: | Port | Protocol | Purpose | |---|---|---| | 11774 | UDP | Game traffic (required) | | 11775 | TCP | HTTP/info server (required) | | 11776 | TCP | RCON (optional) | | 11777 | TCP | VoIP (optional) |

External access: UPnP handles port forwarding automatically if router supports it. Alternatively add a playit.gg TCP+UDP tunnel (account already exists).

Prerequisites before starting: 1. Check free RAM on chizuru — server needs ~2-4 GB 2. Download ElDewrito game files (~2GB zip) from the community 3. Decide: add to LXC 103 or new dedicated LXC

Configuration: dewrito_prefs.cfg — server name, max players, map rotation, RCON password.

Linux client (for playing, not hosting): Steam Play + Proton 9.0-4. Official guide at eldewrito.org.


8. Forgejo action logs → Loki: revisit approach (PARTIALLY RESOLVED by Alloy migration)

Current state (2026-03-24): A Python cron script runs every 2 minutes on the Forgejo LXC, decompresses .log.zst files from /var/lib/forgejo/data/actions_log/, and pushes them to Loki. It works, but a cron script is fragile and hard to observe — it has no health metrics, can silently fall behind, and is yet another custom thing to maintain.

Why the obvious approach (Promtail) doesn't work: Forgejo stores completed action logs as zstd-compressed binary files, not plain text. Promtail can only tail plain text files.

Alternatives to evaluate:

  1. Grafana Alloy (replaces Promtail) — Alloy's pipeline supports decompressor stages and custom loki.process transforms. It may be able to decompress zstd on the fly as files are written. Much more observable than a cron script — Alloy has a built-in UI and exposes metrics.

  2. Vector — purpose-built log router with a richer transform pipeline than Promtail. Supports file watching, custom decoding (including via WASM transforms), and has first-class zstd support in its codec. Would replace the script entirely and run as a proper service.

  3. Forgejo webhook → log endpoint — Forgejo fires webhooks on workflow events. A small receiver (n8n workflow, or a lightweight HTTP service) could call the Forgejo API to download the job log on completion and push it to Loki. No polling, no cron, event-driven. The log download API exists but requires knowing the job ID, which the webhook payload may or may not include.

  4. Change how Forgejo stores logs — Forgejo's [actions] config section has options for log retention and storage. It may be possible to configure it to write uncompressed logs or to a different backend (e.g., S3/Minio), from which a proper log shipper could read them.

Recommendation to revisit: Try Grafana Alloy first — it's already in the Grafana ecosystem, replaces Promtail (which we're already running on the runner LXC), and has native zstd support. If Alloy works, we can consolidate all Promtail instances (runner + future ones) onto Alloy.

To pick this back up: Replace the cron script + Promtail setup on both the Forgejo LXC and the runner LXC with a single Alloy instance, or one Alloy per LXC. Check whether Alloy's loki.source.file + loki.process can handle .log.zst files natively.


9. Docker container logs → Loki (RESOLVED by Alloy migration)

Current state (2026-03-24): Docker container logs on docker-host (LXC 103) are shipped to Loki via the existing observability-agents stack (Promtail + Docker socket). This works for services on LXC 103. However, when debugging failures via MCP/Claude, docker logs is not accessible — we have to SSH through Proxmox, which is slow and manual.

The goal: Be able to query any container's stdout/stderr in Grafana (or via Loki MCP) without needing SSH access.

Options to evaluate:

  1. Grafana Alloy with Docker log collection — Alloy has a native loki.source.docker component that streams logs from all containers via the Docker socket automatically, with container name/image/labels as stream labels. This is the cleanest solution and would also replace Promtail (consolidating with plan #8 above).

  2. Docker logging driver → Loki — Docker supports a loki log driver natively. Setting log-driver: loki in /etc/docker/daemon.json on LXC 103 sends all container logs directly to Loki without any sidecar. Downside: if Loki is unreachable, logs are lost (no local buffer). Also requires restarting all containers.

  3. Promtail Docker service discovery — the existing Promtail config can be extended with a docker_sd_configs scrape job that autodiscovers containers and tails their log files from /var/lib/docker/containers/. Already partially in place — check whether the current promtail-config.yml on LXC 103 covers this.

Recommendation: Try Grafana Alloy first (aligns with plan #8). One Alloy instance per LXC replaces both Promtail and the Forgejo cron script, and Alloy's Docker component handles container log discovery automatically.

To pick this back up: Check services/observability-agents/promtail-config.yml — if it already has Docker discovery, the gap might just be label configuration. Otherwise, migrate to Alloy.


SSO Status (as of 2026-03-22)

Service SSO Status Method
Glance Gate only (no app auth) oauth2-proxy ✓
Gatus Gate only (no app auth) oauth2-proxy ✓
code-server Transparent (no password set) oauth2-proxy ✓
Open WebUI Native OIDC ✓ Direct OIDC (pkceEnabled: false)
Grafana Native OIDC ✓ Direct OIDC
Vaultwarden Native SSO ✓ #/sso → org identifier homelab
Forgejo Native OIDC ✓ forgejo admin auth add-oauth (openidConnect)
n8n Gate only, needs own login oauth2-proxy (no fix available)
The Lounge Gate only, needs own login oauth2-proxy (no fix available)