Apache Benchmarks with ab and curl

Apache Benchmarks with ab and curl

πŸ“… 2026-03-28 ✏️ 2026-07-11 ✍️ Andreas Wittmann πŸ‘οΈ ... apache web ab curl

In web server administration there is often a need to measure the performance of a website. Especially after updates to components such as Apache or PHP, there is a possibility that a well-functioning website may suddenly lose performance.

Two tools can help here: ab (ApacheBench) for load testing with multiple parallel requests, and curl for quick single-request timing. Both run on the command line and produce results immediately.

ab

ab is part of the apache2-utils package:

sudo apt install apache2-utils

It sends a configurable number of requests to a URL β€” sequentially or in parallel β€” and produces a statistical report. The number of requests is set with -n, concurrency with -c.

A basic run with 5 sequential requests:

ab -n 5 <url>

Example output:

This is ApacheBench, Version 2.3 <$Revision: 1923142 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking <Servername> (be patient).....done

Server Software:        Apache
Server Hostname:        <Servername>
Server Port:            80

Document Path:          /subdir
Document Length:        133099 bytes

Concurrency Level:      1
Time taken for tests:   7.824 seconds
Complete requests:      5
Failed requests:        0
Total transferred:      669680 bytes
HTML transferred:       665495 bytes
Requests per second:    0.64 [#/sec] (mean)
Time per request:       1564.802 [ms] (mean)
Time per request:       1564.802 [ms] (mean, across all concurrent requests)
Transfer rate:          83.59 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:  1480 1565  64.9   1600    1631
Waiting:     1391 1468  58.1   1507    1515
Total:       1480 1565  64.9   1600    1631

Percentage of the requests served within a certain time (ms)
  50%   1591
  66%   1608
  75%   1608
  80%   1631
  90%   1631
  95%   1631
  98%   1631
  99%   1631
 100%   1631 (longest request)

The most relevant lines for a quick comparison:

Field Meaning
Time taken for tests Total wall-clock time for all requests
Requests per second Throughput β€” higher is better
Time per request Average latency per request
Failed requests Any value above 0 deserves investigation
Waiting Time until first byte β€” reflects server processing time
50% / 95% / 100% Latency percentiles β€” the 95% and 100% values reveal outliers

Parallel requests

To simulate concurrent users, add -c for the concurrency level. The total number of requests -n should be a multiple of -c:

ab -n 100 -c 10 <url>

This sends 100 requests with 10 running in parallel at any time β€” a useful stress test to find out how the server behaves under load.

HTTPS and custom headers

For HTTPS URLs ab uses the https:// scheme directly. To add a custom header (e.g. for authenticated endpoints):

ab -n 50 -c 5 -H "Authorization: Bearer <token>" <url>

curl

curl is well suited for quick single-request timing, particularly when comparing the effect of a specific change. The -w flag controls what gets printed after the request completes; -o /dev/null -sS suppresses the response body while still showing errors.

The most useful single metric:

curl -o /dev/null -sS -w "%{time_total}\n" <url>

For a more detailed breakdown, use a multi-line format string:

curl -o /dev/null -sS -w "
   namelookup:  %{time_namelookup}s
      connect:  %{time_connect}s
   appconnect:  %{time_appconnect}s
  pretransfer:  %{time_pretransfer}s
 starttransfer:  %{time_starttransfer}s
              ----------
        total:  %{time_total}s
" <url>
Field Meaning
time_namelookup DNS resolution time
time_connect TCP connection established
time_appconnect TLS handshake complete (HTTPS only)
time_pretransfer Time until request was sent
time_starttransfer Time until first byte received (TTFB)
time_total Full transfer including response body

time_starttransfer (TTFB β€” Time To First Byte) is especially useful: it reflects server processing time and is not affected by the size of the response.

Averaging multiple measurements

A single curl measurement can vary due to network jitter or caching. Running several requests in a loop gives a more reliable picture:

for i in $(seq 1 10); do
    curl -o /dev/null -sS -w "%{time_total}\n" <url>
done

Conclusion

Both tools complement each other well. ab is the right choice when you need to test throughput and behaviour under load β€” after a configuration change or to find the concurrency limit of a server. curl is faster to use for a quick before/after comparison of a single endpoint.

Either way, having baseline values documented before making changes is worth the effort. Without a reference point, it is difficult to judge whether a change actually improved anything.