My homelab infra & documentation
  • Python 46.3%
  • HTML 26.8%
  • Shell 21.4%
  • PowerShell 4.3%
  • CSS 0.6%
  • Other 0.6%
Find a file
noc 0a8afd17e7
Beads→Segments rename + media/log-triage hardening
- Rename beads-ui → Segments across dashboard (machines.json,
  services.json, app.py), README, scripts/push-homelab-status.py,
  scripts/newrepo. Remove launchagents/com.noc.beads-ui.plist and
  scripts/sync-beads.sh (beads tool retired; Segments daemon
  net.nocfa.segments on :7765 replaces it).
- scripts/git-autopull.sh: relabel beads remote pull as the legacy
  ops repo (still pulled for memory + key material).
- README + scripts/newrepo: drop codeberg/github auto-push wording;
  origin is the only remote, public mirrors are manual.
- linux/scripts/media-pipeline-watchdog.sh: debounce stale-mount
  alerts with a 2-consecutive-failure counter + slow-probe
  diagnostic log. Fixes 2026-05-22 02:16 false positive triggered
  by an rclone-zurg/RD CDN retry storm (mount recovered on its own).
- linux/scripts/library-update.sh: run the mount sanity probe
  BEFORE the symlink-cleanup pass and stop using `find -xtype l`
  (it traversed /mnt/zurg and could delete valid library links on
  transient FUSE failures). Add a per-hook-arg wait loop and drop
  the Plex scan path (Plex retired from media pipeline).
- services/log-triage/app.py: clamp `exposure` server-side when
  every triggering HTTP status is 4xx/5xx (small MDSF model keeps
  overstating on juicy-looking 404s). Tighten OUTPUT_CONTRACT rule
  ordering to lead with status-decides-exposure. Add test_clamp,
  test_clamp_e2e, test_clamp_noop.
- services/loki/config/loki.yaml + services/gatus/config.yaml:
  config drift from the 2026-05-22 Loki crashloop fix + Gatus
  coverage additions (encrypted, git-crypt).
- .gitignore: ignore linux/env/ (host-local env files with
  plaintext API keys, outside git-crypt coverage) and
  media-quarantine/ (runtime output from library-update).
2026-05-22 21:13:38 +01:00
.github/ISSUE_TEMPLATE Add GitHub issue templates for bugs and feature requests 2026-02-03 17:20:14 +00:00
agent Memory architecture redesign: retire extractor + observer, ship matrix-capture, fix discord-capture 2026-05-08 03:22:51 +01:00
archive Memory architecture redesign: retire extractor + observer, ship matrix-capture, fix discord-capture 2026-05-08 03:22:51 +01:00
configs Update cloudflare-api.env to cfut_ all-access token 2026-05-03 15:08:22 +01:00
dashboard Beads→Segments rename + media/log-triage hardening 2026-05-22 21:13:38 +01:00
docs Drop stale TeamSpeak launchctl refs, ignore data snapshots 2026-04-22 23:36:23 +01:00
launchagents Beads→Segments rename + media/log-triage hardening 2026-05-22 21:13:38 +01:00
linux Beads→Segments rename + media/log-triage hardening 2026-05-22 21:13:38 +01:00
onedrive-migration Add Seafile self-hosted file sync service 2026-05-03 01:13:57 +01:00
scripts Beads→Segments rename + media/log-triage hardening 2026-05-22 21:13:38 +01:00
services Beads→Segments rename + media/log-triage hardening 2026-05-22 21:13:38 +01:00
setup fix setup-linux.sh: configure dual push (GitHub + Codeberg) and branch tracking 2026-02-18 00:25:30 +00:00
windows Convert Glances to NSSM Windows service 2026-02-08 17:45:11 +00:00
.gitattributes Add crowdsec-home-ip-watch: prevent self-ban on ISP IP rotation 2026-05-22 20:55:50 +01:00
.gitignore Beads→Segments rename + media/log-triage hardening 2026-05-22 21:13:38 +01:00
.gitleaks.toml Add gitleaks config and ignore file 2026-05-02 20:24:54 +01:00
.gitleaksignore Add gitleaks config and ignore file 2026-05-02 20:24:54 +01:00
.sops.yaml feat: media pipeline scripts, agent linux support, SOPS auto-encrypt 2026-02-14 05:18:47 +00:00
.stignore Update .stignore: cover audit-discovered local writers 2026-05-02 21:53:20 +01:00
LICENSE Add multi-machine architecture, cross-platform agent, and repo polish 2026-02-03 17:12:22 +00:00
README.md Beads→Segments rename + media/log-triage hardening 2026-05-22 21:13:38 +01:00

License: MIT

noc-homelab

A four-machine homelab running macOS, Linux, and a VPS, connected over Tailscale. Manages media streaming, Matrix communications, game streaming, and monitoring through a central dashboard and agent API.

Dashboard

Machines

Machine OS Role Connectivity
noc-local macOS Dashboard host, sole writable git clone, Cloudflare tunnels LAN + Tailscale
noc-tux Ubuntu 24.04 LTS Agent, media pipeline, Matrix, observability stack LAN + Tailscale 100.91.104.124
noc-claw macOS On-device LLM runtime (MLX), log-triage Tailscale 100.95.102.128
noc-baguette AlmaLinux 9 OVH VPS, rathole tunnel server Public + Tailscale 100.96.57.116

Architecture

noc-local (macOS)                          noc-tux (Ubuntu)
┌──────────────────────┐                   ┌──────────────────────┐
│  Dashboard :8080     │◄── Agent API ───► │  Agent :8080         │
│  Copyparty / Maloja  │    (Tailscale)    │  Matrix Stack        │
│  TeamSpeak 6         │                   │  Media Pipeline      │
│  Caddy / Segments    │                   │    (Zurg → Rclone →  │
│  Cloudflare tunnels  │                   │     FileBot → Emby)  │
│  Syncthing (hub)     │                   │  Sunshine            │
│                      │                   │  Loki / Grafana      │
└──────────────────────┘                   │  CrowdSec LAPI       │
           ▲                               │  Rathole Client ─────┼──► noc-baguette
           │ Agent API                     └──────────────────────┘         │
           ▼                                          ▲                     │
┌──────────────────────┐                              │ Syncthing           │
│  noc-claw (macOS)    │──────────────────────────────┘                     ▼
│  MLX Server :8181    │                              ┌──────────────────────┐
│  log-triage :8182    │                              │  noc-baguette (VPS)  │
└──────────────────────┘                              │  Rathole Server      │
                                                      │   :2333 (Tailscale)  │
                                                      │   :23512/udp public  │
                                                      └──────────────────────┘

The dashboard on noc-local polls the agent API on noc-tux and noc-claw for live service status. Service control (start/stop/restart) is forwarded through the agents, which manage systemd units, LaunchAgents, and Docker containers.

File sync is hub-and-spoke: noc-local is the only writable git clone, and Syncthing distributes the working tree to the two spokes. Edits made on a host propagate back to noc-local for commit. Detailed operational notes live in basic-memory.

Services

noc-local

Service Port Manager Description
Dashboard 8080 launchd Central control plane
Copyparty 8081 launchd File server with web UI
Maloja 42010 launchd Music scrobble server
Multi-Scrobbler 9078 launchd Scrobbler aggregator
TeamSpeak 6 9987 Docker Voice chat + screen share
Syncthing 8384 launchd File sync hub
Caddy 80/443 launchd Reverse proxy
Segments 7765 launchd Task tracker dashboard
Forgejo 3090 launchd Self-hosted Git forge (git.nocfa.net)
Glances / Netdata 61999 / 19999 launchd System metrics
CrowdSec Agent -- launchd Forwards alerts to noc-tux LAPI
Cloudflare tunnels -- launchd All public-facing edge endpoints

noc-tux

Service Port Manager Description
Agent 8080 systemd (user) Service control API
Matrix Synapse + Element + Admin -- systemd matrix.nocfa.net + element.nocfa.net
Matrix Traefik / Postgres / Coturn 443 / -- / 3478 systemd Reverse proxy + DB + TURN
Emby / Plex 8096 / 32400 systemd Media streaming
Zurg + Rclone 9999 / -- systemd (user) Real-Debrid WebDAV → FUSE at /mnt/zurg
Sunshine 47990 systemd (user) Game streaming (HEVC/AV1)
Gatus / Glances / Netdata 3001 / 61999 / 19999 systemd Health + metrics
Loki + Grafana 3100 / 3000 Docker Log aggregation, 14-day retention
Alloy -- systemd Log shipper → Loki
CrowdSec LAPI 8150 systemd Central alerting (3 agents)
Arcane 3552 Docker Docker management UI

noc-claw

Service Port Manager Description
MLX Server 8181 launchd mlx_lm.server serving mlx-community/gemma-3-12b-it-4bit
log-triage 8182 launchd MLX-backed CrowdSec alert enricher
Glances / Netdata 61999 / 19999 launchd System metrics
CrowdSec Agent -- launchd Forwards alerts to noc-tux LAPI

noc-baguette

Service Port Manager Description
Rathole Server 2333/tcp systemd Tunnel control (Tailscale-only)
Forgejo SSH 2222/tcp rathole git-only SSH (ssh.git.nocfa.net)
Resonite 23512/udp rathole Resonite headless server tunnel
Attack-surface scanner -- systemd timer Weekly nuclei + testssl + ssh-audit

Media Pipeline

Real-Debrid Cloud
       │ (API poll every 10s)
       ▼
Zurg (WebDAV :9999) ──► Rclone FUSE (/mnt/zurg)
       │
       ▼ on_library_update hook
library-update.sh
  ├── FileBot: movies → media/movies/
  ├── FileBot: shows  → media/shows/
  ├── Emby /Library/Refresh
  └── Plex /library/sections/all/refresh
       │
       ▼
Emby (8096) + Plex (32400)

Content stays in the Real-Debrid cloud — no local storage needed. A zurg-healthcheck timer runs every 5 minutes comparing the Real-Debrid API torrent count against what Zurg is serving and restarts the stack on divergence.

Matrix Stack

Self-hosted Matrix homeserver at matrix.nocfa.net, Element Web at element.nocfa.net. All six services run as native systemd units (no Docker). Traefik handles TLS, Coturn handles TURN/STUN. Admin UI at matrix.nocfa.net/synapse-admin/.

Rathole Tunnels

Game servers run on noc-tux behind NAT. Rathole punches outbound through the NAT to noc-baguette, exposing UDP/TCP ports publicly without opening the home router. The control channel (port 2333) is Tailscale-only — the VPS is not a jump box.

Observability & Security

  • Logs — Loki on noc-tux ingests from all hosts via Grafana Alloy. 14-day retention, "Homelab Logs" dashboard provisioned in Grafana.
  • Metrics — Netdata parent on noc-tux streams from brew-installed children on both Macs. 4GB dbengine retention.
  • IDS — CrowdSec LAPI on noc-tux (Tailscale + LAN only). Both Macs run native v1.7.7 agents in agent-only mode. Alerts fan out via a direct Discord webhook and an MLX-backed log-triage enricher on noc-claw. Currently observation mode (decisions stored, nothing blocked).
  • External attack surface — weekly nuclei + testssl + ssh-audit run on noc-baguette, results to Discord on findings.

Secrets Management

git-crypt — transparent clean/smudge filter encryption. Plaintext on disk for direct service use; ciphertext in git objects. Patterns listed in .gitattributes (25 files: configs/*.env, services/*/.env, etc.). gitleaks runs in the pre-commit hook as a defense-in-depth scan.

The git-crypt key lives in a separate private sync repo (noc-homelab-beads/, gitignored here). Fresh-clone procedure: git clone <url> && cd noc-homelab && git-crypt unlock /path/to/git-crypt.key.

Git Framework

  • noc-local is the only writable clone. Single remote: origin on self-hosted Forgejo. Public mirrors are updated manually, not by this repo.
  • Hosts (noc-tux, noc-claw) have no .git/. They receive working-tree updates via Syncthing and cannot commit. Edits made on a host propagate back to noc-local.
  • Pre-commit hook runs gitleaks against staged content. A leaked secret aborts the commit.
  • GPG-signed commits on all three machines.

Repository Structure

noc-homelab/
├── agent/                  REST API agent (canonical multi-host config)
│   ├── agent.py            Flask app, port 8080 (Linux) / 5005 (macOS)
│   ├── config.yaml         All hosts; agent filters by platform.node()
│   └── platforms/          Linux/macOS/Windows handlers
├── dashboard/              Control dashboard (runs on noc-local)
├── linux/                  Systemd units, scripts, native service configs
├── services/               Docker Compose stacks + per-service configs
├── configs/                Per-host service configs (most git-crypt-encrypted)
├── launchagents/           macOS LaunchAgent plists
├── scripts/                Utility scripts
├── setup/                  Per-machine bootstrap scripts
└── docs/                   Architecture and setup notes

Deployment

git clone ssh://noc@ssh.git.nocfa.net:2222/NocFA/noc-homelab.git
cd noc-homelab
git-crypt unlock /path/to/git-crypt.key
./setup/setup-linux.sh   # noc-tux
# or
./setup/setup-macos.sh   # noc-local / noc-claw

Setup scripts install dependencies, wire up the pre-commit hook, configure GPG signing, and lay down the systemd / launchd units relevant to the host.