# Codebase Concerns **Analysis Date:** 2026-02-04 ## Tech Debt **IP Addressing Scheme Inconsistency:** - Issue: Container IPs don't follow VMID convention. NPM (VMID 100) is at .1, Dockge (VMID 101) at .10, PBS (VMID 106) at .6, instead of matching .100, .101, .106 - Files: `homelab-documentation.md` (lines 139-159) - Impact: Manual IP tracking required, DNS records must be maintained separately, new containers require manual IP assignment planning, documentation drift risk - Fix approach: Execute TODO task to reorganize vmbr1 to VMID=IP scheme (.100-.253 range), update NPM proxy hosts, DNS records (lab.georgsen.dk), and documentation **DNS Record Maintenance Manual:** - Issue: Internal DNS (Technitium) and external DNS (dns.services) require manual updates when IPs/domains change - Files: `homelab-documentation.md` (lines 432-449), `~/bin/dns` script - Impact: Risk of records becoming stale after IP migrations, no automation for new containers - Fix approach: Implement `dns-services` helper script (TODO.md line 27) with API integration for automatic updates **Unimplemented Helper Scripts:** - Issue: `dns-services` API integration promised in TODO but not implemented - Files: `TODO.md` (line 27), `dns-services/credentials` exists but script doesn't - Impact: Manual dns.services operations required, cannot automate domain setup - Fix approach: Create `~/bin/dns-services` wrapper (endpoint documented in TODO) **Ping Capability Missing on 12 Containers:** - Issue: Unprivileged LXC containers drop cap_net_raw, breaking ping on VMIDs 100, 101, 102, 103, 104, 105, 107, 108, 110, 111, 112, 114, 115, 1000 - Files: `TODO.md` (lines 31-33), `CLAUDE.md` (line 252-255) - Impact: Health monitoring fails, network diagnostics broken, Telegram bot status checks incomplete (bot has no ping on home network itself), Uptime Kuma monitors may show false negatives - Fix approach: Run `setcap cap_net_raw+ep /bin/ping` on each container (must be reapplied after iputils-ping updates) **Version Pinning Warnings:** - Issue: CLAUDE.md section 227-241 warns about hardcoded versions becoming stale - Files: `homelab-documentation.md` (lines 217, 228, 239), `~/bin/updates` script shows version checking is implemented but some configs have `latest` tags - Impact: Security patch delays, incompatibilities when manually deploying services - Fix approach: Always query GitHub API for latest versions (updates script does this correctly for discovery phase) ## Known Bugs **Telegram Bot Inbox Storage Race Condition:** - Symptoms: Concurrent message writes could corrupt inbox file, messages may be lost - Files: `telegram/bot.py` (lines 39, 200-220 message handling), `~/bin/telegram` (lines 73-79 clear command) - Trigger: Multiple rapid messages from admin or concurrent bot operations - Workaround: Clear inbox frequently and check for corruption; bot currently appends to file without locking - Root cause: File-based inbox with no atomic writes or mutex protection **PBS Backup Mount Dependency Not Enforced:** - Symptoms: PBS services may start before Synology CIFS mount is available, backup path unreachable - Files: `homelab-documentation.md` (lines 372-384), container 106 config - Trigger: System reboot when Tailscale connectivity is delayed - Workaround: Manual restart of proxmox-backup-proxy and proxmox-backup services - Root cause: systemd dependency chain `After=mnt-synology.mount` doesn't guarantee mount is ready at service start time **DragonflyDB Password in Plain Text in Documentation:** - Symptoms: Database password visible in compose file and documentation - Files: `homelab-documentation.md` (lines 248-250) - Trigger: Anyone reading docs or inspecting git history - Workaround: Consider password non-critical if container only accessible on internal network - Root cause: Password stored in version control and documentation rather than .env or secrets file **NPM Proxy Host 18 (mh.datalos.dk) Not Configured:** - Symptoms: Domain not resolving despite DNS record missing and NPM entry (ID 18) mentioned in TODO - Files: `TODO.md` (line 29), `homelab-documentation.md` (proxy hosts section) - Trigger: Accessing mh.datalos.dk from browser - Workaround: Must be configured manually via NPM web UI - Root cause: Setup referenced in TODO but not completed ## Security Considerations **Exposed Credentials in Git History:** - Risk: Credential files committed (credentials, SSH keys, telegram token examples) - Files: All credential files in `telegram/`, `pve/`, `forgejo/`, `dns/`, `dockge/`, `uptime-kuma/`, `beszel/`, `dns-services/` directories (8+ files) - Current mitigation: Files are .gitignored in main repo but present in working directory - Recommendations: Rotate all credentials listed, audit git log for historical commits, use HashiCorp Vault or pass for credential storage, document secret rotation procedure **Public IP Hardcoded in Documentation:** - Risk: Home IP 83.89.248.247 exposed in multiple locations - Files: `homelab-documentation.md` (lines 98, 102), `CLAUDE.md` (line 256) - Current mitigation: IP is already public/static, used for whitelist access - Recommendations: Document that whitelisting this IP is intentional, no other PII mixed in **Telegram Bot Authorization Model Too Permissive:** - Risk: First user to message bot becomes admin automatically with no verification - Files: `telegram/bot.py` (lines 86-95) - Current mitigation: Bot only responds to authorized user, requires bot discovery - Recommendations: Require multi-factor authorization on first start (e.g., PIN from environment variable), implement audit logging of all bot commands **Database Credentials in Environment Variables:** - Risk: DragonflyDB password passed via Docker command line (visible in `docker ps`, logs, process listings) - Files: `homelab-documentation.md` (line 248) - Current mitigation: Container only accessible on internal vmbr1 network - Recommendations: Use Docker secrets or mounted .env files instead of command-line arguments **Synology CIFS Credentials in fstab:** - Risk: SMB credentials stored in plaintext in fstab file with mode 0644 (world-readable) - Files: `homelab-documentation.md` (line 369) - Current mitigation: Mounted on container-only network, requires PBS container access - Recommendations: Use credentials file with mode 0600, rotate credentials regularly, monitor file permissions **SSH Keys Included in Documentation:** - Risk: Public SSH keys hardcoded in CLAUDE.md setup examples - Files: `CLAUDE.md` and `homelab-documentation.md` SSH key examples - Current mitigation: Public keys only (not private), used for container access - Recommendations: Rotate these keys if documentation is ever exposed, don't include in public repos ## Performance Bottlenecks **Single NVMe Storage (RAID0) Without Local Redundancy:** - Problem: Core server has 2x1TB NVMe in RAID0 (striped, no redundancy) - Files: `homelab-documentation.md` (lines 17-24) - Cause: Cost optimization for Hetzner dedicated server - Impact: Single drive failure = total data loss; database corruption risk from RAID0 stripe inconsistency - Improvement path: (1) Ensure PBS backups run successfully to Synology, (2) Test backup restore procedure monthly, (3) Plan upgrade path if budget allows (3-way mirror or RAID1) **Backup Dependency on Single Tailscale Gateway:** - Problem: All PBS backups to Synology go through Tailscale relay (10.5.0.134), single point of failure - Files: `homelab-documentation.md` (lines 317-427) - Cause: Synology only accessible via Tailscale network, relay container required - Impact: Tailscale relay downtime = backup failure; no local backup option - Improvement path: (1) Add second Tailscale relay for redundancy, (2) Explore PBS direct SSH backup mode, (3) Monitor relay container health **DNS Queries All Route Through Single Technitium Container:** - Problem: All internal DNS (lab.georgsen.dk) goes through container 115, DHCP defaults to this server - Files: `homelab-documentation.md` (lines 309-315), container config - Cause: Single container architecture - Impact: DNS outage = network unreachable (containers can't resolve any hostnames) - Improvement path: (1) Deploy DNS replica on another container, (2) Configure DHCP to use multiple DNS servers, (3) Set upstream DNS fallback **Script Execution via Telegram Bot with Subprocess Timeout:** - Problem: Bot runs helper scripts with 30-second timeout, commands like PBS backup query can exceed limit - Files: `telegram/bot.py` (lines 60-78, 191) - Cause: Helper scripts do remote SSH execution, network latency variable - Impact: Commands truncated mid-execution, incomplete status reports, timeouts on slow networks - Improvement path: Increase timeout selectively, implement command queuing, cache results for frequently-called commands ## Fragile Areas **Installer Shell Script with Unimplemented Sections:** - Files: `pve-homelab-kit/install.sh` (495+ lines with TODO comments) - Why fragile: Multiple TODO placeholders indicate incomplete implementation; wizard UI done but ~30 implementation TODOs remain - Safe modification: (1) Don't merge branches without running through full install, (2) Test each section independently, (3) Add shell `set -e` error handling - Test coverage: Script has no tests, no dry-run mode, no rollback capability **Container Configuration Manual in LXC Config Files:** - Files: `/etc/pve/lxc/*.conf` across Proxmox host (not in repo, not version controlled) - Why fragile: Critical settings (features, ulimits, AppArmor) outside version control, drift risk after manual fixes - Safe modification: Keep backup copies in `homelab-documentation.md` (already done for PBS), automate via Terraform/Ansible if future containers added - Test coverage: Config changes only tested on live container (no staging env) **Helper Scripts with Hardcoded IPs and Paths:** - Files: `~/bin/updates` (lines 16-17, 130), `~/bin/pbs`, `~/bin/pve`, `~/bin/dns` - Why fragile: DOCKGE_HOST, PVE_HOST hardcoded; if IPs change during migration, all scripts must be updated manually - Safe modification: Extract to config file (e.g., `/etc/homelab/config.sh` or environment variables) - Test coverage: Scripts tested against live infrastructure only **SSH-Based Container Access Without Key Verification:** - Files: `~/bin/updates` (lines 115-131), scripts use `-q` flag suppressing host key checks - Why fragile: `ssh -q` disables StrictHostKeyChecking, vulnerable to MITM; scripts assume SSH keys are pre-installed - Safe modification: Add `-o StrictHostKeyChecking=accept-new` to verify on first connection, document key distribution procedure - Test coverage: SSH connectivity assumed working **Backup Monitoring Without Alerting on Failure:** - Files: `~/bin/pbs`, `telegram/bot.py` (status command only, no automatic failure alerts) - Why fragile: Failed backups only visible if manually checked; no monitoring of backup completion - Safe modification: Add systemd timer to check PBS status hourly, send Telegram alert on failure - Test coverage: Manual checks only ## Scaling Limits **Container IP Space Exhaustion:** - Current capacity: vmbr1 is /24 (256 IPs, .0-.255), DHCP range .100-.200 (101 IPs available for DHCP), static IPs scattered - Limit: After ~150 containers, IP fragmentation becomes difficult to manage; DHCP range conflicts with static allocation - Scaling path: (1) Implement TODO IP scheme (VMID=IP), (2) Expand to /23 (512 IPs) if more containers needed, (3) Use vmbr2 (vSwitch) for secondary network **Backup Datastore Single Synology Volume:** - Current capacity: Synology `pbs-backup` share unknown size (not documented) - Limit: Unknown when share becomes full; no warning system implemented - Scaling path: (1) Document share capacity in homelab-documentation.md, (2) Add usage monitoring to `beszel` or Uptime Kuma, (3) Plan expansion to second NAS **Dockge Stack Limit:** - Current capacity: Dockge container 101 running ~8-10 stacks visible in documentation - Limit: No documented resource constraints; may hit CPU/RAM limits on Hetzner AX52 with more containers - Scaling path: (1) Monitor Dockge resource usage via Beszel, (2) Profile Dragonfly memory usage, (3) Plan VM migration for heavy workloads **DNS Query Throughput:** - Current capacity: Single Technitium container handling all internal DNS - Limit: Container CPU/RAM limits unknown; no QPS monitoring - Scaling path: (1) Add DNS replica, (2) Monitor query latency, (3) Profile Technitium logs for slow queries ## Dependencies at Risk **Technitium DNS (Unmaintained Risk):** - Risk: TechnitiumSoftware/DnsServer has irregular commit history; last significant release early 2024 - Impact: Security fixes may be delayed; compatibility with newer Linux kernels unknown - Migration plan: (1) Profile current Technitium features used, (2) Evaluate CoreDNS or Dnsmasq alternatives, (3) Plan gradual migration with dual DNS **DragonflyDB as Redis Replacement:** - Risk: Dragonfly smaller ecosystem than Redis; breaking changes possible in minor updates - Impact: Applications expecting Redis behavior may fail; less community support for issues - Migration plan: (1) Pin Dragonfly version in compose file (currently `latest`), (2) Test upgrades in dev environment, (3) Document any API incompatibilities found **Dockge (Single Maintainer Project):** - Risk: Dockge maintained by one developer (louislam); bus factor high - Impact: If maintainer loses interest, fixes and features stop; dependency on their release schedule - Migration plan: (1) Use Dockge for UI only, don't depend on it for production orchestration, (2) Keep docker-compose expertise on team, (3) Consider Portainer as fallback alternative **Forgejo (Younger than Gitea):** - Risk: Forgejo is recent fork of Gitea; database schema changes possible in patch versions - Impact: Upgrades may require manual migrations; data loss risk if migration fails - Migration plan: (1) Test Forgejo upgrades on backup copy first, (2) Document upgrade procedure, (3) Keep Gitea as fallback if Forgejo breaks ## Missing Critical Features **No Automated Health Monitoring/Alerting:** - Problem: Status checks exist (via Telegram bot, Uptime Kuma) but no automatic alerts when services fail - Blocks: Cannot sleep soundly; must manually check status to detect outages - Implementation path: (1) Add Uptime Kuma HTTP monitors for all public services, (2) Create Telegram alert webhook, (3) Monitor PBS backup success daily **No Automated Certificate Renewal Verification:** - Problem: NPM handles Let's Encrypt renewal, but no monitoring for renewal failures - Blocks: Certificates could expire silently; discovered during service failures - Implementation path: (1) Add Uptime Kuma alert for HTTP 200 on https://* services, (2) Add monthly certificate expiry check, (3) Set up renewal failure alerts **No Disaster Recovery Runbook:** - Problem: Procedures for rescuing locked-out server (Hetzner Rescue Mode) not documented - Blocks: If SSH access lost, cannot recover without external procedures - Implementation path: (1) Document Hetzner Rescue Mode recovery steps, (2) Create network reconfiguration backup procedures, (3) Test rescue mode monthly **No Change Log / Audit Trail:** - Problem: Infrastructure changes not logged; drift from documentation occurs silently - Blocks: Unknown who made changes, when, and why; cannot track config evolution - Implementation path: (1) Add git commit requirement for all manual changes, (2) Create change notification to Telegram, (3) Weekly drift detection report **No Secrets Management System:** - Problem: Credentials scattered across plaintext files, git history, and documentation - Blocks: Cannot safely share access with team members; no credential rotation capability - Implementation path: (1) Deploy HashiCorp Vault or Vaultwarden, (2) Migrate all secrets to vault, (3) Create credential rotation procedures ## Test Coverage Gaps **PBS Backup Restore Not Tested:** - What's not tested: Full restore procedures; assumed to work but never verified - Files: `homelab-documentation.md` (lines 325-392), no restore test documented - Risk: If restore needed, may discover issues during actual data loss emergency - Priority: HIGH - Add monthly restore test procedure (restore single VM to temporary location, verify data integrity) **Network Failover Scenarios:** - What's not tested: What happens if Tailscale relay (1000) goes down, if NPM container restarts, if DNS returns SERVFAIL - Files: No documented failure scenarios - Risk: Unknown recovery time; applications may hang instead of failing gracefully - Priority: HIGH - Document and test each service's failure mode **Helper Script Error Handling:** - What's not tested: Scripts with SSH timeouts, host unreachable, malformed responses - Files: `~/bin/updates`, `~/bin/pbs`, `~/bin/pve` (error handling exists but not tested against failures) - Risk: Silent failures could go unnoticed; incomplete output returned to caller - Priority: MEDIUM - Add error injection tests (mock SSH failures) **Telegram Bot Commands Under Load:** - What's not tested: Bot response when running concurrent commands, or when helper scripts timeout - Files: `telegram/bot.py` (no load tests, concurrency behavior unknown) - Risk: Bot may hang or lose messages under heavy load - Priority: MEDIUM - Add load test with 10+ concurrent commands **Container Migration (VMID IP Scheme Change):** - What's not tested: Migration of 15+ containers to new IP scheme; full rollback procedures - Files: `TODO.md` (line 5-15, planned but not executed) - Risk: Single IP misconfiguration could take multiple services offline - Priority: HIGH - Create detailed migration runbook with rollback at each step before executing --- *Concerns audit: 2026-02-04*