Aj
Developer Tools Azure

Apache JMeter on Ubuntu 24.04 on Azure User Guide

| Product: Apache JMeter on Ubuntu 24.04 LTS on Azure

Overview

Apache JMeter is the de-facto open-source tool for load and performance testing. The cloudimg image ships JMeter as a headless / server appliance: JMeter's GUI is a desktop Swing application and is not installed for interactive use here, so the product surface is non-GUI command-line test execution and the JMeter distributed-mode remote engine. The image installs Apache JMeter 5.6.3 from the official Apache binary distribution to /opt/jmeter, installs OpenJDK 17 as the runtime, runs the distributed-mode jmeter-server engine as a systemd service under a dedicated unprivileged jmeter user, ships a bundled sample test plan, and keeps test plans, results and HTML dashboard reports on a dedicated Azure data disk at /var/lib/jmeter. Backed by 24/7 cloudimg support.

What is included:

  • Apache JMeter 5.6.3 (Apache-2.0) from the official Apache binary distribution at /opt/jmeter
  • Headless (non-GUI) test execution: jmeter -n -t plan.jmx -l results.jtl
  • The distributed-mode remote engine jmeter-server running as a systemd service (jmeter-server.service) under a dedicated unprivileged jmeter user
  • OpenJDK 17 (Ubuntu 24.04 main) as the JVM runtime
  • RMI registry on 127.0.0.1:1099 and the server engine port on 127.0.0.1:1100, both loopback-only, with RMI SSL enabled against a per-VM keystore generated on first boot
  • A bundled sample test plan at /opt/jmeter/sample.jmx
  • HTML dashboard report generation from .jtl results
  • Test plans, results and reports on a dedicated 30 GiB Azure data disk at /var/lib/jmeter
  • 24/7 cloudimg support

The distributed-mode engine listens on 127.0.0.1 only and the RMI ports are never opened to the internet. Run headless tests locally on the VM, or attach a remote JMeter controller over an SSH tunnel using the per-VM keystore as the trust boundary.

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B4ms (4 vCPU / 16 GiB RAM) is a good starting point for the JVM-based engine. NSG inbound: allow 22/tcp from your management network. No inbound application ports are needed because tests run locally or the remote engine is reached over the SSH tunnel.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Apache JMeter by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) only. Then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name jmeter \
  --image <marketplace-image-urn> \
  --size Standard_B4ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm JMeter is installed and the engine is running

/opt/jmeter/bin/jmeter --version 2>/dev/null | head -8
systemctl is-active jmeter-server.service

You should see the JMeter 5.6.3 banner and active:

    _    ____   _    ____ _   _ _____       _ __  __ _____ _____ _____ ____
   / \  |  _ \ / \  / ___| | | | ____|     | |  \/  | ____|_   _| ____|  _ \
  / _ \ | |_) / _ \| |   | |_| |  _|    _  | | |\/| |  _|   | | |  _| | |_) |
 / ___ \|  __/ ___ \ |___|  _  | |___  | |_| | |  | | |___  | | | |___|  _ <
/_/   \_\_| /_/   \_\____|_| |_|_____|  \___/|_|  |_|_____| |_| |_____|_| \_\ 5.6.3

active

Apache JMeter version and jmeter-server service status

Step 5 - Confirm the distributed-mode engine binds to loopback only

The distributed-mode jmeter-server engine listens on the RMI registry port 1099 and the server engine port 1100, both bound to loopback:

ss -tln | grep -E ':1099|:1100'
LISTEN 0 50 [::ffff:127.0.0.1]:1100 *:*
LISTEN 0 50 [::ffff:127.0.0.1]:1099 *:*

Both ports are bound to 127.0.0.1 and an nftables guard drops any non-loopback traffic to them. They are never exposed to the internet.

Step 6 - Read the per-VM endpoint notes

Each VM writes its endpoint details on first boot to an information file, including the RMI endpoint, the per-VM RMI SSL keystore path, and the per-VM keystore password used to attach a remote controller:

cat /var/lib/cloudimg/apache-jmeter-endpoints.notes

The file records JMETER_HOME, the loopback RMI endpoint, the keystore path, the per-VM JMETER_RMI_KEYSTORE_PASSWORD, the public IP, and the SSH-tunnel guidance.

Apache JMeter per-VM endpoint notes

Step 7 - Review the bundled sample test plan

A sample test plan ships at /opt/jmeter/sample.jmx (a 5-thread x 20-loop thread group with a Summary Report listener). Confirm it is present:

ls -l /opt/jmeter/sample.jmx

Step 8 - Run a headless (non-GUI) test

Run the bundled sample plan headless with jmeter -n and write the results to a .jtl file. The run prints a live summary and an end-of-run line:

sudo -u jmeter /opt/jmeter/bin/jmeter -n -t /opt/jmeter/sample.jmx -l /var/lib/jmeter/results/run.jtl 2>/dev/null | grep -vE 'WARN Status' | tail -8

You should see the run reach ... end of run with the read and write counts and zero errors:

Starting standalone test @ 2026 Jun 24 21:49:29 UTC (1782337769902)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary +      1 in 00:00:00 =    6.2/s Avg:   122 Min:   122 Max:   122 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +     99 in 00:00:03 =   29.2/s Avg:   141 Min:    11 Max:   261 Err:     0 (0.00%) Active: 0 Started: 5 Finished: 5
summary =    100 in 00:00:04 =   28.2/s Avg:   141 Min:    11 Max:   261 Err:     0 (0.00%)
Tidying up ...    @ 2026 Jun 24 21:49:33 UTC (1782337773532)
... end of run

Apache JMeter headless test run with summary output

Step 9 - Generate an HTML dashboard report

Generate a JMeter HTML dashboard report from the .jtl results with jmeter -g, then list the report directory:

sudo -u jmeter /opt/jmeter/bin/jmeter -g /var/lib/jmeter/results/run.jtl -o /var/lib/jmeter/reports/run 2>/dev/null | grep -iE 'report|dashboard' | head -2
ls -1 /var/lib/jmeter/reports/run

The report directory contains index.html, the content graphs, and statistics.json:

content
index.html
sbadmin2-1.0.7
statistics.json

Open index.html in a browser (copy the report directory off the VM, or serve it over an SSH tunnel) to see the response-time, throughput and over-time dashboards.

Apache JMeter generated HTML dashboard report directory

Step 10 - Run your own test plan

Copy your own .jmx plan to the data disk and run it headless, writing results and generating a report:

# Copy your plan to the VM (from your workstation):
scp my-plan.jmx azureuser@<vm-public-ip>:/var/lib/jmeter/test-plans/

# On the VM:
sudo -u jmeter /opt/jmeter/bin/jmeter -n -t /var/lib/jmeter/test-plans/my-plan.jmx -l /var/lib/jmeter/results/my-run.jtl
sudo -u jmeter /opt/jmeter/bin/jmeter -g /var/lib/jmeter/results/my-run.jtl -o /var/lib/jmeter/reports/my-run

Step 11 - Drive this VM as a remote engine (distributed mode)

The jmeter-server engine is the remote half of JMeter's distributed (master/worker) mode. The RMI endpoint listens on 127.0.0.1:1099 only and is secured with RMI SSL against the per-VM keystore at /var/lib/jmeter/rmi_keystore.jks. To drive this VM from a controller, open an SSH tunnel, copy the keystore to the controller, point the controller's jmeter.properties at it, and target the tunnelled endpoint:

# On your workstation:
ssh -L 1099:127.0.0.1:1099 azureuser@<vm-public-ip>
scp azureuser@<vm-public-ip>:/var/lib/jmeter/rmi_keystore.jks ./rmi_keystore.jks

# Then on the controller (with the keystore + per-VM password configured):
jmeter -n -t my-plan.jmx -R 127.0.0.1:1099 -l results.jtl

Never expose 1099 or 1100 to the internet; the per-VM keystore and loopback binding are the security boundary.

Maintenance

  • Data: test plans, .jtl results and HTML reports live on the dedicated data disk at /var/lib/jmeter, so they survive reboots and the volume is independently resizable.
  • Engine: the distributed-mode remote engine runs as jmeter-server.service; restart it with sudo systemctl restart jmeter-server.service.
  • Tuning: edit /opt/jmeter/bin/user.properties for engine and RMI tuning, then restart the service.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.
  • Security boundary: the RMI registry and server engine ports bind to loopback only with RMI SSL against a per-VM keystore - keep 1099/1100 off the public internet and reach the remote engine over the SSH tunnel.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.

Apache JMeter and the Apache feather logo are trademarks of The Apache Software Foundation. This image is provided by cloudimg and is not affiliated with or endorsed by The Apache Software Foundation.