DEV Community

Cover image for Building a Security Test Lab with QEMU: From Zero to Network Monitoring
Mohamed Zrouga
Mohamed Zrouga

Posted on

Building a Security Test Lab with QEMU: From Zero to Network Monitoring

Why QEMU for Your Test Lab?

As software engineers and security professionals, we constantly need isolated environments to test new tools, experiment with network configurations, or validate security measures before production deployment. While solutions like VirtualBox and VMware are popular, QEMU offers something special: lightweight, scriptable, headless operation perfect for automation and CI/CD pipelines.

In this guide, I'll walk you through building a complete QEMU-based test lab focused on network security and infrastructure testing. By the end, you'll have a reproducible environment for testing firewalls, monitoring tools, and distributed systems.

What We'll Build

We're creating a multi-VM test lab that simulates a realistic network environment:

  • Gateway VM: Acts as router/firewall
  • Application VM: Simulates production workloads
  • Attacker VM: For security testing and validation

This setup mirrors real-world scenarios where you need to test network policies, intrusion detection, or packet filtering.

Prerequisites

Before we start, ensure you have:

  • A Linux host (Ubuntu/Debian in examples, but adaptable to any distro)
  • At least 8GB RAM and 20GB free disk space
  • Basic command-line familiarity
  • Sudo access for network configuration

Step 1: Installing QEMU

First, let's get QEMU installed with all necessary components:

# Ubuntu/Debian
sudo apt update
sudo apt install qemu-kvm qemu-utils libvirt-daemon-system virtinst bridge-utils

# Verify installation
qemu-system-x86_64 --version
Enter fullscreen mode Exit fullscreen mode

For other distributions:

# Fedora/RHEL
sudo dnf install qemu-kvm qemu-img libvirt virt-install

# Arch
sudo pacman -S qemu libvirt virt-manager
Enter fullscreen mode Exit fullscreen mode

Add your user to necessary groups to avoid constant sudo:

sudo usermod -aG libvirt,kvm $USER
# Log out and back in for changes to take effect
Enter fullscreen mode Exit fullscreen mode

Step 2: Creating Your First VM - The Gateway

Let's start with the gateway VM, which will be our network's control point.

Creating the Disk Image

# Create a working directory
mkdir -p ~/qemu-lab/images
cd ~/qemu-lab

# Create a 20GB disk image (qcow2 format for snapshots)
qemu-img create -f qcow2 images/gateway.qcow2 20G
Enter fullscreen mode Exit fullscreen mode

Why qcow2? It supports snapshots, copy-on-write, and compression - essential for test environments where you'll want to reset frequently.

Download a Minimal OS

For security testing, I recommend Alpine Linux (lightweight) or Debian netinst:

# Alpine Linux (very lightweight, boots in seconds)
wget https://dl-cdn.alpinelinux.org/alpine/v3.23/releases/x86_64/alpine-virt-3.23.0-x86_64.iso \
  -O images/alpine.iso

# Or Debian if you prefer more familiar tools
# wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.2.0-amd64-netinst.iso \
#   -O images/debian.iso
Enter fullscreen mode Exit fullscreen mode

First Boot and Installation

qemu-system-x86_64 \
  -name gateway \
  -m 1024 \
  -smp 2 \
  -hda images/gateway.qcow2 \
  -cdrom images/alpine.iso \
  -boot d \
  -enable-kvm \
  -nic user,model=virtio \
  -nographic
Enter fullscreen mode Exit fullscreen mode

Flag breakdown:

  • -name gateway: Identifies your VM
  • -m 1024: 1GB RAM (adjust based on your needs)
  • -smp 2: 2 CPU cores
  • -hda: Primary disk
  • -cdrom: Installation media
  • -boot d: Boot from CD-ROM first
  • -enable-kvm: Hardware acceleration (crucial for performance)
  • -nic user: Simple NAT networking for installation
  • -nographic: Console mode (no GUI needed)

Quick Alpine Installation:

# Once booted, login as root (no password)
setup-alpine

# Follow prompts:
# - Keyboard: us
# - Hostname: gateway
# - Network: eth0, dhcp
# - Password: (set a strong one)
# - Timezone: your timezone
# - Disk: sda, sys (use entire disk)
Enter fullscreen mode Exit fullscreen mode

After installation completes, power off the VM (type poweroff).

Step 3: Setting Up Advanced Networking

This is where QEMU shines for security testing. We'll create an isolated network that simulates real infrastructure.

Create a Network Configuration Script

# Create scripts directory
mkdir -p ~/qemu-lab/scripts

# Network setup script
cat > ~/qemu-lab/scripts/setup-network.sh << 'EOF'
#!/bin/bash

# Create an isolated bridge for our test lab
sudo ip link add name br-testlab type bridge
sudo ip addr add 10.0.100.1/24 dev br-testlab
sudo ip link set br-testlab up

# Enable IP forwarding (so gateway can route)
sudo sysctl -w net.ipv4.ip_forward=1

# Create TAP interfaces for VMs
for i in 0 1 2; do
  sudo ip tuntap add tap$i mode tap user $USER
  sudo ip link set tap$i master br-testlab
  sudo ip link set tap$i up
done

echo "Test lab network ready: 10.0.100.0/24 on br-testlab"
EOF

chmod +x ~/qemu-lab/scripts/setup-network.sh
Enter fullscreen mode Exit fullscreen mode

you will end up with this network topology

10.0.100.1/24 Network
       |
   [Bridge](br-testlab)
    /   |    \
  TAP0 TAP1 TAP2
  VM1  VM2   VM3
Enter fullscreen mode Exit fullscreen mode

Characteristics:

  • VMs are on SAME subnet as host
  • VMs are "visible" to external network

Network Teardown Script

cat > ~/qemu-lab/scripts/teardown-network.sh << 'EOF'
#!/bin/bash

# Remove TAP interfaces
for i in 0 1 2; do
  sudo ip link set tap$i down 2>/dev/null
  sudo ip link delete tap$i 2>/dev/null
done

# Remove bridge
sudo ip link set br-testlab down 2>/dev/null
sudo ip link delete br-testlab 2>/dev/null

echo "Test lab network removed"
EOF

chmod +x ~/qemu-lab/scripts/teardown-network.sh
Enter fullscreen mode Exit fullscreen mode

Run the setup:

~/qemu-lab/scripts/setup-network.sh
Enter fullscreen mode Exit fullscreen mode

Step 4: Creating VM Launch Scripts

Rather than typing long QEMU commands, let's create reusable launch scripts.

Gateway VM Script

cat > ~/qemu-lab/scripts/run-gateway.sh << 'EOF'
#!/bin/bash

qemu-system-x86_64 \
  -name gateway \
  -m 1024 \
  -smp 2 \
  -hda ~/qemu-lab/images/gateway.qcow2 \
  -enable-kvm \
  -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
  -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:00 \
  -netdev user,id=net1 \
  -device virtio-net-pci,netdev=net1,mac=52:54:00:12:34:01 \
  -nographic \
  -serial mon:stdio
EOF

chmod +x ~/qemu-lab/scripts/run-gateway.sh
Enter fullscreen mode Exit fullscreen mode

This gateway has TWO network interfaces:

  • net0: Connected to internal test network (10.0.100.0/24)
  • net1: NAT to internet for updates

Quick Clone Function for Additional VMs

# Create application VM from gateway template
qemu-img create -f qcow2 -b images/gateway.qcow2 -F qcow2 images/app.qcow2

# Create attacker VM
qemu-img create -f qcow2 -b images/gateway.qcow2 -F qcow2 images/attacker.qcow2
Enter fullscreen mode Exit fullscreen mode

These are backing images - they only store differences from the base, saving massive disk space.

Application VM Script

cat > ~/qemu-lab/scripts/run-app.sh << 'EOF'
#!/bin/bash

qemu-system-x86_64 \
  -name app-server \
  -m 2048 \
  -smp 2 \
  -hda ~/qemu-lab/images/app.qcow2 \
  -enable-kvm \
  -netdev tap,id=net0,ifname=tap1,script=no,downscript=no \
  -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:10 \
  -nographic \
  -serial mon:stdio
EOF

chmod +x ~/qemu-lab/scripts/run-app.sh
Enter fullscreen mode Exit fullscreen mode

Attacker VM Script

cat > ~/qemu-lab/scripts/run-attacker.sh << 'EOF'
#!/bin/bash

qemu-system-x86_64 \
  -name attacker \
  -m 1024 \
  -smp 2 \
  -hda ~/qemu-lab/images/attacker.qcow2 \
  -enable-kvm \
  -netdev tap,id=net0,ifname=tap2,script=no,downscript=no \
  -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:20 \
  -nographic \
  -serial mon:stdio
EOF

chmod +x ~/qemu-lab/scripts/run-attacker.sh
Enter fullscreen mode Exit fullscreen mode

Step 5: Network Configuration Inside VMs

Start each VM and configure networking:

Gateway VM (10.0.100.1)

# Start gateway
~/qemu-lab/scripts/run-gateway.sh

# Inside VM - configure interfaces
# For Alpine Linux:
cat > /etc/network/interfaces << 'EOF'
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 10.0.100.1
    netmask 255.255.255.0

auto eth1
iface eth1 inet dhcp
EOF

# Restart networking
rc-service networking restart

# Enable forwarding permanently
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p

# Setup basic NAT (so internal VMs can reach internet via gateway)
apk add iptables
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

# Save iptables rules
rc-update add iptables
/etc/init.d/iptables save
Enter fullscreen mode Exit fullscreen mode

Application VM (10.0.100.10)

# Configure static IP
cat > /etc/network/interfaces << 'EOF'
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 10.0.100.10
    netmask 255.255.255.0
    gateway 10.0.100.1
    dns-nameservers 8.8.8.8
EOF

rc-service networking restart
Enter fullscreen mode Exit fullscreen mode

Attacker VM (10.0.100.20)

# Configure static IP
cat > /etc/network/interfaces << 'EOF'
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 10.0.100.20
    netmask 255.255.255.0
    gateway 10.0.100.1
    dns-nameservers 8.8.8.8
EOF

rc-service networking restart

# Install security testing tools
apk add nmap tcpdump hping3 netcat-openbsd
Enter fullscreen mode Exit fullscreen mode

Step 6: Snapshots for Quick Resets

One of QEMU's killer features - instant rollback:

# Create a "clean state" snapshot for each VM
qemu-img snapshot -c clean-install images/gateway.qcow2
qemu-img snapshot -c clean-install images/app.qcow2
qemu-img snapshot -c clean-install images/attacker.qcow2

# After testing, rollback to clean state
qemu-img snapshot -a clean-install images/gateway.qcow2

# List all snapshots
qemu-img snapshot -l images/gateway.qcow2
Enter fullscreen mode Exit fullscreen mode

Step 7: Practical Use Cases

Now your lab is ready! Here are some real-world scenarios:

Testing Network Monitoring Tools

On the gateway VM, install your monitoring solution:

# Example: tcpdump for packet analysis
apk add tcpdump

# Capture traffic between app and attacker
tcpdump -i eth0 -w /tmp/capture.pcap

# Or install eBPF-based tools for advanced monitoring
# (Great for testing tools like Cilium, Falco, or custom eBPF monitors like Cerberus)
Enter fullscreen mode Exit fullscreen mode

Simulating Attack Scenarios

From attacker VM:

# Port scan the application
nmap -sV 10.0.100.10

# Test firewall rules
hping3 -S -p 80 10.0.100.10

# Monitor on gateway to see what's blocked
Enter fullscreen mode Exit fullscreen mode

Testing Firewall Rules

On gateway, add restrictive rules:

# Block all traffic from attacker to app
iptables -I FORWARD -s 10.0.100.20 -d 10.0.100.10 -j DROP

# Allow only SSH
iptables -I FORWARD -s 10.0.100.20 -d 10.0.100.10 -p tcp --dport 22 -j ACCEPT
Enter fullscreen mode Exit fullscreen mode

Container Testing

Install Docker on the app VM to test container networking and security policies in isolation.

Step 8: Automation and Management

Create a master control script:

cat > ~/qemu-lab/manage-lab.sh << 'EOF'
#!/bin/bash

case "$1" in
  start)
    ./scripts/setup-network.sh
    echo "Starting VMs in tmux sessions..."
    tmux new-session -d -s gateway './scripts/run-gateway.sh'
    tmux new-session -d -s app './scripts/run-app.sh'
    tmux new-session -d -s attacker './scripts/run-attacker.sh'
    echo "Lab started. Attach with: tmux attach -t <gateway|app|attacker>"
    ;;
  stop)
    echo "Stopping all VMs..."
    tmux kill-session -t gateway 2>/dev/null
    tmux kill-session -t app 2>/dev/null
    tmux kill-session -t attacker 2>/dev/null
    ./scripts/teardown-network.sh
    ;;
  reset)
    echo "Resetting all VMs to clean snapshot..."
    qemu-img snapshot -a clean-install images/gateway.qcow2
    qemu-img snapshot -a clean-install images/app.qcow2
    qemu-img snapshot -a clean-install images/attacker.qcow2
    echo "Reset complete"
    ;;
  *)
    echo "Usage: $0 {start|stop|reset}"
    exit 1
    ;;
esac
EOF

chmod +x ~/qemu-lab/manage-lab.sh
Enter fullscreen mode Exit fullscreen mode

Usage:

# Start entire lab
./manage-lab.sh start

# Access any VM
tmux attach -t gateway

# Reset everything to clean state
./manage-lab.sh reset

# Shut down cleanly
./manage-lab.sh stop
Enter fullscreen mode Exit fullscreen mode

Performance Tips

  1. Always use KVM acceleration (-enable-kvm) - it's 10-20x faster than emulation
  2. Allocate appropriate resources - Don't over-provision RAM
  3. Use virtio drivers - Much faster than emulated hardware
  4. qcow2 for flexibility, raw for performance - Use raw images if speed is critical
  5. CPU pinning for consistency:
   -smp 2,sockets=1,cores=2,threads=1
Enter fullscreen mode Exit fullscreen mode

Troubleshooting Common Issues

VM won't start with KVM error:

# Check if KVM is available
lsmod | grep kvm
# If not, enable in BIOS (Intel VT-x or AMD-V)
Enter fullscreen mode Exit fullscreen mode

Network not working:

# Verify TAP interfaces are up
ip link show | grep tap

# Check bridge configuration
bridge link show br-testlab
Enter fullscreen mode Exit fullscreen mode

Cannot connect to VMs:

# From host, ping the bridge IP
ping 10.0.100.1

# Check iptables isn't blocking
sudo iptables -L -n
Enter fullscreen mode Exit fullscreen mode

Performance is slow:

# Verify KVM is actually being used
ps aux | grep qemu | grep -i kvm
Enter fullscreen mode Exit fullscreen mode

Next Steps and Advanced Topics

Your test lab is now ready for serious work! Consider exploring:

  • Ansible automation - Provision VMs automatically
  • Cloud-init integration - Pre-configure VMs on first boot
  • PXE boot testing - Network installation scenarios
  • Multi-host clustering - Test Kubernetes or Docker Swarm
  • VPN testing - Simulate site-to-site connections
  • VLAN tagging - Complex network segmentation

Conclusion

QEMU provides a powerful, scriptable foundation for testing network security tools and infrastructure. Unlike heavyweight alternatives, it integrates seamlessly into CI/CD pipelines, supports headless operation, and gives you complete control over the network topology.

The lab we built mirrors production environments while remaining completely isolated and reproducible. Use it to validate security tools, test infrastructure changes, or experiment with new technologies risk-free.

All scripts and configurations from this guide are available in my GitHub https://github.com/zrougamed/blog .

What will you test first in your new lab? Drop a comment below!


About the author: I'm a Senior Software Engineer at Deltaflare, where we work on the Phoenix Platform protecting Critical National Infrastructure across energy, water, and transport sectors. I use QEMU extensively for testing security tools and validating infrastructure changes before production deployment in CNI environments. You can find me at https://zrouga.email or check out my open-source work on GitHub.

Top comments (0)