Cutting Web Latency on a VPS: TTFB, TLS 1.3, and HTTP/2 Tuning

Time to First Byte (TTFB) is the silent killer of perceived performance. A page can be perfectly optimized on the front end, yet every navigation still feels slow because the server takes 400–800 ms to start responding. On a VPS, much of that delay is not the application — it is the network and TLS stack: TLS handshake round-trips, HTTP/1.1 connection churn, missing session resumption, and disabled compression. This guide shows how to measure TTFB precisely and cut it by 200–400 ms with Nginx configuration alone.

Before tuning, know your starting point and your hardware’s limits. The latency your users experience also depends on where your VPS is located relative to them, so choose a provider with a datacenter near your audience — our VPS comparison table includes region coverage for the major hosts.

1. Measure TTFB With a Timing Breakdown

curl can decompose a request into its phases, which tells you exactly where the milliseconds go:

curl -o /dev/null -s -w \
  'DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n' \
  https://your-vps.example.com/

# Repeat 10x and look at the median:
for i in $(seq 1 10); do curl -o /dev/null -s -w '%{time_starttransfer}\n' https://your-vps.example.com/; done | sort -n | sed -n '5p'

On a well-configured server in the same region as the test client, expect: DNS < 5 ms, TCP connect < 30 ms, TLS < 50 ms, and TTFB under 150 ms for a cached page. Anything above that is tunable.

2. Enable TLS 1.3 and OCSP Stapling

TLS 1.3 reduces the handshake from two round-trips to one — a 1-RTT saving on every new connection, which is often 30–60 ms of latency on cross-continental links. Pair it with OCSP stapling so the server (not the client) fetches certificate revocation status, saving another round-trip for clients that would otherwise check it themselves:

# /etc/nginx/conf.d/tls.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;

Verify with openssl s_client -connect your-vps:443 -brief — you should see TLSv1.3 and, with stapling, no separate OCSP URL fetch.

3. Cache TLS Sessions for Reconnects

Browsers reconnect to your server constantly. A shared session cache lets a returning client skip the full handshake — for TLS 1.3 this also enables 0-RTT resumption for idempotent requests. Give Nginx a generous shared cache:

ssl_session_cache shared:SSL:10m;   # ~40k sessions
ssl_session_timeout 1d;
ssl_session_tickets on;

This is one of the cheapest wins on the list: repeat visits and asset requests stop paying the handshake tax entirely.

4. Turn On HTTP/2

HTTP/2 multiplexes many requests over a single connection, eliminating head-of-line blocking and connection churn for pages with dozens of assets. With Nginx it is one line per server block:

listen 443 ssl http2;
# (or on newer builds: listen 443 ssl;  http2 on;)

Combined with TLS session caching, HTTP/2 typically removes 2–4 connection round-trips from a page load. Confirm it is active with curl -I --http2 -s https://your-vps/ | head -1 (look for HTTP/2).

5. Tune Keepalive and TCP Options

Keepalive reuses connections instead of rebuilding them, and tcp_nodelay disables Nagle’s algorithm so small responses flush immediately. For the upstream (PHP-FPM) side, an upstream keepalive pool avoids reopening connections to the backend on every request:

# HTTP/1.1 client keepalive
keepalive_timeout 20s;
keepalive_requests 1000;
tcp_nodelay on;

# Upstream keepalive for PHP-FPM
upstream php {
    server unix:/run/php/php8.3-fpm.sock;
    keepalive 32;
}
server {
    location ~ \.php$ {
        fastcgi_pass php;
        fastcgi_keep_conn on;
        include fastcgi_params;
    }
}

tcp_nopush can be left on for static file responses — it batches headers and body into fewer packets, which pairs well with sendfile on.

6. Compress Text Assets

Compression does not change TTFB for the HTML itself much, but it dramatically shortens the transfer phase for CSS, JS, and JSON — which users perceive as part of “first byte” on slow links. Enable gzip (or brotli via the ngx_brotli module) with sensible minimum lengths:

gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types text/css application/javascript application/json image/svg+xml;

7. What the Numbers Should Look Like

On a 2 vCPU VPS with a PHP app and a same-region test client, the stack above typically moves TTFB from 350–500 ms to 80–150 ms. The handshake savings (TLS 1.3 + session cache + HTTP/2) account for most of the improvement on repeat visits; compression and keepalive handle the rest. If TTFB stays above 300 ms after this tuning, profile the application itself — the bottleneck is then PHP, the database, or an external API call, not the transport layer.

Conclusion

Reducing web latency on a VPS is mostly a configuration exercise: TLS 1.3 with OCSP stapling, a shared session cache, HTTP/2, keepalive, and compression. Measure with curl -w before and after each change so you know what actually moved the needle. If your stack still feels slow after tuning, the next lever is application-level caching or a managed platform that bakes this in — Cloudways, for example, ships with HTTP/2 and caching enabled out of the box. And when you shop for the VPS itself, remember that datacenter location is the one latency factor no config can fix — see the full specs and regions on the main site before you buy.

Leave a Reply