AWS / OCTOBER 17, 2026
Three rounds. Then network throttling.
Four separate t4g.nano instances (2 vCPUs, 512 MiB each), Ubuntu 24.04 ARM64, two CPU workers each, and one identical public SiteVue snapshot. Direct native servers, with no CDN, proxy, or load balancer. A separate c7g.xlarge (4 vCPUs, 8 GiB) generated load over private IPv4 in us-east-2a.
The planned 5-round run stopped during round 4. Tables and charts use only the first 3 complete rounds shared by all four servers (60 measurements). All 78 samples, including 9 reported request errors and the partial round, remain in the raw download. Superweb fell from roughly 5 Gbit/s to about 32 Mbit/s during the fourth-round uncompressed-JavaScript sample and recorded nine timeouts. ENA bandwidth-allowance counters increased while host CPU fell near idle, consistent with exhausted EC2 network burst capacity. This is a short-burst comparison, not a sustained-throughput claim.
wrk 4.2.0, HTTP/1.1 keep-alive without pipelining, 4 client threads and 64 connections. 3 complete rounds, 2-second warmups and 10-second measurements. Workload order rotates and server runs are interleaved; the exact sequence is preserved in the samples. Only one load test runs at a time. Tables show medians; higher requests/second is better. HTTPS is a separate workload, not mixed into HTTP results. This is throughput under load, not browser page-load time.
Superweb 2026.10 preview, nginx 1.24.0, Caddy 2.6.2, lighttpd 1.4.74. Competitor versions are Ubuntu 24.04 distribution packages, not the latest upstream releases.
The interrupted round
| Round | Server / workload | Req/s | Timeouts | p99 latency | Host CPU | Available host RAM | Transmit | Inferred constraint |
|---|---|---|---|---|---|---|---|---|
| 4 | Superweb / JavaScript, identity · HTTP | 250 | 9 | 3727 ms | 0.3% | 204.8 MiB | 0.032 Gbit/s | Network |
Download every sample and resource counter ↗ · Try the browser preview ↗
| Workload | Superweb | nginx | Caddy | lighttpd |
|---|---|---|---|---|
| Tiny text · HTTP | 188,237 | 98,483 | 18,097 | 106,373 |
| Home page, gzip · HTTP | 128,292 | 91,991 | 13,683 | 85,766 |
| JavaScript, identity · HTTP | 3,393 | 3,395 | 3,397 | 3,397 |
| JavaScript, gzip · HTTP | 10,823 | 10,843 | 9,571 | 10,880 |
| JavaScript, gzip · HTTPS | 10,781 | 10,809 | 7,394 | 10,778 |
Variation and latency
| Workload | Server | Median req/s | Min–max req/s | Median p99 latency |
|---|---|---|---|---|
| Tiny text · HTTP | Superweb | 188,237 | 170,907–194,267 | 0.47 ms |
| Tiny text · HTTP | nginx | 98,483 | 98,192–101,106 | 0.85 ms |
| Tiny text · HTTP | Caddy | 18,097 | 17,973–18,453 | 11.76 ms |
| Tiny text · HTTP | lighttpd | 106,373 | 103,986–109,135 | 0.95 ms |
| Home page, gzip · HTTP | Superweb | 128,292 | 111,835–128,294 | 0.89 ms |
| Home page, gzip · HTTP | nginx | 91,991 | 86,723–94,209 | 1.00 ms |
| Home page, gzip · HTTP | Caddy | 13,683 | 13,529–13,976 | 14.83 ms |
| Home page, gzip · HTTP | lighttpd | 85,766 | 83,559–90,657 | 1.21 ms |
| JavaScript, identity · HTTP | Superweb | 3,393 | 3,392–3,393 | 35.00 ms |
| JavaScript, identity · HTTP | nginx | 3,395 | 3,395–3,395 | 37.60 ms |
| JavaScript, identity · HTTP | Caddy | 3,397 | 3,396–3,397 | 38.88 ms |
| JavaScript, identity · HTTP | lighttpd | 3,397 | 3,397–3,398 | 35.55 ms |
| JavaScript, gzip · HTTP | Superweb | 10,823 | 10,822–10,824 | 11.90 ms |
| JavaScript, gzip · HTTP | nginx | 10,843 | 10,842–10,843 | 19.74 ms |
| JavaScript, gzip · HTTP | Caddy | 9,571 | 9,223–10,089 | 19.57 ms |
| JavaScript, gzip · HTTP | lighttpd | 10,880 | 10,879–10,882 | 12.16 ms |
| JavaScript, gzip · HTTPS | Superweb | 10,781 | 10,780–10,783 | 13.35 ms |
| JavaScript, gzip · HTTPS | nginx | 10,809 | 10,807–10,810 | 14.49 ms |
| JavaScript, gzip · HTTPS | Caddy | 7,394 | 7,347–7,566 | 24.38 ms |
| JavaScript, gzip · HTTPS | lighttpd | 10,778 | 10,240–10,823 | 8.77 ms |
CPU, available RAM, and limits by workload
These resource values come from the same three complete rounds as the throughput table. Only whole 5-second intervals inside each timed run are used, excluding warmups and partial boundary intervals. CPU and transmit are duration-weighted per run, then median across rounds; the range is across run averages. 100% CPU means both vCPUs. RAM is the minimum available host memory, not the web server's own allocation. The original sampler did not record process RSS/PSS; see the separate resource study for server RAM measurements.
| Workload | Server | Host CPU | CPU range | Min available host RAM | Transmit | Inferred constraint |
|---|---|---|---|---|---|---|
| Tiny text · HTTP | Superweb | 100.0% | 85.5–100.0% | 212.6 MiB | 0.774 Gbit/s | CPU; Not established |
| Tiny text · HTTP | nginx | 100.0% | 100.0–100.0% | 217.3 MiB | 0.309 Gbit/s | CPU |
| Tiny text · HTTP | Caddy | 98.9% | 98.6–99.0% | 215.3 MiB | 0.053 Gbit/s | CPU |
| Tiny text · HTTP | lighttpd | 100.0% | 100.0–100.0% | 216.1 MiB | 0.308 Gbit/s | CPU |
| Home page, gzip · HTTP | Superweb | 88.3% | 82.6–88.9% | 203.5 MiB | 5.004 Gbit/s | Network; Not established |
| Home page, gzip · HTTP | nginx | 100.0% | 99.9–100.0% | 217.8 MiB | 3.507 Gbit/s | CPU |
| Home page, gzip · HTTP | Caddy | 98.9% | 98.8–99.1% | 212.0 MiB | 0.532 Gbit/s | CPU |
| Home page, gzip · HTTP | lighttpd | 100.0% | 100.0–100.0% | 211.0 MiB | 3.243 Gbit/s | CPU |
| JavaScript, identity · HTTP | Superweb | 31.7% | 30.6–33.9% | 205.9 MiB | 5.005 Gbit/s | Network |
| JavaScript, identity · HTTP | nginx | 30.3% | 29.7–32.2% | 219.4 MiB | 5.004 Gbit/s | Network |
| JavaScript, identity · HTTP | Caddy | 57.6% | 57.4–57.7% | 219.4 MiB | 5.004 Gbit/s | Network |
| JavaScript, identity · HTTP | lighttpd | 28.5% | 28.1–29.1% | 218.6 MiB | 5.004 Gbit/s | Network |
| JavaScript, gzip · HTTP | Superweb | 40.9% | 40.1–42.2% | 209.0 MiB | 5.004 Gbit/s | Network |
| JavaScript, gzip · HTTP | nginx | 34.9% | 32.3–37.1% | 218.9 MiB | 5.005 Gbit/s | Network |
| JavaScript, gzip · HTTP | Caddy | 99.2% | 98.9–99.2% | 212.8 MiB | 4.456 Gbit/s | CPU; CPU + Network |
| JavaScript, gzip · HTTP | lighttpd | 31.7% | 30.9–32.6% | 218.7 MiB | 5.004 Gbit/s | Network |
| JavaScript, gzip · HTTPS | Superweb | 66.6% | 66.4–68.5% | 197.2 MiB | 5.007 Gbit/s | Network |
| JavaScript, gzip · HTTPS | nginx | 89.1% | 89.0–90.5% | 203.2 MiB | 5.005 Gbit/s | Network |
| JavaScript, gzip · HTTPS | Caddy | 99.4% | 99.4–99.5% | 215.7 MiB | 3.448 Gbit/s | CPU |
| JavaScript, gzip · HTTPS | lighttpd | 99.9% | 99.4–100.0% | 213.8 MiB | 4.969 Gbit/s | CPU; CPU + Network |
Constraint labels are inferences: CPU when run-average host CPU is at least 95%; network when transmit reaches 4.75 Gbit/s or bandwidth-allowance counters increase with CPU below 80%; both when both conditions hold. Memory pressure is flagged by new cgroup high/max/OOM events. Otherwise the constraint is not established. Multiple labels mean the inferred constraint differed between rounds. An ENA exceedance counts queued/dropped packets, not HTTP errors. Lack of a memory-pressure event does not prove RAM could never become a limit.
Separate CPU and server RAM study ↗
Method and validation
Run window (UTC): 2026-10-17T20:22:43.882527+00:00 to 2026-10-17T20:38:40.520657+00:00
The 60 measurements in the common complete rounds had zero reported connection, read, write, status, or timeout errors. Decoded response SHA-256, encoding, and HTTP 200 were checked before and after every sample. The full 290-file snapshot was independently verified on all four hosts. Peak measured wrk process CPU was 2.04 of 4 cores (50.9%); host CPU, network/ENA counters, memory, and CPU credit metrics accompany the raw data.
Superweb uses its default 32 MiB/worker cache, cached gzip, and 1-second file revalidation. nginx uses sendfile, an open-file cache, and gzip_static. Caddy uses precompressed gzip and GOMAXPROCS=2. lighttpd uses epoll and a level-6 gzip disk cache. Access logging is disabled and Cache-Control is public, max-age=0 on all four. Gzip streams can differ slightly in size while decoding to the same bytes; wire body sizes are preserved in every sample.
SiteVue source commit: 2ac4fda96182660d819e91830e33029467c80fd5. Superweb executable SHA-256: 303a0a8f7ff5f5538cd05bd28a5d931fd26c452a8fdb041b9851b379b8458cb8.
The current downloads and Superweb hosts include a later HTTP/2 read-loop fix for coalesced TLS records. This throughput run used HTTP/1.1 and the pre-fix executable identified by its SHA-256 in this report; the updated binary has not been rerun through this full AWS benchmark.
| Server | Peak host CPU | Min available RAM | Peak transmit | ENA bandwidth / PPS exceedances |
|---|---|---|---|---|
| Superweb | 100.0% | 197 MiB | 5.01 Gbit/s | 15,195,500 / 0 |
| nginx | 100.0% | 203 MiB | 5.01 Gbit/s | 9,966,767 / 0 |
| Caddy | 99.5% | 212 MiB | 5.00 Gbit/s | 3,521,991 / 0 |
| lighttpd | 100.0% | 203 MiB | 5.00 Gbit/s | 8,820,318 / 0 |
Host CPU and transmit peaks use 5-second intervals overlapping measurements; RAM is available memory, not server RSS. ENA exceedance deltas cover the telemetry window, including warmups. An exceedance means traffic met an instance allowance and can be queued or dropped; it is not an HTTP error count. Client ENA exceedance delta during measured samples: 0.
What these numbers cover
These are burst measurements on one instance of each server, not sustained-capacity guarantees or a universal ranking. T4g.nano has a 0.032 Gbit/s network baseline and up to 5 Gbit/s burst capacity. CPU credits are Unlimited; surplus charges can accrue. Network allowance counters and round-to-round variation matter, particularly for large responses. The client has a 1.876 Gbit/s network baseline and up to 12.5 Gbit/s burst capacity. Public hosts may receive incidental traffic; the browser preview was not exercised during the load test. No statistical confidence interval is claimed from three complete rounds. The network-throttled sample is part of the recorded outcome and must not be omitted when discussing sustained performance.
AWS network bandwidth documentation ↗ · CPU credit documentation ↗
Reproduce
Use deploy/aws/benchmark-client.json to create a temporary client in the same subnet. Build wrk 4.2.0, populate a config with current private IPs and the paths/hashes from benchmark-manifest.json, then run the command below. Capture host telemetry with deploy/aws/telemetry.py and retrieve AWS CPU credit metrics. Keep all samples, inspect errors and limits, and delete the temporary client stack after downloading its results.
python3 deploy/aws/benchmark.py benchmark-config.json \ --rounds 5 --seconds 10 --warmup 2 --threads 4 --connections 64 \ --output aws-results.json
Benchmark setup and public endpoints ↗ · Earlier M5 Max report ↗
Run against the public hosts
Download the standalone Linux benchmark driver and public-host configuration. With Python 3, ethtool, and wrk 4.2.0 installed, run:
python3 benchmark.py example-config.json --output my-results.json
This uses public DNS and the internet path from your client, so it will not reproduce the private-network figures above. Record your instance type and location in the config. The script validates bodies and saves every round; it uploads nothing unless you explicitly supply your own S3 bucket.