Modular CLI tool for QEMU/KVM educational labs.
QLab makes it easy to create, share, and run hands-on virtualization labs. Each lab is a plugin that spins up one or more QEMU virtual machines, fully provisioned via cloud-init β so students learn by doing, with zero manual setup.
flowchart TD
U(["π€ User"])
R(["ποΈ Plugin Registry"])
WS["π .qlab/ workspace"]
VM["π₯οΈ QEMU/KVM VM (cloud-init)"]
U -->|"β qlab init (once)"| WS
U -->|"β‘ qlab install"| R -->|"plugin cloned"| WS
U -->|"β’ qlab run"| WS -->|"boots"| VM
U -->|"β£ qlab shell"| VM
flowchart TD
A(["qlab install nginx-lab"]) --> B["plugin cloned into .qlab/plugins/nginx-lab/"]
B --> C(["qlab run nginx-lab"])
C --> D["qcow2 overlay disk created"]
D --> E["QEMU VM started"]
E --> F["cloud-init: installs nginx, configures service"]
F --> G{{"VM ready β β SSH port auto-assigned"}}
G --> H(["qlab shell nginx-lab"])
H --> I["interactive SSH session β do the lab β"]
I --> J(["qlab stop nginx-lab"])
J --> K(["qlab uninstall nginx-lab"])
| Feature | Details | |
|---|---|---|
| π | Plugin-based labs | Each lab is a self-contained plugin β install, run, share |
| βοΈ | Cloud-init provisioning | VMs boot fully configured, zero manual setup |
| πΎ | Overlay disks | qcow2 copy-on-write snapshots keep base images untouched |
| π | Auto SSH keys | Passwordless login, generated once per workspace |
| π₯οΈ | Serial console + SSH | Connect via qlab shell or nographic console |
| ποΈ | Plugin registry | Install labs from a local or remote registry |
| π | Pure Bash | No frameworks, no compilation β just shell scripts |
| ποΈ | TUI manager | Interactive menu-driven interface via dialog |
# Install QLab
curl -fsSL https://raw.githubusercontent.com/manzolo/qlab/main/install.sh | sudo bash
# Create and initialize a workspace
mkdir my-lab && cd my-lab
qlab init
# Install and run your first lab
qlab install hello-lab
qlab run hello-lab
# Connect to the VM
qlab shell hello-labDefault VM credentials: labuser / labpass (SSH key login is automatic).
| Command | Description |
|---|---|
qlab init |
Initialize a new workspace |
qlab install <name> |
Install a plugin (bundled, registry, or git URL) |
qlab run <name> |
Run a lab (boots VM with cloud-init) |
qlab shell <name> |
SSH into a running VM |
qlab stop <name> |
Stop a running VM |
qlab reset [name] |
Reset a single plugin, or the entire workspace |
qlab log <name> |
Tail the VM boot log |
qlab status |
Show workspace and VM status |
qlab list installed |
Show installed plugins |
qlab list available |
Show registry plugins |
qlab ports |
Show SSH port map and detect conflicts |
qlab uninstall <name> |
Remove a plugin |
qlab test <name> |
Run a plugin's automated test suite |
qlab manager |
Open interactive TUI (requires dialog) |
Install any plugin with qlab install <name> or browse them all with qlab list available.
| Plugin | Ver | VMs | Description |
|---|---|---|---|
| π Getting started | |||
| hello-lab | 1.6 | 1 | Basic VM boot lab with cloud-init |
| π Web servers | |||
| nginx-lab | 1.9 | 1 | Nginx web server installation and configuration |
| apache-lab | 1.8 | 1 | Apache web server with SSL/TLS and virtual hosts |
| ποΈ Databases | |||
| mysql-lab | 1.9 | 1 | MySQL/MariaDB database management, users, and backups |
| postgres-lab | 1.10 | 1 | PostgreSQL with pgAdmin for database management |
| π¦ Containers & DevOps | |||
| docker-lab | 1.8 | 1 | Docker containers and Docker Compose |
| git-lab | 1.6 | 1 | Git: commits, branches, merge, conflicts, stash, rebase, git flow |
| πΎ Storage | |||
| lvm-lab | 1.7 | 1 | LVM with extra virtual disks for PV, VG, and LV management |
| raid-lab | 1.8 | 2 | LVM & ZFS disk management with 4 extra disks |
| βοΈ System | |||
| systemd-lab | 1.7 | 1 | Systemd service management, unit files, timers, and journald |
| π Security & authentication | |||
| ssh-lab | 2.7 | 2 | SSH hardening with fail2ban, port knocking, and key auth |
| firewall-lab | 1.10 | 2 | Firewall with iptables, ufw, and traffic analysis |
| cyber-lab | 0.9 | 2 | Attack/defense β the attack IS the test: fail2ban ban, vulnerable web (RCE/XSS/traversal), the blind filter, the Docker/FORWARD trap, mail SPF/DKIM/DMARC, raw-TCP service |
| systems-lab | 0.9 | 1 | Linux Systems β the boot IS the test: GRUB cmdline, rescue of a broken boot, sysctl/modules, partitions by UUID, LUKS vs the attacker with the disk, persistent networking, live diagnostics, and a capstone recovered from a powered-off machine |
| container-lab | 0.5 | 1 | Container Lab β a container is a process, measured: namespaces/cgroups by hand before Docker, image immutability, reproducible non-root builds, volumes vs the writable layer, container DNS only where it should answer |
| vpn-lab | 1.8 | 2 | VPN with WireGuard and OpenVPN (server + client) |
| ldap-lab | 1.9 | 2 | LDAP with OpenLDAP, phpLDAPadmin, and client |
| pam-lab | 1.10 | 3 | PAM authentication: modules, policies, 2FA, LDAP integration |
| π Networking | |||
| dhcp-lab | 1.9 | 2 | DHCP server/client lab for dynamic IP addressing |
| dns-lab | 1.8 | 2 | DNS & BIND9 server/client for record types and zone management |
| pxe-lab | 1.1 | 2 | PXE/netboot β a diskless client with no OS installs Debian, Ubuntu or Windows over the network: DHCP options 66/67/93/175, TFTP vs HTTP, iPXE chainload, preseed / autoinstall / WinPE+DISM |
| π¬ Services | |||
| mail-lab | 1.9 | 3 | Mail server with Postfix and Dovecot (server + 2 clients) |
| filesharing-lab | 1.8 | 4 | File sharing with FTP, NFS, and Samba (3 servers + client) |
| π€ Advanced | |||
| ml-network-lab | 1.4 | 1 | Machine Learning for network monitoring with Python/scikit-learn |
Every plugin is a directory with three files:
my-plugin/
βββ plugin.conf # JSON metadata (name, version, description)
βββ install.sh # Optional: runs on install (dependency checks, setup)
βββ run.sh # Required: entry point (launches the VM)
Plugins source $QLAB_ROOT/lib/*.bash for core helpers (start_vm, create_overlay, allocate_port, etc.).
See doc/CREATE_PLUGIN_PROMPT.md for a step-by-step guide to building your own lab plugin.
Override RAM and disk size for any plugin at runtime:
# Run docker-lab with 4 GB RAM and 30 GB disk
QLAB_MEMORY=4096 QLAB_DISK_SIZE=30G qlab run docker-lab| Variable | Description | Example |
|---|---|---|
QLAB_MEMORY |
VM RAM in MB | 4096 |
QLAB_DISK_SIZE |
Overlay disk size | 30G |
Priority: environment variable β qlab.conf (DEFAULT_MEMORY) β plugin default.
QLab includes a menu-driven terminal interface β no commands to memorize:
qlab managerRequires dialog (sudo apt install dialog). From the TUI you can initialize workspaces, browse and install plugins from the registry, start/stop VMs, open SSH shells, and tail logs.
One-liner (recommended):
curl -fsSL https://raw.githubusercontent.com/manzolo/qlab/main/install.sh | sudo bashWithout root, falls back to a user-local install (~/.local/bin):
curl -fsSL https://raw.githubusercontent.com/manzolo/qlab/main/install.sh | bashFrom source:
git clone https://github.com/manzolo/qlab.git
cd qlab
sudo ./install.shManual (no install):
git clone https://github.com/manzolo/qlab.git
cd qlab
sudo apt install qemu-kvm qemu-utils genisoimage git jq curl
export PATH="$PWD/bin:$PATH"curl -fsSL https://raw.githubusercontent.com/manzolo/qlab/main/install.sh | sudo bashThe install script runs git pull --ff-only automatically if QLab is already installed.
License: MIT | Contributing | Changelog