Multipass Local Slave Setup (Free Hands-On)
This is a free, fully local alternative to the OCI cloud setup in Section 15. Instead of paying for cloud VMs, you spin up disposable Ubuntu VMs on your own machine with Multipass (Canonical's lightweight VM manager) and use them as JMeter slaves. It's the cheapest way to practice the full distributed workflow end-to-end before you touch the cloud.
For the theory behind distributed testing, see Section 12. For the paid cloud version, see Section 15.
Why Multipass
- Free — no cloud account, no credit card, no egress charges
- Fast — a worker VM boots in ~30 seconds; tear it down just as fast
- Same subnet as the host — on Windows, Multipass VMs sit on the Hyper-V Default Switch network alongside the host, so RMI works in both directions out of the box. This sidesteps the NAT callback problem that breaks cloud slaves (see Section 12 — NAT breaks distributed testing)
- Disposable — snapshot a configured VM, clone it, or
delete --purgewhen done
The trade-off: workers share your host's CPU and RAM, so this is for validating the setup and small loads, not generating massive load. For real scale, use cloud slaves (Section 15).
Prerequisites
- Windows 10/11 (this guide assumes the Hyper-V backend, which Multipass uses by default on Windows)
- Spare host resources — budget ~2 vCPUs and ~4 GB RAM per worker on top of what your host needs
- The same JMeter version you run on your controller (this guide uses 5.6.3 to match Section 15)
Note: Multipass enables Hyper-V automatically on Windows Pro/Enterprise. On Windows Home (no Hyper-V), Multipass falls back to VirtualBox — the VM steps are identical, but the networking details in Step 3 differ.
Step 1: Install Multipass
Download the installer from multipass.run, or use winget:
winget install Canonical.Multipass
The installer enables Hyper-V and may require a reboot. Verify:
multipass version
Step 2: Launch Worker VMs
Launch one VM per slave. Give each a clear name, matching the convention from Section 15:
multipass launch 24.04 --name jmeter-slave-1 --cpus 2 --memory 4G --disk 10G
multipass launch 24.04 --name jmeter-slave-2 --cpus 2 --memory 4G --disk 10G
Check they're running and note their IPs:
multipass list
Name State IPv4 Image
jmeter-slave-1 Running 172.28.x.x Ubuntu 24.04 LTS
jmeter-slave-2 Running 172.28.y.y Ubuntu 24.04 LTS
The 172.28.x.x addresses come from the Hyper-V Default Switch. Write them down — you'll use them as the -R targets on the controller. (They can change on host reboot; see Step 3.)
Step 3: How Multipass Networking Works (Default Switch)
This is the part that makes local distributed testing just work, so it's worth understanding.
On Windows, Multipass attaches each VM to the Hyper-V Default Switch, an internal NAT network:
- Your host gets a virtual adapter on this network —
vEthernet (Default Switch), typically172.28.x.1 - Each VM gets an address on the same subnet —
172.28.x.y - The NAT only applies to VM → internet traffic. Host ↔ VM traffic is direct, because both sides are on the same internal subnet
That direct, same-subnet path is exactly what bidirectional RMI needs:
- Controller → slave (send the test plan) — host reaches the VM's
172.28.x.ydirectly - Slave → controller (send results back) — the VM reaches the host's
172.28.x.1directly
Contrast this with the cloud setup in Section 15, where the controller sat behind a home/office router with no address the cloud slaves could call back to. Here, host and VMs are effectively on one subnet — the ideal case from Section 12.
Find your host's Default Switch IP — you'll need it in Step 8:
ipconfig
Look for Ethernet adapter vEthernet (Default Switch) and note its IPv4 address (e.g. 172.28.x.1).
Dynamic IP caveat: Windows recreates the Default Switch subnet on every host reboot, so both the VM IPs and the host's Default Switch IP can change. After a reboot, re-run
multipass listandipconfigand update your-Rtarget and RMI hostname accordingly. This is the one rough edge of the default networking.
Step 4: Install Java (Inside Each VM)
Open a shell into the VM (you land as the ubuntu user with passwordless sudo):
multipass shell jmeter-slave-1
Then, inside the VM, install Java 17 (match the major version you run on the controller):
sudo apt-get update
sudo apt-get install -y openjdk-17-jdk
java -version
# Expected: openjdk version "17.0.x"
Step 5: Install JMeter (Inside Each VM)
Still inside the VM, install JMeter to /opt/jmeter — same steps as Section 15:
cd /opt
sudo wget https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.6.3.tgz
sudo tar -xzf apache-jmeter-5.6.3.tgz
sudo ln -sfn /opt/apache-jmeter-5.6.3 /opt/jmeter
sudo rm -f apache-jmeter-5.6.3.tgz
/opt/jmeter/bin/jmeter --version
# Should show: Apache JMeter 5.6.3
Important: Use the same JMeter version on every VM and the controller. Version mismatches cause silent serialization failures in distributed mode.
Step 6: Create the Start/Stop Scripts (Inside Each VM)
These are the same scripts as Section 15, with the user path adjusted to ubuntu. HOST_IP auto-detects the VM's Default Switch address, so you don't have to hardcode it.
start-slave.sh
mkdir -p /home/ubuntu/jmeter-PT/linux
cat > /home/ubuntu/jmeter-PT/linux/start-slave.sh << 'EOF'
#!/bin/bash
JMETER_HOME="/opt/jmeter"
HOST_IP=$(hostname -I | awk '{print $1}')
export JVM_ARGS="-Xms512m -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=100"
pkill -f "jmeter-server" 2>/dev/null || true
sleep 1
echo "Starting JMeter slave on ${HOST_IP}..."
nohup ${JMETER_HOME}/bin/jmeter-server \
-Djava.rmi.server.hostname=${HOST_IP} \
-Dserver.rmi.localport=50000 \
-Dserver_port=1099 \
-Dserver.rmi.ssl.disable=true \
> /home/ubuntu/jmeter-PT/linux/jmeter-slave.log 2>&1 &
echo "JMeter slave PID: $!"
EOF
chmod +x /home/ubuntu/jmeter-PT/linux/start-slave.sh
Key flags (same rationale as Section 15):
-Djava.rmi.server.hostname— announces the VM's Default Switch IP so the controller's callbacks land-Dserver.rmi.localport=50000/-Dserver_port=1099— pin the RMI ports-Dserver.rmi.ssl.disable=true— disable RMI SSL (normi_keystore.jkson internal networks)
stop-slave.sh
cat > /home/ubuntu/jmeter-PT/linux/stop-slave.sh << 'EOF'
#!/bin/bash
pkill -f "jmeter-server" 2>/dev/null && echo "Stopped." || echo "No slave process found."
EOF
chmod +x /home/ubuntu/jmeter-PT/linux/stop-slave.sh
Firewall note: Multipass Ubuntu images ship with
ufwinactive, so there's nothing to open inside the VM. If you enabledufwyourself, runsudo ufw allow 1099/tcp && sudo ufw allow 50000/tcp.
Step 7: Start the Slave
Inside each VM:
bash /home/ubuntu/jmeter-PT/linux/start-slave.sh
tail -10 /home/ubuntu/jmeter-PT/linux/jmeter-slave.log
You should see:
Created remote object: UnicastServerRef2 [liveRef: [endpoint:[172.28.x.y:50000]...]]
Type exit to leave the VM shell — the slave keeps running thanks to nohup.
Step 8: Configure the Controller (Windows Host)
The controller is your Windows host running JMeter. For the slaves to call results back, the controller must announce its Default Switch IP (from Step 3), not 127.0.0.1.
Allow Java through the Windows Firewall so the slaves' RMI callbacks reach the controller. Either approve the prompt Windows shows on first run, or pin the callback port and add a rule for it (run PowerShell as Administrator):
New-NetFirewallRule -DisplayName "JMeter RMI callback" -Direction Inbound `
-Protocol TCP -LocalPort 60000 -Action Allow
Step 9: Run the Distributed Test
From the controller (Windows host), targeting the VM IPs from multipass list:
jmeter -n -t Dummy-HTTP-Test.jmx -l results.jtl ^
-R 172.28.x.y,172.28.y.y ^
-Djava.rmi.server.hostname=172.28.x.1 ^
-Jclient.rmi.localport=60000 ^
-Jserver.rmi.ssl.disable=true
-R— comma-separated VM IPs (the slaves)-Djava.rmi.server.hostname— the host's Default Switch IP, so slaves can send results back-Jclient.rmi.localport=60000— pin the callback port to match the firewall rule-Jserver.rmi.ssl.disable=true— disable RMI SSL on the controller side too
When it finishes, confirm the JTL actually has rows (the console may still show the summary = 0 display quirk — see Section 12).
Step 10: Share Test Data with the VMs
JMeter sends the .jmx to slaves but not CSV data or JARs (see Section 12 — Files Are Not Automatically Distributed). Multipass makes this easy with a host-folder mount:
multipass mount "C:\Users\user\Documents\VTC\2026\testing-knowledge-base\jmeter-working-dir\test_data" jmeter-slave-1:/home/ubuntu/jmeter-PT/linux/test_data
Now the VM sees your test data at the same path the test plan expects. Unmount with multipass umount jmeter-slave-1.
Troubleshooting
VM IP changed after a host reboot
The Default Switch subnet is recreated on reboot. Re-run multipass list for the new VM IPs and ipconfig for the new host Default Switch IP, then restart the slave (start-slave.sh auto-detects the new VM IP) and update the -R / -Djava.rmi.server.hostname values in your run command.
Controller can't reach the slave
multipass list REM is the VM Running?
ping 172.28.x.y REM can the host reach the VM IP?
If ping works but JMeter doesn't connect, confirm the slave is listening (tail the slave log for the Created remote object line).
Test starts but JTL is empty
Almost always the result callback being blocked:
- Confirm
-Djava.rmi.server.hostnameis the host's Default Switch IP (172.28.x.1), not127.0.0.1 - Confirm the Windows Firewall allows inbound
java.exe/ port60000(Step 8)
Version mismatch errors
Serialization errors (ClassNotFoundException, InvalidClassException) mean the VM and controller run different JMeter versions. Reinstall the matching version (Step 5).
Tips
- Validate locally first — this is the same advice as Section 15, except here it costs nothing. Get a 2-thread / 30-second run returning a populated JTL before scaling up
- Pause to reclaim resources —
multipass stop jmeter-slave-1frees the RAM/CPU without deleting the VM;multipass startbrings it back - Snapshot a configured worker — once Java + JMeter + scripts are in place,
multipass snapshot jmeter-slave-1lets you roll back or clone instead of rebuilding - Automate the build — pass a
--cloud-initfile tomultipass launchto install Java, download JMeter, and drop the scripts in on first boot, turning Steps 4–6 into one command - Keep JMeter versions identical across all VMs and the controller — the single most common cause of silent distributed failures
- This is for setup validation, not scale — workers compete with your host for CPU/RAM. Once the workflow is proven here, move real load to cloud slaves (Section 15)