I build, automate, and defend infrastructure - security-first. NoxLab is where I prove it hands-on: one cheap second-hand workstation running a small org's worth of services end to end - a segmented network, a tiered Docker platform, a self-hosted GitLab with a security-conscious publishing pipeline, a SIEM with local-LLM alert triage, and a tested rebuild-from-bare-metal recovery path.
One box, built and run end to end - and what each part is evidence of. Every claim links to the write-up that backs it.
The "servers" are mostly VMs on a single second-hand workstation. It does almost everything.
Picked because it was cheap and takes DDR3 ECC. Ubuntu LTS because I wanted to stay in the Debian family and LTS was the boring, correct choice.
It shipped with a Quadro K2000 whose nouveau driver crashed the desktop every ~3 days like clockwork - a GNOME bug marked "won't fix". A GTX 1050 Ti fixed that with solid proprietary drivers and gave me headroom - which is exactly what unlocked the overnight Gemma triage, with a Jellyfin server next on the roadmap.
The whole staged storage set - two 1TB laptop drives plus a 128GB cache disk - cost about EUR 30.
Everything here runs on that one box. Each tile opens a console with the detail - what it does, and why it earns its place.
All five run on the one box (VirtualBox): the Wazuh SIEM appliance, Windows/Ubuntu/Fedora targets bridged to the LAN, and a NAT-isolated REMnux box for malware analysis. Click any for its real specs.
The full write-up, design decisions, and copy-adaptable templates. Each page is the real reference, not a teaser.
# one TLS front door; sensitive apps fenced to LAN + VPN
A new service gets HTTPS and its access rule from a handful of labels. Public things never open a port - they leave over an outbound tunnel.
→ full write-up: Network# self-hosted forge; what GitHub receives is one squashed commit
Everything lives on the internal GitLab first. Publishing strips the CI config and force-pushes a single orphan commit, so there is no history - and no old-commit secret - to leak.
→ full write-up: CI/CD Publishing# two runners, split by network egress - which jobs can reach the internet?
Egress is a capability granted to one job, not a default for every build. A poisoned dependency pulled during check has nowhere to phone home.
# agents on every machine report here; the single pane
Custom rules plus abuse.ch threat-intel lists raise the alerts. Overnight a local Gemma model triages them (see Ollama + Gemma).
→ full write-up: Security Stack# network IDS on the wire; matches flow into Wazuh
Signature + protocol analysis on the wire; matches become Wazuh alerts, so network and host detections share one timeline.
→ full write-up: Security Stack# the host that runs everything is a target too
Auditing, automated bans, a host firewall, and periodic hardening audits - the base layer everything else sits on.
→ full write-up: Security Stack# secrets encrypted at rest; decrypted only in memory, where needed
Committed as ciphertext, single source of truth per secret. The CI publish token, webhook secrets, and service env all live this way.
→ full write-up: Architecture# own recursive resolver, pinned to a loopback alias
Survives reboots and link changes, blocks ads/trackers, and keeps resolution entirely in-house. Pin the things that must not move.
→ full write-up: Network# DoH frontend so clients resolve over HTTPS, not plaintext :53
Terminates DNS-over-HTTPS on its own loopback alias and forwards to Unbound - encrypted resolution for clients, recursion stays local.
→ full write-up: Network# the only inbound port on the whole network (on the MikroTik edge)
One UDP port forwarded to OpenVPN; everything else is outbound-only. Public services dial out over a tunnel, so they have zero inbound surface.
→ full write-up: Network# boot-ordered tiers on isolated bridges
Ingress (Traefik) comes up first; apps sit behind it on a separate bridge with no lateral path across.
→ full write-up: Docker Platform# overnight L1 triage of the day's Wazuh alerts - in-house, on the GPU
Gemma is L1: it classifies each alert, keeps a self-updating correlation memory, pulls context from the Obsidian vault, and escalates what it cannot resolve to an L2 Claude review. The human keeps every verdict; telemetry never leaves the box.
→ full write-up: Security Stack# the rebuild playbook is the real DR artifact
Backups restore data; this restores the system - bare metal to running services. Layered backups (config + encrypted secrets) feed it.
→ full write-up: Backup & DR# the network's knowledge base - and the SOC agent's memory
The living docs of the whole lab - topology, runbooks, decisions - exposed over an MCP server so tooling (and the overnight LLM) can query it. These public pages are its sanitised cut.
→ full write-up: Architecture# the knowledge base as a typed API, not a copy
A small FastMCP server that exposes the Obsidian vault over the Model Context Protocol - typed read / search / write / status tools, over stdio or streamable-HTTP. It is how the overnight SOC agent does its RAG lookups and how I maintain the docs with Claude: the single source of truth is queried, never duplicated. Built security-first - localhost-bound by default, DNS-rebinding protection, secrets kept out of the code.
→ source: mcp-vault-ligament ↗# Windows endpoint-detection target, bridged to the LAN
Sysmon + a Wazuh agent ship Windows events to the SIEM. A snapshot-and-revert target - nothing of value lives on it.
→ full write-up: Network# general-purpose Linux lab, bridged to the LAN
Where configs, packages, and exploits get tried before they touch anything real.
→ full write-up: Network# malware analysis - deliberately NOT on the LAN
REMnux is the reverse-engineering / malware-analysis distro. Kept NAT-isolated so a live sample can't reach the rest of the lab.
→ full write-up: Network# a second distro family for cross-distro testing
Different package manager, SELinux on by default - so detections and playbooks get exercised beyond the Debian family.
→ full write-up: Network# the SIEM appliance itself - the heaviest workload on the box
Wazuh runs as a VM on the core. Agents across the host and the other VMs report in here; the overnight Gemma triage reads from it.
→ full write-up: Network