Files
homelab-configs/AGENTS.md
T
jgitta eba13efd34 docs: Add comprehensive memory inventory and resale valuation
- Document physical memory configuration for workstation (24GB, 3x Hynix 8GB)
- Document Proxmox host memory details (112GB total: 6x 8GB Hynix + 2x 32GB HP)
- Add April 2026 resale valuation estimates (~$805 combined)
- Include DIMM-level details with serial numbers and part numbers

Co-Authored-By: Oz <oz-agent@warp.dev>
2026-04-18 21:28:46 -05:00

20 KiB
Raw Blame History

Homelab Infrastructure — Project Knowledge

Host Machine

  • ThinkStation-P710 — Primary Proxmox host
    • IP: 192.168.88.25 (jg-hud)
    • Specs: Dual Xeon E5 v4, 110GB ECC RAM, 16 cores
    • OS: Proxmox VE
    • SSH: root@192.168.88.25 (key: SHA256:i4whMVfdf+SxGttDKhL9PEltWv2ABPQs7BRUunCfcf8)

Local WORKSTATION

  • ThinkStation-P710

  • Specs: Dual Xeon E5 v4

  • OS Linux Mint

    • Also runs Frigate NVR directly at 192.168.88.41

Workstation Memory Inventory (April 2026)

  • Installed memory: 24GB total
  • DIMMs installed:
    • CPU1_A0 / DIMM1 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 718BE2E4, Rank 2
    • CPU1_B0 / DIMM3 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 718BE3C5, Rank 2
    • CPU1_B1 / DIMM5 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 1145576F, Rank 2
  • Empty slots: remaining reported DIMM slots unpopulated
  • Estimated resale value for installed memory: ~$135 total (~$45/stick, used-market estimate)

Network

  • MikroTik router: 192.168.88.1
    • Main LAN: 192.168.88.0/24
    • IoT VLAN: 192.168.2.0/24
    • Static WAN IP: 184.170.161.177
    • SSH access: available via user: sofi with hostAlias 192.168.88.1
    • Commands use RouterOS syntax (e.g. /ip dhcp-server network print, /ip dns static print)
    • Can read/change: DHCP networks, DNS static entries, firewall rules, interfaces, NAT rules
  • Synology RT6600ax: WiFi AP only (pure AP mode, no routing, no DHCP)
  • DNS architecture:
    • DHCP clients get: Primary 192.168.88.27 (Pi-hole), Secondary 192.168.88.1 (MikroTik fallback)
    • Pi-hole upstream: 192.168.88.1 (MikroTik) → resolves local jgitta.com domains internally, then 1.1.1.1/8.8.8.8 for internet
    • MikroTik has static A records for all *.jgitta.com192.168.88.110 (Caddy)
    • IoT VLAN DNS force-redirected to Pi-hole via MikroTik DSTNAT
    • Fallback: if Pi-hole is down, clients auto-fail over to MikroTik (192.168.88.1) within ~2s
  • Cloudflare:
    • Zone ID: 3511a9ac47fa469b24a5c0f411063da4
    • DNS API token: gEgJiSdJKSLhnCwQGXRiRWgz5WhTmkZQk0H89X8p
    • DNS Edit token: cfat_RhlfvleyZGst8k6rTVx9Ti7x3b8NuE3uOxExka3i9d128e8c
    • All jgitta.com subdomains point to WAN IP

Proxmox VMs & Containers

ID Name IP Specs Role
VM102 jellyfin 192.168.88.10 2c/12GB Jellyfin + *arr stack + qBittorrent/ProtonVPN
VM103 next 192.168.88.62 2c/8GB Nextcloud + OnlyOffice
VM104 Windows11-NVR 8c/11GB Windows VM
VM105 openclaw-debian 4c/4GB
VM106 haos 192.168.88.39 2c/8GB Home Assistant OS
VM107 pbs 192.168.88.60 4c/8GB Proxmox Backup Server (nightly full backups)
VM112 siklos/docker-server 192.168.88.27 4c/12GB Main Docker host
VM113 photos 192.168.88.32 4c/16GB PhotoPrism + Immich (dedicated photo VM)
VM113 zorin-os 2c/4GB
CT200 gitea 192.168.88.200 1c/512MB Gitea git server (port 3000)
CT201 openclaw 192.168.88.29 AI gateway (Gemini + Telegram bot, port 18789)
CT202 caddy-proxy 192.168.88.110 2c/4GB Caddy reverse proxy
VM111 debian-1 Stopped/unused

Storage Pools (on jg-hud)

Pool Size Type
nvme-thin 4.3TB LVM
SSD-1.7T 1.7TB
big-11t 10.8TB
HD4T-1 3.6TB
HD4T-2 3.6TB
nextcloud-fast 1.8TB ZFS
pbs 39TB PBS
  • TrueNAS: 192.168.88.24 — 25.5TB (TrueNAS-NFS pool)
  • Photos NFS: /mnt/big-11t/photos on Proxmox host, NFS-exported to siklos and ThinkStation

SSH Access

All active endpoints are directly accessible via SSH on port 22.

Device IP User SSH Command
Proxmox (jg-hud) 192.168.88.25 root ssh root@192.168.88.25
MikroTik router 192.168.88.1 sofi ssh sofi@192.168.88.1
VM102 (jellyfin) 192.168.88.10 jgitta ssh jgitta@192.168.88.10
VM103 (next) 192.168.88.62 jgitta ssh jgitta@192.168.88.62
VM106 (haos) 192.168.88.39 root ssh root@192.168.88.39
VM107 (pbs) 192.168.88.60 root ssh root@192.168.88.60
VM112 (siklos) 192.168.88.27 jgitta ssh jgitta@192.168.88.27
VM113 (photos) 192.168.88.32 jgitta ssh jgitta@192.168.88.32
CT200 (gitea) 192.168.88.200 jgitta ssh jgitta@192.168.88.200
CT202 (caddy-proxy) 192.168.88.110 root ssh root@192.168.88.110
TrueNAS 192.168.88.24 admin ssh admin@192.168.88.24
ThinkStation 192.168.88.41 jgitta ssh jgitta@192.168.88.41

Notes:

  • CT201 (openclaw) is currently powered off
  • All connections are direct (no jump hosts required)
  • All use standard SSH port 22

SSH Quick Reference

Quick reference for direct SSH access to all endpoints (all on port 22):

Infrastructure:

ssh root@192.168.88.25      # Proxmox
ssh sofi@192.168.88.1       # MikroTik

VMs:

ssh jgitta@192.168.88.10    # VM102 jellyfin
ssh jgitta@192.168.88.62    # VM103 next
ssh root@192.168.88.39      # VM106 haos
ssh root@192.168.88.60      # VM107 pbs
ssh jgitta@192.168.88.27    # VM112 siklos
ssh jgitta@192.168.88.32    # VM113 photos

Containers:

ssh jgitta@192.168.88.200   # CT200 gitea
ssh root@192.168.88.110     # CT202 caddy-proxy

Storage & Workstation:

ssh admin@192.168.88.24     # TrueNAS
ssh jgitta@192.168.88.41    # ThinkStation

Caddy Reverse Proxy (CT202 — 192.168.88.110)

  • Version: v2.11.2 with Cloudflare DNS plugin
  • Config: /etc/caddy/Caddyfile imports /etc/caddy/snippets.caddy and /etc/caddy/sites/*.caddy
  • TLS: DNS challenge via Cloudflare
  • Snippets: headers_base, internal_only, web_secure, web_media, stream_secure, proxy_timeouts, pve_proxy

sites/infrastructure.caddy

Subdomain Backend Notes
proxmox.jgitta.com 192.168.88.25:8006 internal_only
pbs.jgitta.com 192.168.88.60:8007 internal_only
mesh.jgitta.com 192.168.88.27:444 MeshCentral
pihole.jgitta.com 192.168.88.27:8080 internal_only
homarr.jgitta.com 192.168.88.27:7575
apache.jgitta.com 192.168.88.27:8383 Guacamole
notes.jgitta.com 192.168.88.27:3010 Karakeep
links.jgitta.com 192.168.88.27:3015 Linkwarden
gitea.jgitta.com 192.168.88.200:3000
status.jgitta.com 192.168.88.27:3001 Uptime Kuma, internal_only
grafana.jgitta.com 192.168.88.27:3020 internal_only
glances.jgitta.com 192.168.88.27:61208 internal_only
dashboard.jgitta.com 192.168.88.27:8096 custom dashboard
blue.jgitta.com 192.168.88.47:75
claw.jgitta.com 192.168.88.29:18789 internal_only
office.jgitta.com 192.168.88.27:8880 OnlyOffice
jgitta.com / www 192.168.88.27:8095 WordPress

sites/media.caddy

Subdomain Backend Notes
jellyfin.jgitta.com 192.168.88.10:8096 stream_secure
sonarr.jgitta.com 192.168.88.10:8989 internal_only
radarr.jgitta.com 192.168.88.10:7878 internal_only
prowlarr.jgitta.com 192.168.88.10:9696 internal_only
ha.jgitta.com 192.168.88.39:8123 Home Assistant
cameras.jgitta.com 192.168.88.41:8971 Frigate, stream_secure
next.jgitta.com 192.168.88.62:80 Nextcloud
collabora.jgitta.com 192.168.88.62:9980 Collabora (may be replaced by OnlyOffice)
hub.jgitta.com 192.168.88.65 Hubitat
pictures.jgitta.com 192.168.88.32:2283 Immich (VM113)
photos.jgitta.com 192.168.88.32:2342 PhotoPrism (VM113)

When adding new subdomains

Always handle DNS (Cloudflare) and Caddy changes together as a single operation.

Jellyfin (VM102 — 192.168.88.10)

  • URL: https://jellyfin.jgitta.com
  • Port: 8096
  • API Token: b861664663924b68858a67b91f6d1188
  • Admin User ID: 12659173-DBBE-43E5-B116-DE70B63A470D
  • DB: /var/lib/jellyfin/data/jellyfin.db (SQLite)
  • Virtual folders config: /var/lib/jellyfin/root/default/<LibraryName>/options.xml
  • LiveTV config: /etc/jellyfin/livetv.xml
  • HDHomeRun tuner: http://192.168.88.22 (device ID: 10B00DE1)

Media Libraries

Library CollectionFolder ID Path
Shows A656B907-EB3A-7353-2E40-E44B968D0225 /mnt/media/tv
Movies F137A2DD-21BB-C1B9-9AA5-C0F6BF02A805 /mnt/media/movies
Recordings 79A2726D-3C50-E769-A8AF-1E4184E4FCCF /mnt/media/recordings

Media mount: /mnt/media (5.8TB, ~55% used) — subdirs: movies/, tv/, recordings/, torrents/

Critical: Library Path Management

NEVER edit options.xml directly to change library paths. Jellyfin ignores changes made directly to the file while running, and on restart it overwrites the file from its internal state.

Always use the API to add/remove paths:

# Add a path to a library
curl -X POST "http://localhost:8096/Library/VirtualFolders/Paths" \
  -H "Authorization: MediaBrowser Token=\"<token>\"" \
  -H "Content-Type: application/json" \
  -d '{"Name":"Shows","PathInfo":{"Path":"/mnt/media/tv"}}'

# Remove a path from a library
curl -X DELETE "http://localhost:8096/Library/VirtualFolders/Paths?name=Shows&path=%2Fmnt%2Fmedia%2Ftv&refreshLibrary=false" \
  -H "Authorization: MediaBrowser Token=\"<token>\""

Root Cause History: TV Shows Not Appearing (April 2026)

The Recordings library was accidentally configured with path /mnt/media (the entire media mount) instead of /mnt/media/recordings. This caused:

  • Recordings library to scan and "own" all TV shows and movies
  • Shows library to have no path configured (empty PathInfos) — never scanned /mnt/media/tv
  • All items getting TopParentId pointing to the /mnt/media Folder (not Shows CollectionFolder)
  • Jellyfin auto-creating a Recordings2 library whenever LiveTV checked /mnt/media/recordings didn't match Recordings' path /mnt/media

Fix: Use API to remove /mnt/media from Recordings, add /mnt/media/recordings to Recordings, add /mnt/media/tv to Shows, delete Recordings2, wipe BaseItems table (preserving UserData), restart + scan.

DB Wipe Command (preserves UserData/watch history)

DELETE FROM AncestorIds; DELETE FROM BaseItemImageInfos;
DELETE FROM BaseItemMetadataFields; DELETE FROM BaseItemProviders;
DELETE FROM BaseItemTrailerTypes; DELETE FROM Chapters;
DELETE FROM MediaStreamInfos; DELETE FROM AttachmentStreamInfos;
DELETE FROM TrickplayInfos; DELETE FROM KeyframeData;
DELETE FROM PeopleBaseItemMap; DELETE FROM Peoples;
DELETE FROM MediaSegments; DELETE FROM ItemValuesMap;
DELETE FROM ItemValues; DELETE FROM BaseItems; VACUUM;

Run as: sudo sqlite3 /var/lib/jellyfin/data/jellyfin.db "..." (Must stop Jellyfin first: sudo systemctl stop jellyfin)

Recordings2 Auto-Creation

If a Recordings2 library appears, it means LiveTV's recording path in /etc/jellyfin/livetv.xml doesn't match the Recordings library path. Fix via API (remove/add paths) rather than editing XML files.

Dotfiles

  • Gitea: http://192.168.88.200:3000/jgitta/dotfiles.git
  • Token (read/write): 56ac53def371df34d8f9c4b5580b28d4f62ab1ab
  • Includes: micro config, bash aliases, update-dotfiles alias
  • Preferred editor: micro (never nano)

Backups

  • PBS (VM107, 192.168.88.60): nightly full backups of all VMs
  • TrueNAS (192.168.88.24): bulk storage backups

Key Notes

  • KSM enabled with ksmtuned on Proxmox host
  • Watchtower runs on Siklos but Pi-hole is excluded from auto-updates
  • When restoring VMs: restore all disks to HD4T-2 first, then qm disk move OS disk to nvme-thin
  • delete_vm MCP tool removes all disks — always confirm before running

Proxmox Host Physical Memory Inventory (April 2026)

  • Host: jg-hud / 192.168.88.25
  • Installed memory: 112GB total (documentation previously rounded this to 110GB)
  • Maximum supported capacity reported by DMI: 1TB
  • ECC: Multi-bit ECC

Installed DIMMs

  • CPU1
    • CPU1_A0 / DIMM1 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 718BE307, Rank 2
    • CPU1_B0 / DIMM3 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 718BE31F, Rank 2
    • CPU1_C0 / DIMM2 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 11455775, Rank 2
    • CPU1_D0 / DIMM4 — 32GB DDR4-2133, HP, Part HP24D4R7D4MAM-32, Serial ED2DB54D, Rank 2
    • CPU1_B1 / DIMM5 — empty
    • CPU1_D1 / DIMM6 — empty
  • CPU2
    • CPU2_A0 / DIMM1 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 11455770, Rank 2
    • CPU2_B0 / DIMM3 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 718BE3C1, Rank 2
    • CPU2_C0 / DIMM2 — 8GB DDR4-2133, Hynix, Part HMA41GR7AFR8N-UH, Serial 718BE3B1, Rank 2
    • CPU2_D0 / DIMM4 — 32GB DDR4-2133, HP, Part HP24D4R7D4MAM-32, Serial EA2DB84D, Rank 2
    • CPU2_B1 / DIMM5 — empty
    • CPU2_D1 / DIMM6 — empty

Memory Resale Valuation (April 2026)

  • Market estimate based on current used listings and reseller references:
    • 8GB DDR4-2133 Hynix ECC sticks: ~$45 each
    • 32GB DDR4-2133 HP server sticks: ~$200 each
  • Proxmox installed memory estimated resale value:
    • 6 × 8GB Hynix = ~$270
    • 2 × 32GB HP = ~$400
    • Total = ~$670
  • Workstation installed memory estimated resale value:
    • 3 × 8GB Hynix = ~$135
  • Combined estimated resale value for both systems' installed memory:
    • ~$805 total

DNS Resolution Flow (Split-DNS)

All *.jgitta.com subdomains resolve internally to Caddy (192.168.88.110) via MikroTik static DNS entries — not through Cloudflare/public DNS. If a subdomain doesn't resolve internally, check MikroTik static DNS first, then Caddy config.

  • Internal: MikroTik static entries → 192.168.88.110 (Caddy)
  • External: Cloudflare A records → 184.170.161.177 (WAN) → NAT → Caddy
  • Other names: Pi-hole (192.168.88.27:53) handles upstream forwarding
  • .homenet names: MikroTik static DNS only (e.g., siklos.homenet, jellyfin.homenet)
  • IoT DNS: Force-redirected to Pi-hole via MikroTik DSTNAT rules

Firewall gotcha: vlan20-IoT is dynamically added to the WAN interface list. NAT rules using in-interface-list=WAN will match IoT traffic. WAN-facing rules must use in-interface=ether1 instead.

Service Architecture — Native vs Docker

VM102 (jellyfin, 192.168.88.10) — native systemd for core services:

  • jellyfin.service — native systemd
  • qbittorrent-nox.service — native systemd
  • me.proton.vpn.split_tunneling.service — native systemd
  • Radarr, Sonarr, Prowlarr, FlareSolverr — Docker containers

VM103 (next, 192.168.88.62) — Nextcloud native Apache:

  • Nextcloud 33.0.0 — native Apache (/etc/apache2/sites-enabled/nextcloud.conf)
  • Web root: /var/www/nextcloud/
  • Config: /var/www/nextcloud/config/config.php
  • Data dir: /mnt/nextcloud-data (local 2TB disk /dev/sdb1, ~65% used)
  • DB: MySQL on localhost, db nextcloud, user nextcloud
  • Tiered storage mounts:
    • Warm: 192.168.88.25:/nvme5-1tb/nextcloud-data/mnt/warm-storage (900GB NFS)
    • Cold: 192.168.88.24:/mnt/pool1/cold-storage/mnt/cold-storage (58TB NFS from TrueNAS)
  • Media: 192.168.88.25:/mnt/big-11t/media/mnt/media

VM112 / Siklos (192.168.88.27) — all services Docker; compose files at /srv/docker/<service>/ (RAM reduced to 12GB after photo services migrated out)

VM113 / photos (192.168.88.32) — dedicated photo services VM, Docker:

  • PhotoPrism — port 2342, compose /srv/docker/photoprism/docker-compose.yml
    • Storage: /srv/docker/photoprism/storage_data/ (14GB)
    • DB: MariaDB 11 at /srv/docker/photoprism/db_data/
  • Immich — port 2283, compose /srv/docker/immich/docker-compose.yml
    • Library: /srv/docker/immich/library/ (22GB)
    • DB: PostgreSQL at /srv/docker/immich/postgres/
  • NFS: /mnt/photos from 192.168.88.25:/mnt/big-11t/photos
  • Node exporter: port 9100

ThinkStation workstation (192.168.88.41) — Linux Mint 22.3 (separate machine from Proxmox host at .25):

  • Frigate NVR — Docker, image ghcr.io/blakeblackshear/frigate:stable-tensorrt
    • Compose: /opt/frigate/docker-compose.yml
    • Ports: 8971 (web UI), 5000, 85548555 (RTSP), 8555/udp
  • Open-WebUI — Docker (no external ports)
  • Disks: OS /dev/sda2 (234GB, 73%), /dev/sdb2 14TB HD at /mnt/14TB-HD (72%), /dev/nvme0n1p1 469GB at /mnt/INTEL-SSD, /dev/sdc1 1.8TB at /mnt/StorFly-SSD
  • NFS mount: /mnt/photos from 192.168.88.25:/mnt/big-11t/photos

VM Disk → Storage Pool Mapping

VM Disk Pool Size Notes
VM102 jellyfin scsi0 (OS) big-11t 32GB
VM102 jellyfin scsi1 (media) big-11t 6TB /mnt/media inside VM
VM103 next scsi0 (OS) nvme-thin 32GB
VM103 next scsi1 (data) nvme-thin 2TB local nextcloud data disk
VM106 haos scsi0 HD4T-2 32GB
VM107 pbs scsi0 SSD-1.7T 32GB
VM112 siklos scsi0 nvme-thin 250GB

Storage pool usage (as of April 2026):

Pool Type Total Used%
nvme-thin lvmthin 4.4TB 39%
big-11t dir 10.8TB 59%
SSD-1.7T dir 1.7TB 70%
HD4T-1 dir 3.6TB 70%
HD4T-2 dir 3.6TB 0.2%
pbs PBS 64TB 23%
nextcloud-fast zfspool INACTIVE
nvme4-2tb zfspool 1.8TB 0%
nvme5-1tb zfspool 900GB 0%

NFS Export Map

From jg-hud (192.168.88.25):

Export Clients Mounted by
/mnt/big-11t/media 192.168.88.0/24 VM102 (/mnt/media), VM103 (/mnt/media)
/mnt/big-11t/photos 192.168.88.0/24 VM112 (/mnt/photos), ThinkStation (/mnt/photos)
/nvme5-1tb/nextcloud-data 192.168.88.62 only VM103 (/mnt/warm-storage)

From TrueNAS (192.168.88.24):

Export Mounted by
/mnt/pool1/cold-storage VM103 (/mnt/cold-storage, 58TB)
PBS dataset VM107 PBS (/mnt/pbsdataset/pbs-store)

Backup Schedule & Retention

Job 1 — PBS (enabled): Mon/Wed/Fri at 21:00

  • All VMs/CTs except VM107 (PBS itself)
  • Storage: pbs (PBS datastore pbs-store on TrueNAS NFS at /mnt/pbsdataset/pbs-store)
  • Retention: keep-daily=7, keep-weekly=4, keep-monthly=3
  • Email notification: jgitta@jgitta.com

Job 2 — TrueNAS NFS (disabled): Sun/Tue/Thu/Sat at 00:00

  • All VMs, storage: Proxmox-TrueNAS-NFS, keep-last=5

TrueNAS (192.168.88.24)

  • TrueNAS SCALE 24.10.2.4
  • pool1: RAIDZ2, 8 disks, ~63.7TB used / ~104.4TB total, ONLINE/healthy
    • Hosts PBS backup store (NFS-exported to VM107)
    • Hosts cold-storage NFS export (58TB, mounted on VM103)
  • API: use curl -sk https://192.168.88.24/api/v2.0/<endpoint> -u "root:<password>"
  • MCP connection is broken — use curl API directly
  • Disks with SMART warnings: sda/9JH31S2T (40 unreadable, 24 ATA errors), sdh/9JG47UTT (13 ATA errors)

Log Locations

Service Location Command
Jellyfin /var/log/jellyfin/ tail -f /var/log/jellyfin/jellyfin$(date +%Y%m%d).log on VM102
FFmpeg transcode /var/log/jellyfin/FFmpeg.Transcode-*.log VM102
Caddy systemd journal journalctl -u caddy -f on CT202
Pi-hole FTL DB / journal /etc/pihole/pihole-FTL.db, journalctl -u pihole-FTL on Siklos
Docker services (Siklos) docker logs docker compose logs -f in /srv/docker/<service>/
Proxmox /var/log/pve/ on jg-hud (192.168.88.25)
qBittorrent systemd journal journalctl -u qbittorrent-nox -f on VM102
ProtonVPN systemd journal journalctl -u me.proton.vpn.split_tunneling -f on VM102

Uptime Kuma Monitors (Siklos, port 3001)

HTTP checks: Caddy Health, Gitea, Glances, Grafana, Homarr, Home Assistant, Immich, Jellyfin, Karakeep, Linkwarden, MeshCentral, Nextcloud, PBS, Pi-hole web, Prometheus Port checks: MikroTik SSH (:22), Pi-hole DNS (:53), Proxmox SSH (:22), Siklos SSH (:22) DNS check: Pi-hole DNS resolution (google.com via 192.168.88.27:53) Metric check: Node Exporter on ThinkStation (192.168.88.41:9100)

Not monitored: VM102 SSH, qBittorrent, ProtonVPN status, Radarr/Sonarr/Prowlarr health, TrueNAS, Frigate