Load Testing VPS with JMeter
Load testing is an essential step for checking a server to determine how it can handle heavy traffic. You can use tools like Apache JMeter to simulate many users visiting a website or app at the same time and check its performance, speed, and stability. In this guide, you will learn a step-by-step instruction for load testing VPS with JMeter.
If you want to run a load test, it is recommended to use a powerful and reliable VPS. PerLod Hosting provides VPS solutions that are best for JMeter load testing.
Table of Contents
Load Testing VPS with JMeter for Performance Optimization
With this step-by-step tutorial for load testing VPS with JMeter, you will achieve the following:
- Generate realistic HTTP load from a client machine, not the VPS.
- Collect server-side status metrics such as CPU, RAM, Disk, and Network during the test.
- Run JMeter headless and produce an HTML report.
- Parameterize tests via -J flags.
- Read results and spot bottlenecks.
Remember to test the systems you have exact permissions for. Let’s dive into the guide steps for starting load testing on a VPS.
1. Set up Load Generator (Client Machine)
The first step is to choose your load generator. You must use a machine separate from the VPS under test.
Our client machine is Ubuntu 24.04. You must install Java on your client machine:
apt update
apt install default-jdk wget tar -y
Verify Java installation by checking its version:
java --version

Then, download latest version of JMeter on your load generator (client machine). At the current time, the latest stable version of JMeter is 5.6.3. To download and install it, run the following commands:
export JMETER_VERSION=5.6.3
cd /opt
wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgz
tar -xzf apache-jmeter-${JMETER_VERSION}.tgz
ln -sfn /opt/apache-jmeter-${JMETER_VERSION} /opt/jmeter
To verify JMeter is running correctly, run the command below:
/opt/jmeter/bin/jmeter -v

2. Prepare Target VPS for Load Testing
At this point, you must set up a few tools and some configurations on the target VPS for load testing. Our target VPS is Ubuntu 24.04.
Run the system update and install the required tools with the following command:
apt update
apt install -y htop sysstat net-tools iproute2
If sysstat is disabled on your target VPS, you must enable it with the following commands:
sed -i 's/ENABLED="false"/ENABLED="true"/' /etc/default/sysstat || true
systemctl enable --now sysstat
In separate SSH sessions, you can live-watch the following metrics during the load test.
For CPU, Memory, and Process, run:
htop
For CPU run queue, memory, IO, and context switches, execute:
iostat -xz 1
To get TCP socket summary, run:
ss -s
To check how many active HTTP/HTTPS sockets are available, run: You can adjust ports if needed.
watch -n1 "ss -tan | awk '\$4 ~ /:80|:443/ && \$1 ~ /ESTAB/ {c++} END{print c+0}'"
For Web server logs, for example, Nginx, run:
tail -F /var/log/nginx/access.log
tail -F /var/log/nginx/error.log
3. Set up a Minimal and Production-Safe JMeter Test Plan
In this step, we will create a small JMX that:
- Hits one URL (GET).
- Uses a Thread Group with ramp-up and a time-boxed duration.
- Uses properties so you can override host/users/ramp/duration at runtime.
Create Test Plan File on Load Generator (Client Machine)
The first step is to create the test plan file on your client machine. Create the test directory and navigate to it with the following command:
mkdir -p ~/jmeter-tests && cd ~/jmeter-tests
Then, create the JMeter test plan file with your desired text editor:
nano vps-smoke.jmx
Add the following minimal JMX to the file:
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.0">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="VPS Load Test" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="protocol" elementType="Argument">
<stringProp name="Argument.name">protocol</stringProp>
<stringProp name="Argument.value">https</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">example.com</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="port" elementType="Argument">
<stringProp name="Argument.name">port</stringProp>
<stringProp name="Argument.value">443</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="path" elementType="Argument">
<stringProp name="Argument.name">path</stringProp>
<stringProp name="Argument.value">/</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="users" elementType="Argument">
<stringProp name="Argument.name">users</stringProp>
<stringProp name="Argument.value">50</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="rampup" elementType="Argument">
<stringProp name="Argument.name">rampup</stringProp>
<stringProp name="Argument.value">30</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="duration" elementType="Argument">
<stringProp name="Argument.name">duration</stringProp>
<stringProp name="Argument.value">180</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Load" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">true</boolProp>
<stringProp name="LoopController.loops">-1</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">${__P(users,50)}</stringProp>
<stringProp name="ThreadGroup.ramp_time">${__P(rampup,30)}</stringProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">${__P(duration,180)}</stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults" enabled="true">
<stringProp name="HTTPSampler.protocol">${__P(protocol,https)}</stringProp>
<stringProp name="HTTPSampler.domain">${__P(host,example.com)}</stringProp>
<stringProp name="HTTPSampler.port">${__P(port,443)}</stringProp>
</ConfigTestElement>
<hashTree/>
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Headers" enabled="true">
<collectionProp name="HeaderManager.headers">
<elementProp name="" elementType="Header">
<stringProp name="Header.name">User-Agent</stringProp>
<stringProp name="Header.value">JMeter</stringProp>
</elementProp>
<elementProp name="" elementType="Header">
<stringProp name="Header.name">Accept</stringProp>
<stringProp name="Header.value">*/*</stringProp>
</elementProp>
</collectionProp>
</HeaderManager>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="GET ${__P(path,/)}" enabled="true">
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.path">${__P(path,/)}</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>
Once you are done, save and close the file.
Note: The jmeter=”5.6.0″ defined inside the JMX header does not have to exactly match your installed JMeter version. JMeter will load the plan without issues.
Enable File Descriptors on Load Generator (Client Machine)
You can configure the client system to handle high concurrency and more requests per second. To do this, you can increase the number of open files or sockets and expand the port range.
ulimit -n 65535
This sets the maximum number of open files and sockets to 65,535, so the system can handle more connections. If you add this setting to the /etc/security/limits.conf file, the change will stay after a reboot. Remember to re-login:
echo '* soft nofile 65535' | sudo tee -a /etc/security/limits.conf
echo '* hard nofile 65535' | sudo tee -a /etc/security/limits.conf
Also, you can expand the temporary port range on the client machine to handle very high requests per second:
sudo sysctl -w net.ipv4.ip_local_port_range="10240 65535"
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
4. Run JMeter Load Test and Generate an HTML Report
At this point, you can run the test on your load generator (client machine). Remember to replace values to match your target VPS.
mkdir -p out
/opt/jmeter/bin/jmeter \
-n \
-t ./vps-smoke.jmx \
-l ./out/results.jtl \
-e -o ./out/report \
-Jprotocol=https \
-Jhost=YOUR.DOMAIN.OR.IP \
-Jport=443 \
-Jpath=/ \
-Jusers=100 \
-Jrampup=60 \
-Jduration=300
Flags explanation:
- -n = non-GUI.
- -t = JMX file.
- -l = results (JTL/CSV).
- -e -o = build an HTML report in out/report/.
- -J* override the variables we put in the JMX.
During the test from your target VPS, you can live-watch the metrics we discussed in step 2.
When load testing VPS with JMeter finishes, open the HTML report with the following command:
xdg-open ./out/report/index.html 2>/dev/null || open ./out/report/index.html
In the HTML report, you must focus on:
- Response Times Over Time
- Throughput
- Error %
- Active Threads Over Time
- Connect/Latency breakdown
And correlate with target VPS metrics.
Parameterized re-runs Test
You can also run JMeter tests with different parameters using the -J flag. It can quickly re-run tests without editing the JMX file. For example:
# Smaller smoke test (30 users, 2 mins)
/opt/jmeter/bin/jmeter -n -t vps-smoke.jmx -l out/smoke.jtl -e -o out/smoke \
-Jhost=YOUR.DOMAIN -Jusers=30 -Jrampup=30 -Jduration=120 -Jpath=/
# Heavier (300 users, 10 mins)
/opt/jmeter/bin/jmeter -n -t vps-smoke.jmx -l out/heavy.jtl -e -o out/heavy \
-Jhost=YOUR.DOMAIN -Jusers=300 -Jrampup=120 -Jduration=600 -Jpath=/api/health
Troubleshooting Common JMeter Load Testing Errors
- For immediate errors like wrong URL, TLS issue, or firewall/WAF blocking, you can verify with curl -v https://YOUR.DOMAIN/.
- To troubleshoot High error rates only at peak times, when the server is overloaded or the database is slow, you can adjust thread counts, pool sizes, and network limits.
- JMeter OOM/slow client: You must avoid heavy listeners in the plan and increase JMeter memory.
- Too many short connections: Use Keep-Alive on client and server.
- For handling high concurrency and more requests per second, increase the port range and reuse connections.
That’s it, you are done. Just keep in mind that performing tests from a separate client machine, JMeter heap, and client OS limits are sufficient, and target VPS monitoring shells are open during the test.
FAQs
Why is JMeter suitable for VPS load testing?
Because it supports multiple protocols like HTTP, HTTPS, FTP, JDBC, etc., which allows distributed testing, and provides detailed metrics like response time, throughput, and error rates.
What metrics should I focus on during VPS load testing?
Key metrics include: Response Time, Throughput, Error Rate, and CPU/Memory Usage.
Can JMeter test database performance on a VPS?
Yes. JMeter’s JDBC Request Sampler can simulate database queries to measure query response times and database scalability under load.
Conclusion
Load testing VPS with JMeter is essential for ensuring scalability, reliability, and performance under expected traffic conditions. It is a powerful tool for simulating user loads, identifying bottlenecks, and validating infrastructure improvements.
Ready to put these load-testing principles into practice? Check out PerLod VPS Plans to find the perfect host for your application.
We hope you enjoy this guide. Subscribe to our X and Facebook channels to get the latest articles.
For further reading:
