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.
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 updateapt install default-jdk wget tar -y
Verify Java installation by checking its version:

Then, download the 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 /optwget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgztar -xzf apache-jmeter-${JMETER_VERSION}.tgzln -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 updateapt 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 || truesystemctl enable --now sysstat
In separate SSH sessions, you can live-watch the following metrics during the load test.
For CPU, Memory, and Process, run:
For CPU run queue, memory, IO, and context switches, execute:
To get TCP socket summary, run:
To check how many active HTTP/HTTPS sockets are available, run this command. 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.logtail -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 with GET.
- Uses a Thread Group with ramp-up and a time-boxed duration.
- Uses properties so you can override host, users, ramp, and 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:
Add the following minimal JMX to the file:
1<?xml version="1.0" encoding="UTF-8"?>2<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.0">3 <hashTree>4 <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="VPS Load Test" enabled="true">5 <stringProp name="TestPlan.comments"></stringProp>6 <boolProp name="TestPlan.functional_mode">false</boolProp>7 <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>8 <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">9 <collectionProp name="Arguments.arguments">10 <elementProp name="protocol" elementType="Argument">11 <stringProp name="Argument.name">protocol</stringProp>12 <stringProp name="Argument.value">https</stringProp>13 <stringProp name="Argument.metadata">=</stringProp>14 </elementProp>15 <elementProp name="host" elementType="Argument">16 <stringProp name="Argument.name">host</stringProp>17 <stringProp name="Argument.value">example.com</stringProp>18 <stringProp name="Argument.metadata">=</stringProp>19 </elementProp>20 <elementProp name="port" elementType="Argument">21 <stringProp name="Argument.name">port</stringProp>22 <stringProp name="Argument.value">443</stringProp>23 <stringProp name="Argument.metadata">=</stringProp>24 </elementProp>25 <elementProp name="path" elementType="Argument">26 <stringProp name="Argument.name">path</stringProp>27 <stringProp name="Argument.value">/</stringProp>28 <stringProp name="Argument.metadata">=</stringProp>29 </elementProp>30 <elementProp name="users" elementType="Argument">31 <stringProp name="Argument.name">users</stringProp>32 <stringProp name="Argument.value">50</stringProp>33 <stringProp name="Argument.metadata">=</stringProp>34 </elementProp>35 <elementProp name="rampup" elementType="Argument">36 <stringProp name="Argument.name">rampup</stringProp>37 <stringProp name="Argument.value">30</stringProp>38 <stringProp name="Argument.metadata">=</stringProp>39 </elementProp>40 <elementProp name="duration" elementType="Argument">41 <stringProp name="Argument.name">duration</stringProp>42 <stringProp name="Argument.value">180</stringProp>43 <stringProp name="Argument.metadata">=</stringProp>44 </elementProp>45 </collectionProp>46 </elementProp>47 <stringProp name="TestPlan.user_define_classpath"></stringProp>48 </TestPlan>49 <hashTree>50 <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Load" enabled="true">51 <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>52 <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">53 <boolProp name="LoopController.continue_forever">true</boolProp>54 <stringProp name="LoopController.loops">-1</stringProp>55 </elementProp>56 <stringProp name="ThreadGroup.num_threads">${__P(users,50)}</stringProp>57 <stringProp name="ThreadGroup.ramp_time">${__P(rampup,30)}</stringProp>58 <boolProp name="ThreadGroup.scheduler">true</boolProp>59 <stringProp name="ThreadGroup.duration">${__P(duration,180)}</stringProp>60 <stringProp name="ThreadGroup.delay"></stringProp>61 </ThreadGroup>62 <hashTree>63 <ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults" enabled="true">64 <stringProp name="HTTPSampler.protocol">${__P(protocol,https)}</stringProp>65 <stringProp name="HTTPSampler.domain">${__P(host,example.com)}</stringProp>66 <stringProp name="HTTPSampler.port">${__P(port,443)}</stringProp>67 </ConfigTestElement>68 <hashTree/>69 <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Headers" enabled="true">70 <collectionProp name="HeaderManager.headers">71 <elementProp name="" elementType="Header">72 <stringProp name="Header.name">User-Agent</stringProp>73 <stringProp name="Header.value">JMeter</stringProp>74 </elementProp>75 <elementProp name="" elementType="Header">76 <stringProp name="Header.name">Accept</stringProp>77 <stringProp name="Header.value">*/*</stringProp>78 </elementProp>79 </collectionProp>80 </HeaderManager>81 <hashTree/>82 <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="GET ${__P(path,/)}" enabled="true">83 <boolProp name="HTTPSampler.postBodyRaw">false</boolProp>84 <elementProp name="HTTPsampler.Arguments" elementType="Arguments">85 <collectionProp name="Arguments.arguments"/>86 </elementProp>87 <stringProp name="HTTPSampler.path">${__P(path,/)}</stringProp>88 <stringProp name="HTTPSampler.method">GET</stringProp>89 <boolProp name="HTTPSampler.follow_redirects">true</boolProp>90 <boolProp name="HTTPSampler.auto_redirects">false</boolProp>91 <boolProp name="HTTPSampler.use_keepalive">true</boolProp>92 <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>93 <boolProp name="HTTPSampler.monitor">false</boolProp>94 </HTTPSamplerProxy>95 <hashTree/>96 </hashTree>97 </hashTree>98 </hashTree>99</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.
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.confecho '* 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 in JTL or 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 and 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:
/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=/ /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 or 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.
- For JMeter OOM or a slow client, avoid heavy listeners in the plan and increase JMeter memory.
- For 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 tests should be performed from a separate client machine, JMeter heap and client OS limits should be sufficient, and target VPS monitoring shells should be open during the test.
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:
Horizontal and Vertical Scaling in Dedicated Server
How to Implement a Zero-Trust Microsegmentation