Skip to content
Virtual Hosting & the Host Header
step 1/5

Reading — step 1 of 5

Read

~1 min readCaching, Compression & Beyond

Virtual Hosting

One IP address routinely serves dozens of different sites. Shared web hosting, localhost development, and CDN edges all do this. The mechanism is the Host header — required since HTTP/1.1.

How it works

GET / HTTP/1.1
Host: blog.example.com
  -> serve files for the 'blog' site

GET / HTTP/1.1
Host: shop.example.com
  -> serve files for the 'shop' site

Same TCP socket, same IP, same nginx process — different document roots, different config blocks, different access logs. nginx calls these server blocks; Apache calls them VirtualHost; Caddy calls them site blocks.

Selection algorithm

  1. Look up the Host header value (case-insensitive, strip optional :port).
  2. If exact match exists, dispatch.
  3. Otherwise try wildcards in order of specificity: *.example.com matches blog.example.com and shop.example.com but not example.com itself.
  4. Else fall back to a configured default. Many production servers return 421 Misdirected Request (TLS) or 404 Not Found (HTTP) if no match.

Edge cases

  • Missing Host in HTTP/1.1 -> 400 Bad Request (the header is mandatory)
  • Multiple Host headers -> 400 (potential request smuggling)
  • IPv6 hosts use brackets: Host: [::1]:8080
  • The path is shared across vhosts — /admin on blog.example.com and shop.example.com are different resources.

This is why HTTPS needed SNI — TLS needs to know which cert to use before the Host header is even readable, so the hostname is sent in the ClientHello.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…