Virtual Hosts In Depth: Name-Based, IP-Based & SNI
Apache In Depth
Chapter 5 · Virtual Hosts In Depth: Name-Based, IP-Based & SNI
Web Servers Fundamentals Chapter 4 showed one <VirtualHost> block matched by ServerName/ServerAlias, on a single IP, over plain HTTP. That example quietly skipped three real questions: what happens when a server has more than one IP address, how HTTPS makes this whole mechanism dramatically harder, and what actually happens when a request's Host header doesn't match anything at all.
Name-Based Virtual Hosting (What Fundamentals Already Showed)
Every distinct <VirtualHost> sharing the same IP:port is matched purely by the Host header, exactly as Chapter 4 showed. One historical footnote worth knowing if working from an older tutorial: pre-2.4 Apache required an explicit NameVirtualHost *:80 line to turn this matching on at all. Apache 2.4 removed that requirement — any IP:port combination shared by more than one <VirtualHost> automatically becomes name-based. A leftover NameVirtualHost line from an old config isn't fatal on 2.4 — Apache logs a deprecation warning at startup and ignores it — but it's dead weight worth removing.
IP-Based Virtual Hosting
IP-based hosting is a genuinely different mechanism, not just a variant of the same one: it distinguishes requests by which IP address they arrived on, not by the Host header at all — this requires the server to actually have multiple IP addresses bound to it (multiple NICs, or IP aliases on one interface). It's rare in modern deployments for the exact reason covered next: the historical problem that made IP-based hosting genuinely necessary for HTTPS has since been solved.
The Historical Problem: HTTPS Broke Name-Based Hosting
A TLS handshake — negotiating encryption and presenting a certificate — happens before any HTTP request, including the Host header, is ever sent; it has to, since the request itself needs to be encrypted using whatever the handshake just negotiated. That created a real chicken-and-egg problem for HTTPS name-based hosting: with several <VirtualHost> blocks sharing one IP, each potentially needing a different TLS certificate, Apache had no way to know which certificate to present during the handshake, since the only thing that would have told it which site was intended — the Host header — hadn't arrived yet. For years, the only real fix was IP-based hosting: one dedicated IP address per HTTPS domain, so the IP itself told Apache which certificate to present.
SNI: How Modern HTTPS Solves This
Server Name Indication (SNI) is a TLS extension that adds the target hostname into the very first message of the handshake — the ClientHello — in plain text, before encryption is even established. That's enough information for Apache to pick the correct <VirtualHost>, and therefore the correct certificate, before the rest of the handshake proceeds — solving the historical problem directly, and making genuinely name-based HTTPS hosting on a single IP the normal case today. Client support is effectively universal now (only truly ancient or specialized embedded clients lack it), which is exactly what makes Chapter 6's per-<VirtualHost> mod_ssl configuration possible in the first place.
The Default/Catch-All VirtualHost
When a request's Host header matches none of the ServerName/ServerAlias entries for the matching IP:port, Apache doesn't return an error — it silently serves whichever <VirtualHost> was defined first for that IP:port, in the order the config files were parsed (commonly alphabetical, for a typical sites-enabled/ setup). This is one of the most common real-world Apache surprises: automated scanners and bots routinely probe a server by raw IP address rather than any real domain name, and whatever site happens to load first in the config silently answers every one of those requests.
<VirtualHost> for that IP:port, with no warning that anything unusual happened. A common, deliberate fix is defining an explicit dummy <VirtualHost> block first in the load order — matching nothing meaningful, and configured to return a 403 or close the connection — specifically so an internal, staging, or simply the "wrong" site never becomes the accidental public face of unmatched traffic.
| Name-based | IP-based | |
|---|---|---|
| Distinguishes by | Host header | Which IP address the request arrived on |
| Requires | Nothing extra — one IP is enough | Multiple IP addresses on the server |
| Works with HTTPS on one IP? | Yes, via SNI | Yes, always — no SNI needed at all |
| Common today? | Yes — the normal case | Rare — mostly legacy or specialized isolation needs |
apachectl -S dumps Apache's own fully-parsed virtual host configuration — every IP:port combination, which <VirtualHost> block matches each one, and critically, which one is currently acting as the default for unmatched requests. This is the practical way to confirm the real matching order this chapter describes, rather than manually tracing through include order across multiple config files by hand.
Hands-On Exercises
Two <VirtualHost 203.0.113.5:80> blocks share the same IP:port — site-a.example is defined first in the config, site-b.example second. A request arrives with Host: unknown-domain.example. Which site serves this request, and why?
📄 View solutionExplain, in your own words, why hosting multiple HTTPS domains on a single IP address was impossible before SNI existed, and specifically what information SNI adds, and when, to solve it.
📄 View solutionA team migrating an old Apache 2.2 tutorial's config to a modern Apache 2.4 server includes a leftover "NameVirtualHost *:80" line. Explain what actually happens when Apache starts up with this line present — is it a fatal error, and is it still doing anything useful?
📄 View solutionChapter 5 Quick Reference
- Name-based — matched by
Hostheader; the normal, modern case; needs SNI to work over HTTPS with multiple certs on one IP - IP-based — matched by which IP the request arrived on; needs multiple real IPs; rare today
- SNI — the hostname is sent in the TLS
ClientHello, before encryption, letting Apache pick the right certificate before the handshake finishes - An unmatched
Hostheader is silently served by the first-defined<VirtualHost>for thatIP:port— not an error apachectl -Sshows the real, fully-parsed matching orderNameVirtualHostis deprecated/ignored (with a warning) on Apache 2.4+, not required or fatal