Notes, config snippets, and hard-won gotchas from operating a personal offensive-security and infrastructure homelab. Everything here is sanitized — no personal IPs, hostnames, or credentials.
Multi-host lab running virtualization, containerized self-hosted services, and a private mesh network across heterogeneous endpoints.
- Main workstation — macOS (Intel Mac); Colima Docker runtime; VMware Fusion for Windows/Kali VMs
- Secondary Linux workstation — Debian-based; Kali Linux tooling
- Edge router — Raspberry Pi 4B running as home router (DHCP, routing, traffic management)
- Mobile — iOS endpoint on the mesh
- Immich — self-hosted photo library, multi-terabyte backing store on external drives
- Self-hosted LLM stack — local inference for privacy-sensitive workloads
- Custom TypeScript agent/skill infrastructure — task orchestration and workflow automation
- Tailscale — WireGuard-based mesh across macOS, Linux, Raspberry Pi, and iOS; SSH-over-tailnet for remote admin
- Raspberry Pi 4B router — DHCP, routing tables, traffic management on the local segment
On large photo libraries, the stock Immich Docker Compose hits the V8 heap 2 GiB default cap and enters an ~18-minute restart loop that looks like normal restarts but never converges.
Fix: NODE_OPTIONS=--max-old-space-size=4096 in the Immich container environment.
docker-compose services can exit 255 with mkdir /Volumes/X: permission denied when Colima virtiofs mounts blip.
Fix: docker compose up -d — the mount typically re-establishes without a full Colima restart. If the error persists, colima stop && colima start and re-up.
Docker's (healthy) status only reflects the last successful health probe — it does not reflect whether the container is stable.
Rule: always cross-check RestartCount and StartedAt across sibling services. A container that's "healthy" but has restarted 40 times in the last hour is not healthy in any meaningful sense.
The macOS GUI Tailscale app can't register itself as an SSH server due to Apple sandboxing — the --ssh flag silently no-ops.
Fix: enable the built-in macOS sshd and reach it over the tailnet.
The macOS GUI Tailscale app can't bind port 443 as a non-root process, so tailscale serve and tailscale funnel silently fail.
Fix: use plain http://host:port over the tailnet, or run Tailscale from CLI with elevated permissions.
- Container orchestration and troubleshooting (Docker, Docker Compose, Colima)
- Node.js / V8 memory profiling under production load
- Mesh networking (WireGuard, DNS, routing tables)
- Linux system administration
- Multi-terabyte storage management (external drives, dedup workflows)
- Root-cause analysis in cascading service failures
- Migrate persistent Immich data to a dedicated NAS with redundant storage
- Consolidate the external-drive photo/video archive with content-hash deduplication
- Add Grafana + Prometheus monitoring for the container stack
- Automate homelab backups with restic