HTTP & HTTPS for Operators
HTTP & HTTPS for Operators
HTTP is the protocol that moves the web. As a DevOps engineer you are not writing application logic, but you are the one debugging why a request takes 8 seconds, why a load balancer returns 502 under peak traffic, or why a redirect loop breaks a deployment. That requires an operator-level understanding of how HTTP works end-to-end: methods, status codes, headers, connection lifecycle, and protocol versions.
The Request-Response Model
Every HTTP exchange is a client sending a request and a server returning a response. In HTTP/1.1 both are plain text: a start line, headers, a blank line, and an optional body. Understanding this structure lets you read raw traffic in tcpdump or wireshark without higher-level tooling.
HTTP Methods — Contracts That Infrastructure Depends On
Every method has a defined safety (does it change state?) and idempotency (is repeating it safe?) contract. Load balancers, caches, and retry logic all rely on these contracts. Break them and you get duplicate orders, double-charged customers, or silent data corruption.
- GET — Safe and idempotent. Retrieves a resource. Always cacheable unless overridden. Never use GET to trigger a state change.
- POST — Not safe, not idempotent. Creates or submits. Retrying POST blindly can create duplicates; use client-generated idempotency keys (a UUID in a header) to make retries safe at scale.
- PUT — Not safe, but idempotent. Replaces the entire resource at a URL. Safe to retry on timeout.
- PATCH — Not safe, generally not idempotent. Partial update. Treat like POST from a retry standpoint unless the server explicitly implements idempotency.
- DELETE — Not safe, idempotent. Deleting a resource twice should return
404the second time, not an error. Infrastructure retries on timeout are safe. - HEAD — Identical to GET but returns no body. Use it to check resource existence or read headers such as
Content-Lengthwithout downloading the payload — essential for health checks and cache validation. - OPTIONS — Returns what methods the server supports. Triggered automatically by browsers before every cross-origin request (CORS preflight).
Status Codes That Matter in Production
Memorise these groups. Every monitoring alert, SLO dashboard, and postmortem references them.
- 2xx Success:
200 OK,201 Created(POST that created a resource — body should include aLocationheader pointing to the new resource),204 No Content(success with no body — common for DELETE),206 Partial Content(range requests, video streaming). - 3xx Redirect:
301 Moved Permanently(browsers cache this forever — use only when the old URL will never return),302 Found(temporary redirect, not cached),307/308(like 302/301 but preserve the HTTP method through the redirect — prefer these for API redirects so POST stays POST). - 4xx Client Error:
400 Bad Request,401 Unauthorized(missing or invalid credentials),403 Forbidden(authenticated but not permitted),404 Not Found,408 Request Timeout,429 Too Many Requests(always include aRetry-Afterheader),499(nginx-specific: client closed connection before the response was sent). - 5xx Server Error:
500 Internal Server Error,502 Bad Gateway(upstream returned an invalid response — usually app crashed or returned non-HTTP data),503 Service Unavailable(use this during rolling deployments),504 Gateway Timeout(upstream did not respond within the configured proxy timeout).
404 surge often means a bad deploy changed URL patterns; a sudden 401 surge often means a token rotation was not propagated everywhere. Separate dashboards for each class speed up postmortems significantly.
Headers — The Control Plane of HTTP
Headers carry the metadata that governs caching, authentication, routing, content negotiation, and security. These are the ones you will read and set constantly as an operator:
Host— Required in HTTP/1.1. Tells the server which virtual host to serve. Nginx uses this forserver_namematching; a wrong or missing Host hits the default server, often returning unexpected content.Content-Type— MIME type of the request or response body. Always set it explicitly on requests. Omitting it forces servers to guess the encoding, often incorrectly.Authorization— Carries credentials:Bearer <token>for JWTs and OAuth 2.0,Basic <base64(user:pass)>for basic auth (only over HTTPS).Cache-Control—no-store(never cache anywhere),no-cache(cached but must revalidate before use),max-age=3600(cache for one hour),s-maxage=86400(CDN-specific TTL, overridesmax-agefor shared caches).X-Forwarded-For— Appended by proxies with the original client IP. The value is a comma-separated list. Verify your ingress strips attacker-controlled values before appending its own, otherwise clients can spoof their IP to bypass rate limiting.Transfer-Encoding: chunked— Body sent in variable-length chunks with noContent-Length. Required for streaming responses when total size is unknown at response start time.
Keep-Alive and Connection Reuse
Opening a TCP connection costs one round trip (50-100 ms at typical WAN latencies). Adding TLS adds one or two more. Persistent connections (keep-alive) allow multiple HTTP exchanges over the same TCP connection, amortising that cost across many requests. This is the HTTP/1.1 default and is mandatory in HTTP/2.
For nginx as a reverse proxy, upstream keep-alive must be explicitly configured or every proxied request opens a fresh TCP connection to your app servers — a serious throughput bottleneck and a common source of 502 spikes during traffic bursts.
502 errors. The load balancer idles a connection for 60 seconds then reuses it; but the app server already closed it after 55 seconds. The first request on that dead connection fails. Fix: set the load balancer idle timeout higher than the app server keepalive timeout so the app server always closes first. AWS ALB defaults to 60 s — set nginx keepalive_timeout to 55 s when behind ALB.
HTTP/2 and HTTP/3 — What Changed for Operators
HTTP/2 runs over a single TLS connection and multiplexes many request-response pairs in parallel as independent streams, eliminating HTTP/1.1 head-of-line blocking at the application layer. It uses binary framing instead of plain text and compresses headers with HPACK, reducing overhead for APIs that send many small requests with repeated headers (Authorization, Accept, etc.).
Key operational implications of HTTP/2:
- TLS is effectively required (all major browsers enforce it for HTTP/2).
- Domain sharding — using cdn1.example.com and cdn2.example.com to open more TCP connections — is an HTTP/1.1 workaround that actively hurts HTTP/2 by splitting the single efficient multiplexed stream.
- Enable HTTP/2 in nginx with
listen 443 ssl http2;. Upstream connections from nginx to your app can remain HTTP/1.1 internally.
HTTP/3 replaces TCP with QUIC (UDP-based), eliminating TCP-layer head-of-line blocking. The TLS handshake is folded into the QUIC handshake, enabling 0-RTT resumption for repeat visitors. Nginx 1.25+ supports HTTP/3. Cloudflare and major CDNs already serve HTTP/3 to browsers by default. For most operators today, enabling it at the CDN layer is sufficient — let the CDN negotiate HTTP/3 with browsers while your origin speaks HTTP/1.1 or HTTP/2.
Debugging HTTP with curl — The Operator Primary Tool
curl is your first-line diagnostic for any HTTP issue. These flags let you reproduce virtually any request a browser or service makes and measure exactly where time is spent.
-w immediately tells you where a slow request spends its time. High time_namelookup means DNS is the bottleneck. High time_appconnect minus time_connect means the TLS handshake is slow (certificate chain too long, OCSP stapling missing). High time_starttransfer minus time_appconnect means the application itself is slow to generate the first byte. Each maps to a different fix.
HTTPS — What Changes for Operators
HTTPS is HTTP transported over TLS. From the HTTP perspective nothing changes — the same methods, status codes, and headers apply. What changes is that the TCP connection now carries an encrypted, authenticated channel. Operators care about three HTTPS-specific topics (covered deeply in the next lesson on TLS, but worth noting here):
- Port — HTTPS is port 443 by default. HTTP is port 80. Always redirect 80 to 443 with a
301redirect, and set an HSTS header on the HTTPS response so browsers skip the HTTP hop on subsequent visits:Strict-Transport-Security: max-age=31536000; includeSubDomains. - Mixed content — A page served over HTTPS that loads any sub-resource (image, script, CSS) over HTTP is flagged by browsers as mixed content and the sub-resource may be blocked. Your reverse proxy should set a
Content-Security-Policy: upgrade-insecure-requestsheader to force browsers to upgrade all sub-resource requests to HTTPS automatically. - Certificate errors — A
curlresponse ofSSL certificate problemmeans the certificate chain is broken, expired, or the hostname does not match. Always usecurl -vto see which certificate was presented. Use--cacert /path/to/ca.pemto trust a private CA in automated scripts instead of the dangerous-k(skip verification) flag.