Zero Security

Hacking and Penetration Testing Stuff

Hacking Write-ups Blog Posts whoami Search View on GitHub
5 November 2026

Building a Home Cyber Range with Ludus on a Mini PC

by zero

Illustration: a small silver mini PC beams its network up into a glowing green cloud of virtual machines: a router, two domain controllers, a SQL server and two workstations on VLAN 10, an Elastic SIEM on VLAN 20, and a Kali attacker on VLAN 99 whose red attack path arcs across to the domain controller, all over matrix-style code rain.

Every red teamer, detection engineer and malware analyst eventually hits the same wall: you need somewhere safe and realistic to practise. Somewhere you can build a full Active Directory estate, detonate tooling, break things, and roll it all back without touching a client, a corporate network, or your own machine. The usual answer is “spin it up in the cloud”, but that bill adds up fast, and cyber ranges have an awkward requirement (hardware virtualisation) that makes cloud hosting either expensive or fiddly. A good answer is just to run it at home, on a mini PC the size of a decently stacked sandwich, with Ludus doing most of the heavy architectural systems lifting.

What Is Ludus?

Ludus is an open-source project from Bad Sector Labs that bills itself as “Cyber Ranges for Everyone.” Under the hood it stitches together Proxmox (the hypervisor), Packer (for building VM templates) and Ansible (for configuring everything), and wraps the lot in a simple CLI and API.

The model is beautifully simple:

Define your range in config, run one command, and Ludus builds the VMs, networks them, joins them to a domain, and applies your roles. Snapshot it, trash it, redeploy it. It is infrastructure-as-code for an entire adversary playground.

Ludus 2 added two things worth knowing about. Blueprints let you save a deployed range as a reusable, shareable package, and sources are catalogues of templates, roles and blueprints you can install from a git repo. Bad Sector Labs publish one that ships ready-made GOAD and AD + Elastic labs, so “build me a vulnerable multi-domain forest” is now literally one command. There is also a web UI, but that is a Pro/Enterprise feature; the CLI and API are free and they are all you need at home.

Why It’s So Useful

Another GMKtec Computer with a Very Different Job

If you read my two posts on hardware implants, you already know I have a soft spot for GMKtec’s little boxes. In Part 1 the NucBox G5 was the attacker’s box: a palm-sized Kali machine we drop behind a desk on a physical engagement, with a cellular uplink so its traffic never touches the client’s network. Part 2 went smaller still, down to cables and keyboards.

This post flips it round. The NucBox K8 is the box that stays at home and gets attacked. It hosts the fake victims network domain, the workstations, the SIEM, and the Kali box that goes after them. Same vendor family, opposite side of the engagement. (And yes, there is a third one: my NEO-X1 Pro has grown to five GPUs and become a local AI lab. That is the next post.)

The Hardware: Why a Mini PC Makes Sense

Ludus’s requirements are refreshingly modest. Per the install docs, you need:

That’s a spec a modern mini PC laughs at. I run mine on a GMKtec NucBox K8, the original silver model, which is the exact box the Ludus authors use themselves and recommend in their bare-metal guide. It’s an AMD Ryzen 7 8845HS (8 cores / 16 threads) that scores about 29,000 on Passmark, nearly five times the Ludus floor, so the CPU is never the bottleneck, and Proxmox does a good job of sharing it out between the VMs.

The original silver GMKtec NucBox K8, front and rear views

Here is what’s inside it. Pull it apart, click the callouts, and flick on “Ludus essentials” to see the three things that actually matter for a range host.

Open the exploded view full screen ↗

The case dimensions are the manufacturer’s; the internal layout follows the published teardowns (lid off, four screws, fan tray out, and you’re at the memory and storage). It’s a reconstruction, not CAD.

The two things that matter for a range host are RAM and storage, and this is where the mini PC route shines:

Here’s mine going together back in July 2024, where it lives now, and what two years of running 24/7 did to its fan (more on that at the end). Use the buttons, or your arrow keys once you’ve clicked into the gallery, to step through.

GMKtec no longer sells the original K8. The current version is the NucBox K8 Plus (about £410 with 32 GB and 1 TB at the time of writing, less as a barebones), and it’s the better buy: same 8845HS, dual Intel I226V 2.5GbE, two USB4 ports, a CNC aluminium mid-frame with bigger fans, and an OCuLink port so you can bolt on an external GPU later. There are reviews of the original K8 and the K8 Plus if you want the full rundown.

GMKtec K8 Plus feature summary: four-screen display output, Radeon 780M, dual PCIe 4.0 M.2 2280 slots, DDR5-5600 SO-DIMM up to 96 GB, dual cooling fans, Wi-Fi 6

Want more? If budget allows, the AMD Strix Halo boxes are the dream range hosts. The GMKtec EVO-X2 and EVO-X3 pack the Ryzen AI Max+ 395 with 128 GB of unified memory, enough to run a serious range and local AI models on the same box. And of course there are plenty of cheaper alternatives from other vendors with different CPU, RAM and port trade-offs. The Ludus requirements are the only real constraint.

The Economics: Self-Host vs Cloud

This is the part that sealed it for me.

To run something equivalent in the cloud you’re looking at an always-on instance with ~128 GB of RAM. An AWS r7i.4xlarge (16 vCPU, 128 GB) is $1.06 an hour on demand, roughly $770 a month, call it £580. And that instance can’t even do nested virtualisation: for that you need a bare-metal instance, which starts at several times the price again.

Compare that to a one-off mini PC. A K8 Plus with 32 GB and 1 TB is about £410; my 96 GB, 2 × 2 TB build came to roughly double that. Running 24/7 it draws somewhere between 15 W idle and 60 W with a domain busy, which at the current UK price cap (26p/kWh) is roughly £3 to £12 of electricity a month. The cloud bill overtakes the cheap box in under three weeks and the big build inside two months. After that the hardware is pure savings, and it’s yours, sitting on your desk, with your lab data never leaving the house.

For a lab you leave running, self-hosting isn’t a bit cheaper. It’s a different order of magnitude.

Quick Setup (The General Shape)

Ludus is genuinely quick to get going. The whole thing is one install script, one template build and one YAML file. The official quick start is the best place to begin and walks through each step in detail; at a high level:

1. BIOS. Turn on hardware virtualisation (AMD-V / SVM on the K8). Pick the balanced power profile; the hot one buys you nothing for VMs.

2. Install Debian 13 from the netinst ISO. Untick the desktop environment, tick SSH server, and make sure the box is on wired ethernet. That’s it for the OS.

3. Run the installer. SSH in, become root, install the prerequisites and run the one-liner from the docs:

su -
apt update && apt install curl sudo ca-certificates
curl --proto '=https' --tlsv1.2 -sSf https://ludus.cloud/install | bash

Prefer to read before you run? Download the script with curl https://ludus.cloud/install > install.sh, read it, then run it. Always a good habit. The installer asks a handful of questions (accept the defaults if unsure), installs Proxmox and reboots. Afterwards, check progress with ludus-install-status.

4. Build templates. Export the API key, then start the builds and go and do something else; it takes a couple of hours.

 export LUDUS_API_KEY='JD.xxxxxxxx'   # leading space keeps it out of shell history
ludus templates list
ludus templates build                 # add --parallel 2 if the box can take it
ludus templates logs -f

5. Define and deploy a range. Every user gets a default range config (a DC, a Windows 11 workstation and a Kali box). Pull it, tweak it, push it back and deploy.

ludus range config get > range.yml
nano range.yml
ludus range config set -f range.yml
ludus range deploy
ludus range logs -f
ludus range status

When the deploy finishes, ludus range status shows the range and its VMs. This is a real default range: Ludus puts a router VM in front of every range, and each VM’s address follows 10.<range number>.<VLAN>.<last octet> from the config.

$ ludus range status
+---------+---------------+------------------+---------------+-------------------+-----------------+
| USER ID | RANGE NETWORK | LAST DEPLOYMENT  | NUMBER OF VMS | DEPLOYMENT STATUS | TESTING ENABLED |
+---------+---------------+------------------+---------------+-------------------+-----------------+
|   JD    |  10.2.0.0/16  | 2023-12-31 18:42 |       4       |      SUCCESS      |      FALSE      |
+---------+---------------+------------------+---------------+-------------------+-----------------+
+------------+-----------------------------------+-------+-------------+
| PROXMOX ID |              VM NAME              | POWER |     IP      |
+------------+-----------------------------------+-------+-------------+
|    107     | JD-router-debian13-x64            |  On   | 10.2.10.254 |
|    109     | JD-ad-dc-win2019-server-x64       |  On   | 10.2.10.11  |
|    113     | JD-ad-win11-22h2-enterprise-x64-1 |  On   | 10.2.10.21  |
|    114     | JD-kali                           |  On   | 10.2.99.1   |
+------------+-----------------------------------+-------+-------------+

A range file reads like this. Change the template names, RAM, VLAN or domain and redeploy; add a VM by adding a block.

ludus:
  - vm_name: "-DC01"
    hostname: "-DC01"
    template: win2022-server-x64-template
    vlan: 10
    ip_last_octet: 11
    ram_gb: 8
    cpus: 4
    windows:
      sysprep: false
    domain:
      fqdn: test.lab
      role: primary-dc
  - vm_name: "-WS01"
    hostname: "-WS01"
    template: win11-22h2-x64-enterprise-template
    vlan: 10
    ip_last_octet: 21
    ram_gb: 8
    cpus: 4
    windows:
      install_additional_tools: true
    domain:
      fqdn: test.lab
      role: member
  - vm_name: "-elastic"
    hostname: "-elastic"
    template: debian-13-x64-server-template
    vlan: 10
    ip_last_octet: 2
    ram_gb: 8
    cpus: 4
    linux: true
    roles:
      - badsectorlabs.ludus_elastic_container
  - vm_name: "-kali"
    hostname: "-kali"
    template: kali-x64-desktop-template
    vlan: 99
    ip_last_octet: 1
    ram_gb: 8
    cpus: 4
    linux: true
    testing:
      snapshot: false
      block_internet: false

6. Get in. Ludus runs a WireGuard server for you. Grab your profile, import it into the WireGuard client on your laptop, and the range VMs are reachable directly over RDP, SSH or the Kali box’s browser-based KasmVNC desktop.

ludus user wireguard > ludus.conf   # import on your laptop
ludus range rdp                     # zip of RDP files for the Windows VMs

7. Attack, revert, repeat. ludus testing start snapshots every VM in the range and blocks their internet; ludus testing stop reverts them. Go and break the domain, then put it back exactly how it was.

Shortcut: if what you want is a proper vulnerable forest to practise on, skip writing YAML and deploy the GOAD blueprint from Bad Sector Labs’ source. Two commands, then wait.

ludus range create -r GOAD --name GOAD --from-blueprint ludus-source-bsl/goad
ludus range deploy -r GOAD

GOAD (Game of Active Directory) from Orange Cyberdefense is a great first lab, packed with Active Directory attacks. It builds two forests and three domains (sevenkingdoms.local, its child north.sevenkingdoms.local, and essos.local) across three domain controllers and two member servers. The misconfigurations are deliberate: trusts between the domains, MSSQL trusted links, a vulnerable ADCS certificate authority, bots that fall for LLMNR poisoning and plenty of over-privileged users, so there’s a path to practise for most of the classic AD attacks.

The GOAD lab: three domains (sevenkingdoms.local, north.sevenkingdoms.local and essos.local) with their domain controllers, member servers, trusts, MSSQL links and the users with RDP and admin rights on each

The GOAD layout. Diagram from the GOAD project; Ludus deploys it on its own range network, so the IP addresses differ.

From a blank box to a running AD range is an afternoon, most of which is unattended template builds. The bare-metal guide covers the mini-PC scenario specifically, the CLI documentation explains every ludus command, and the range configuration reference lists every knob.

The Fun Layer: Elastic + AI/MCP Tooling

Once the range is up, this is where it gets interesting in 2026.

Detection and log analysis with Elastic. Because everything in Ludus is an Ansible role, you can drop an Elastic Stack into the range (the ludus_elastic_container role above stands up Elasticsearch and Kibana; ludus_elastic_agent enrols your Windows hosts into Fleet, and from there Elastic Defend is a policy tick-box) and turn your attack lab into a detection lab. Detonate something, then go hunting for it in the logs. Elastic Security Labs have a write-up on automating exactly this, GOAD plus a live malware lab, all instrumented. That feedback loop is how you actually get good at both sides. Your Elastic server also has an API, so you can point an AI assistant at it and turn plain-English questions into queries. Elastic publish an MCP server for Elasticsearch that does exactly this.

Claude as an analysis co-pilot via MCP. The Model Context Protocol lets AI assistants drive real tools, and the reverse-engineering and DFIR community has built some brilliant servers:

Wire these into Claude Desktop, or into VS Code via an agentic harness like Claude Code, and you’ve got an LLM with hands-on access to Ghidra, WinDbg and your range, all running against VMs inside an isolated Ludus network where detonating things is safe by design. Point it at your Elastic alerts for triage, or at a sample in Ghidra for a first pass, and you’ve got a reverse-engineering and detection workbench that would have been science fiction a couple of years ago.

Start Small, Grow From There

You don’t need 96 GB and a Strix Halo box on day one. A 32 GB PC and a single SSD will happily run a small AD range to cut your teeth on. Get Ludus installed, build a couple of templates, deploy one domain, and break it. Add RAM, add a SIEM, add the AI tooling as you go.

A home cyber range used to mean a noisy tower, a pile of cables and a big electricity bill. Now it’s a box the size of a sandwich, a one-off cost that undercuts a few weeks of cloud, and an afternoon of setup. If you’re working towards offensive certs, building detections, or just want somewhere to play without consequences, this is the way.

Bonus: A 120 mm Fan Mod

A 120 mm Noctua fan held above the white 3D-printed spiral grille, which sits on top of the opened K8

After two years of 24/7 range duty, the K8’s little 40 mm lid fan was dusty and working hard (photo 9 onwards in the gallery above). A 120 mm fan moves the same air at a fraction of the speed, so the box runs cooler and quieter. The K6 and K8 share a chassis, so the community’s 3D-printed K6 lids fit; test-fit yours before committing.

K8 stock red    ──► Noctua yellow  (+5V)
K8 stock black  ──► Noctua black   (GND)
K8 stock blue   ──► Noctua blue    (PWM)
K8 stock yellow ──► Noctua green   (RPM)

In the end I only wired the first two. The NF-F12 comes with a bag of little gel-filled crimp connectors, so I cut the old fan’s lead to keep its tiny plug as a pigtail, crimped +5 V and ground onto the Noctua’s lead, and taped it all up. I left PWM and RPM disconnected. A PWM fan with no PWM signal runs at full speed, and at full speed the NF-F12 is still quiet, so there’s nothing to control: full speed ahead. Wire all four if you want the BIOS to slow it down or report its speed. If it then sits at 100% with no RPM reading, PWM and tach are swapped, so swap blue and yellow on the stock side. Either way, check for 5 V across red and black with a multimeter before plugging the fan in. The r/MiniPCs K8 fan replacement thread has the pinout discussion and other people’s builds.

The finished mod: the K8 with a white 3D-printed lid and spiral grille over a brown Noctua NF-F12 fan

The result: temperatures are a few degrees lower, the whine of the little 40 mm fan is gone, and the big Noctua is quiet. It’s good-quality kit, and the packaging is genuinely informative: the manual covers the 5 V wiring and the crimp connectors, which made the job easy. The wiring and the finished fan are the last few photos in the gallery.

Your box, your mod, your risk.


Everything here is for building a legitimate, isolated home lab. Keep malware-analysis and offensive-tooling VMs off any production or untrusted network, and only test against systems you own or are authorised to test. I bought the K8 myself; nothing in this post is sponsored.