A web server doesn’t just "serve" files; it actively participates in a complex negotiation with the client to deliver exactly what’s requested, and only what’s requested.

Let’s watch a request for a simple HTML page, /index.html, from a browser (the client) to a web server like Nginx.

Imagine your browser needs https://example.com/index.html.

  1. DNS Resolution: First, your browser asks, "What’s the IP address for example.com?" It checks its local cache, then your OS cache, then your router, and finally hits a DNS server. Let’s say it gets back 192.0.2.1.

  2. TCP Handshake: Now your browser knows where to go. It initiates a three-way TCP handshake with 192.0.2.1 on port 80 (for HTTP) or 443 (for HTTPS).

    • Browser sends SYN (synchronize).
    • Server sends SYN-ACK (synchronize-acknowledge).
    • Browser sends ACK (acknowledge). This establishes a reliable connection.
  3. HTTP Request: With the connection open, the browser sends the actual HTTP request. For /index.html, it might look like this:

    GET /index.html HTTP/1.1
    Host: example.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
    Accept-Language: en-US,en;q=0.9
    Connection: keep-alive
    
    • GET /index.html: The method and the resource path.
    • HTTP/1.1: The protocol version.
    • Host: example.com: Essential for servers hosting multiple sites.
    • User-Agent: Identifies the browser.
    • Accept: Tells the server what content types the client can handle.
    • Connection: keep-alive: Instructs the server to keep the TCP connection open for subsequent requests.
  4. Server Processing: The web server (e.g., Nginx) receives this request. It parses the request line and headers.

    • It looks at GET /index.html.
    • It checks its configuration (e.g., nginx.conf) to find a location block matching /index.html.
    • Let’s say the configuration directs it to serve files from /var/www/html/. The server now knows to look for /var/www/html/index.html.
  5. File Retrieval (or dynamic generation): The server checks if /var/www/html/index.html exists and is readable.

    • If it’s a static file, it reads it from disk.
    • If the location block points to a FastCGI, uWSGI, or proxy pass directive, the server forwards the request to another process (like PHP-FPM, a Python app, or another web server) and waits for its response.
  6. HTTP Response: Once the server has the content (or a response from an upstream process), it constructs an HTTP response.

    HTTP/1.1 200 OK
    Server: nginx/1.18.0
    Date: Mon, 20 Sep 2023 10:00:00 GMT
    Content-Type: text/html; charset=UTF-8
    Content-Length: 512
    Connection: keep-alive
    Last-Modified: Sun, 19 Sep 2023 14:30:00 GMT
    ETag: "3e8-5c7c1e0a72400"
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>Welcome</title>
    </head>
    <body>
        <h1>Hello, World!</h1>
    </body>
    </html>
    
    • HTTP/1.1 200 OK: The protocol version and status code. 200 OK means success.
    • Server: Identifies the web server software.
    • Date: When the response was generated.
    • Content-Type: Crucial for the browser to know how to render the content.
    • Content-Length: The size of the body in bytes.
    • Last-Modified/ETag: Used for caching.
  7. Browser Rendering: The browser receives this response. It sees Content-Type: text/html, parses the HTML, and starts rendering the page. If the HTML contains references to other resources (like CSS files, images, JavaScript), the browser will repeat steps 1-6 for each of them, often in parallel, leveraging the keep-alive connection.

The "magic" of a web server lies in its ability to map incoming request paths to specific file system locations or upstream application handlers, manage network connections efficiently, and construct valid HTTP responses based on its configuration and the requested resource.

One of the most powerful, yet often overlooked, aspects of HTTP is its stateless nature, which is managed by the server through mechanisms like ETag and Last-Modified headers. When a browser requests a resource that it has cached, it can send a request like If-None-Match: "3e8-5c7c1e0a72400" or If-Modified-Since: Sun, 19 Sep 2023 14:30:00 GMT. If the resource hasn’t changed on the server, the server can respond with a 304 Not Modified status code and an empty body, saving significant bandwidth and processing time. This conditional GET request is a fundamental optimization that makes the web feel fast.

After successfully serving static files, the next logical step is to explore how web servers integrate with dynamic content generation platforms.

Want structured learning?

Take the full Computer Networking course →