TCP, TLS, and HTTP tuning isn’t about making things "faster" in a vague sense; it’s about preventing your network stack from actively fighting against your application’s desires for data.

Imagine this: your web server is churning out data, and your client is desperately trying to slurp it up. TCP is the underlying protocol managing this flow, and it’s got a built-in throttle. TLS adds an encryption layer that further complicates things, and HTTP is the language they’re speaking. If these aren’t tuned, TCP’s throttle might be too tight, TLS might be adding too much latency, and HTTP might be inefficiently structured, all leading to a bogged-down experience that feels like a slow connection, even when the raw bandwidth is there.

Let’s see this in action. We’ll simulate a high-latency, high-packet-loss environment and then tune it.

First, a baseline. We’ll use iperf3 to measure throughput.

Server (server.example.com):

iperf3 -s

Client (client.example.com):

iperf3 -c server.example.com

On a good connection, you might see 900+ Mbps. On a problematic one, you might see 10-50 Mbps. The difference is often TCP’s congestion control and buffer management.

TCP Tuning: The Foundation

TCP’s primary mechanism for dealing with network congestion is its congestion control algorithm and its send/receive buffer sizes.

1. Congestion Control Algorithm:

  • Problem: Older algorithms like Cubic (the default on many Linux systems) can be slow to ramp up bandwidth on high-latency networks.
  • Diagnosis:
    sysctl net.ipv4.tcp_congestion_control
    
    (Likely output: net.ipv4.tcp_congestion_control = cubic)
  • Fix: Switch to BBR (Bottleneck Bandwidth and Round-trip propagation time). BBR aims to directly measure the network’s available bandwidth and round-trip time, leading to more efficient use of available capacity, especially on lossy or high-latency links.
    # On the server AND client
    sysctl -w net.ipv4.tcp_congestion_control=bbr
    echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
    sysctl -p
    
  • Why it works: BBR bypasses traditional TCP’s reliance on packet loss as a signal for congestion. Instead, it actively probes for bandwidth and measures RTT, allowing it to establish a more accurate and higher throughput pipe without causing unnecessary retransmissions.

2. TCP Send/Receive Buffers:

  • Problem: If the TCP send buffer on the server or the receive buffer on the client is too small, the sender will be forced to stop sending data even if the network has capacity, simply because the receiver (or the intermediate buffers) is full. This is known as the "pipe capacity" problem. The ideal buffer size is generally Bandwidth (bps) * RTT (seconds).
  • Diagnosis:
    sysctl net.ipv4.tcp_rmem
    sysctl net.ipv4.tcp_wmem
    
    (Example output: net.ipv4.tcp_rmem = 4096 87380 6291456) The output is min default max. The max value is what we’re interested in.
  • Fix: Increase the maximum buffer sizes. For a 100ms RTT and a 1 Gbps link (10^9 bps), the bandwidth-delay product is 10^9 * 0.1 = 10^8 bytes, or 100 MB.
    # On the server (for outgoing data) and client (for incoming data)
    # Set min=4K, default=87380, max=100MB (104857600)
    sysctl -w net.ipv4.tcp_rmem="4096 87380 104857600"
    sysctl -w net.ipv4.tcp_wmem="4096 87380 104857600"
    echo "net.ipv4.tcp_rmem=4096 87380 104857600" >> /etc/sysctl.conf
    echo "net.ipv4.tcp_wmem=4096 87380 104857600" >> /etc/sysctl.conf
    sysctl -p
    
  • Why it works: Larger buffers allow TCP to keep the "pipe" full of data, sending more packets concurrently without waiting for acknowledgments. This maximizes throughput on high-bandwidth, high-latency links, as TCP can send enough data to fill the round-trip time.

TLS Tuning: Encrypting Efficiently

TLS adds overhead. Modern TLS versions and cipher suites can significantly reduce this overhead.

1. TLS Version:

  • Problem: Older TLS versions (TLS 1.0, 1.1) are less efficient and less secure.
  • Diagnosis: Check your web server configuration (e.g., Nginx ssl_protocols, Apache SSLProtocol).
  • Fix: Ensure you are only enabling TLS 1.2 and TLS 1.3.
    # Nginx example
    ssl_protocols TLSv1.2 TLSv1.3;
    
  • Why it works: TLS 1.3 features a significantly faster handshake (1-RTT or 0-RTT for subsequent connections) and uses more efficient cipher suites, reducing latency and CPU usage.

2. TLS Cipher Suites:

  • Problem: Some cipher suites are computationally expensive, slowing down encryption/decryption, especially on the client side.
  • Diagnosis: Check your web server configuration for ssl_ciphers (Nginx) or SSLCipherSuite (Apache).
  • Fix: Prioritize modern, fast cipher suites. For TLS 1.3, the default is usually excellent. For TLS 1.2, prefer AES-GCM or ChaCha20-Poly1305.
    # Nginx example, prioritizing modern and fast ciphers
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305';
    ssl_prefer_server_ciphers on;
    
  • Why it works: AES-GCM and ChaCha20-Poly1305 are hardware-accelerated or very efficient algorithms. Using them reduces the CPU burden on both server and client, speeding up the encryption/decryption process and freeing up resources for actual data transfer.

3. TLS Session Resumption:

  • Problem: Repeatedly performing the full TLS handshake for every connection is computationally expensive and adds significant latency.
  • Diagnosis: Monitor your server’s TLS handshake statistics (e.g., in Nginx, check ssl_session_cache_size and ssl_session_timeout).
  • Fix: Enable and configure session caching.
    # Nginx example
    ssl_session_cache shared:SSL:10m; # 10MB cache, shared between worker processes
    ssl_session_timeout 10m;        # Sessions valid for 10 minutes
    
  • Why it works: Session resumption (using Session IDs or Session Tickets) allows clients to resume an existing TLS session with a truncated handshake, bypassing most of the computationally intensive steps and saving time and CPU cycles for frequent clients.

HTTP Tuning: Speaking Efficiently

HTTP/2 and HTTP/3 offer significant improvements over HTTP/1.1.

1. HTTP Version:

  • Problem: HTTP/1.1 is line-based, inefficient, and suffers from "head-of-line blocking" at the application layer.
  • Diagnosis: Check your web server configuration (e.g., Nginx http2 directive, Apache Protocols h2 http/1.1).
  • Fix: Enable HTTP/2 and, if possible, HTTP/3.
    # Nginx example
    listen 443 ssl http2;
    
    For HTTP/3, you’ll need to configure QUIC, typically involving UDP listeners.
  • Why it works: HTTP/2 uses multiplexing over a single TCP connection, allowing multiple requests and responses to be in flight concurrently without blocking each other. It also uses header compression. HTTP/3 builds on this by using QUIC (over UDP), which eliminates TCP’s head-of-line blocking and further improves handshake times.

2. HTTP/2 Stream Prioritization:

  • Problem: Even with multiplexing, the order in which data is delivered can impact perceived performance. Critical resources (like CSS and JavaScript for rendering) should be prioritized over less critical ones (like images further down the page).
  • Diagnosis: This is often handled automatically by modern servers and browsers, but can be influenced by client requests and server-side logic.
  • Fix: Ensure your server supports HTTP/2 stream prioritization. For advanced control, applications can set weight and exclusive flags on streams.
  • Why it works: By prioritizing critical resources, the browser can render the page faster, providing a better user experience even if the total download time is similar.

After applying these TCP, TLS, and HTTP/2 settings, re-run your iperf3 test. You should see a significant increase in throughput, potentially saturating your link. The next error you’ll hit is likely related to application-level bottlenecks or client-side processing limitations.

Want structured learning?

Take the full Performance course →