Serving Static Content

Web Servers Fundamentals

Chapter 5 · Serving Static Content

Chapter 1 described serving a static file as simply "read it from disk, send it back" — true as far as it goes, but there's more going on underneath. This chapter covers three details every one of the three servers has to handle for static content: telling the browser what kind of file it just received, deciding what to serve when a URL names a folder rather than a file, and what happens when there's nothing obvious to serve at all.

MIME Types: Telling the Browser What It's Looking At

Every HTTP response includes a Content-Type header — the MIME type — telling the browser how to interpret the bytes that follow (as HTML, as CSS, as a JPEG image, and so on). Each server maps file extensions to MIME types using its own lookup table: Apache and Nginx both ship a mime.types file mapping common extensions to their MIME type, extendable via Apache's AddType directive or Nginx's own types {} block; IIS maintains its own MIME type mappings through IIS Manager or the equivalent XML config. An extension with no matching entry typically falls back to a generic type like application/octet-stream, which prompts most browsers to offer the file as a download rather than trying to render it — a frequent, easy-to-miss cause of "why is my browser downloading this instead of showing it."

Directory Indexes: What Happens When a URL Names a Folder

Requesting /blog/ rather than a specific file requires the server to decide what to actually serve. All three maintain an ordered list of candidate filenames to check inside that directory: Apache's DirectoryIndex directive (commonly index.html index.php, checked in order), Nginx's index directive (the same idea, its own directive name), and IIS's Default Document feature, configured via IIS Manager, listing candidates like Default.htm or index.html in priority order. All three are solving the exact same problem — what to serve for a bare directory request — just under a different directive name each.

Directory Listings: What Happens With No Matching Index File

If none of the configured index candidates exist in a requested directory, each server has a separate, distinct setting controlling what happens next: generate an automatic listing of the directory's actual contents, or return an error. Apache's mod_autoindex can generate this listing if explicitly enabled; Nginx's own autoindex directive is off by default; IIS's Directory Browsing feature is likewise off by default. Enabling this is occasionally useful (a simple internal file share), but it's also a well-known way to accidentally expose a directory's full contents to anyone who requests it.

ApacheNginxIIS
MIME type mappingmime.types + AddTypemime.types + types {}MIME Types config (GUI/XML)
Default document directiveDirectoryIndexindexDefault Document (GUI)
Directory listing defaultOff (module not typically enabled)Off (autoindex off)Off (Directory Browsing disabled)
Unknown extension fallbackapplication/octet-streamapplication/octet-streamapplication/octet-stream
A real debugging scenario this explains
A stylesheet that loads successfully (no 404 in the browser's network tab) but visibly has no effect on the page is very often a MIME type problem, not a missing-file problem — if the server sends it back as text/plain or application/octet-stream instead of text/css, many browsers refuse to apply it as a stylesheet at all. Checking the actual Content-Type header, not just whether the file loaded, is the right first step whenever this happens.
Directory listing is a real, common misconfiguration, not a harmless convenience
All three servers default to directory listing off precisely because leaving it enabled — even unintentionally, by installing a module or checking a box without realizing what it does — can expose a directory's exact file names to anyone who requests that folder's URL, including backup files, configuration snippets, or other content nobody meant to publish. This is a genuine, well-documented misconfiguration category, not a stylistic preference — Chapter 8's own hardening coverage returns to this directly.

Hands-On Exercises

Exercise 1

A server serves a .woff2 font file with no matching MIME type entry configured, so it falls back to application/octet-stream. Explain what a browser is likely to do when it requests this file as part of loading a webpage's CSS, and why.

📄 View solution
Exercise 2

A directory contains index.php but not index.html, and the server's directory-index list is configured as "index.html index.php" in that order. Explain what actually gets served when a bare directory URL is requested, and why the order of the list matters.

📄 View solution
Exercise 3

A developer enables directory listing on a production server "temporarily, just to quickly check what files are in a folder from the browser," then forgets to disable it. Explain, using this chapter's own warning box, what could actually go wrong if this is left enabled.

📄 View solution

Chapter 5 Quick Reference

  • MIME types tell the browser how to interpret a response's body — an unmapped extension falls back to application/octet-stream, often triggering a download instead of rendering
  • Directory index candidates — Apache's DirectoryIndex, Nginx's index, IIS's Default Document — all check an ordered list of filenames for a bare directory request
  • Directory listing is off by default on all three servers, for good reason — it's a real, common way to accidentally expose a folder's contents