In Apache httpd 2.4, how does the server decide which <VirtualHost> block handles an incoming request, and what happens when the request's Host header matches no ServerName or ServerAlias?
answer
- two stages, not one
- address first, then the name
- order in the file decides ties
- no match still gets served
- apachectl -S prints the map
basics
~20 sApache matches in two stages: first it narrows virtual hosts to those whose <VirtualHost> address and port fit the connection, then it compares the Host header against ServerName and ServerAlias. If no name matches, the first vhost listed for that address:port serves the request.
solid answer
~50 sSelection happens in two stages. Apache first picks the set of `<VirtualHost>` blocks whose address:port matches the connection, preferring an exact IP match over a wildcard `*:80`. Within that set it compares the request's `Host` header against each vhost's `ServerName` and `ServerAlias` values, and the **first** block that matches wins — so file and include order is part of the configuration. If nothing matches, Apache does not fail: it falls back to the first vhost defined for that address:port, which becomes the implicit default and quietly answers for every unknown hostname. That is why unrelated domains pointed at your IP end up serving whichever site happens to be listed first. In 2.4 `NameVirtualHost` is obsolete and does nothing; name-based matching is always on. `apachectl -S` prints the resolved map, including which vhost is flagged as the default and the file and line each came from.
go deeper
Know that one Apache can serve many sites, and that ServerName plus ServerAlias are what tie a domain name to a <VirtualHost> block. Be able to say where the site's files come from via DocumentRoot.
Explain both matching stages — address:port narrowing, then Host-header matching — and state plainly that the first vhost for an address:port is the fallback when nothing matches. Mention apachectl -S as the way to prove it.
Show that you treat the default vhost as a security surface: an explicit catch-all first, ServerName correctness verified after every deploy, and awareness that SNI picks the certificate before the Host header is ever read.
Own the ordering contract across a fleet: include order is configuration, so it needs a naming convention, generated config, and a check that diffs the vhost map before and after a change rather than trusting review.
## The problem virtual hosts solve One Apache process, one IP address, and many websites. Apache has to decide, per request, which site's document root, logs, TLS settings and proxy rules apply. That decision is the virtual host lookup, and it runs before almost anything else in request handling. ## Stage one: address and port Apache only listens on the addresses and ports named by `Listen`. A `<VirtualHost 10.0.0.5:8443>` block on a server that never says `Listen 8443` is dead configuration — no socket, no traffic, no error that points at the vhost. This is one of the most common "my config is right but nothing happens" causes. Given a connection, Apache collects the vhosts whose address specification matches, preferring the most specific one. A block written `<VirtualHost 10.0.0.5:80>` beats `<VirtualHost *:80>` for a connection that landed on 10.0.0.5. Only the surviving set goes to stage two. ## Stage two: the Host header Within that set, Apache compares the request's `Host` header (or the `:authority` pseudo-header on HTTP/2) against each vhost's `ServerName`, then its `ServerAlias` entries. `ServerAlias` accepts wildcards: ```apacheconf <VirtualHost *:80> ServerName www.example.com ServerAlias example.com *.example.com DocumentRoot /srv/www/example </VirtualHost> ``` Matching is first-match, in configuration order, and configuration order means the order files are pulled in by `Include`/`IncludeOptional` — usually alphabetical by filename. A vhost carrying a broad `ServerAlias *.example.com` placed early will shadow a later vhost whose `ServerName` is exactly `api.example.com`. Nothing warns you; requests simply land on the wrong site. ## The default vhost, and why it surprises people If no name matches, Apache uses the **first** vhost defined for that address:port. There is no 404-by-hostname behaviour and no "unknown host" error. Practical consequences: - Someone else's domain pointed at your IP gets served by your first vhost. - A typo'd `ServerName` silently demotes that site to unreachable-by-name, while its content shows up for every unmatched host. - Scanners hitting the bare IP see whatever the first vhost exposes. The fix is to make the default explicit rather than accidental: define a first-listed catch-all vhost that returns 404 or a static holding page, and give it a filename that sorts first (`000-default.conf` is the Debian convention for exactly this reason). ## ServerName also affects generated URLs `ServerName` is not only a matching key. When Apache builds a self-referential URL — the redirect it issues when a directory request lacks its trailing slash, for instance — `UseCanonicalName` decides whether it uses the configured `ServerName` (`On`) or the hostname the client supplied (`Off`, the common default in shipped configs). Setting `ServerName` to an internal hostname while `UseCanonicalName On` is in force produces redirects to a name clients cannot resolve. ## TLS makes ordering matter earlier For an HTTPS vhost the certificate must be chosen during the TLS handshake, before any `Host` header exists, so Apache uses the SNI name the client sent. If the client sends no SNI, or sends a name no vhost claims, the handshake is completed with the **first** HTTPS vhost's certificate — after which the request's `Host` header may point somewhere else entirely. `SSLStrictSNIVHostCheck` controls whether such a mismatch is rejected instead of served. ## Diagnosing it `apachectl -S` (equivalently `httpd -S` or `apache2ctl -S`) dumps the resolved virtual-host map: every address:port, every vhost under it with the file and line number it came from, and an explicit `default server` marker. Reading that output takes seconds and settles most "why is this domain serving the wrong site" arguments immediately. Pair it with `apachectl configtest` before any reload. ## Rules worth memorising 1. Address:port narrows; `Host`/SNI selects; first match wins. 2. No match falls back to the first vhost for that address:port — never an error. 3. `NameVirtualHost` is a no-op in 2.4; delete it rather than tuning it. 4. A vhost on a port with no `Listen` receives nothing.
- Someone points their own domain at your server's IP address. What does Apache serve them, and how do you stop it?Whatever your first vhost for that address:port is, because unmatched hostnames fall through to the implicit default. Fix it by defining an explicit catch-all vhost first — a `ServerName` nobody uses, a `Redirect 404` or a blank document root — so the default is a deliberate dead end rather than a real site. Naming it so it sorts first in the include order is what makes it stick.
- Why does `NameVirtualHost *:80` appear in so many older configs, and should you keep it?Under 2.2 it was required to turn on name-based matching for an address; without it, matching was IP-only. Apache 2.4 always does name-based matching, so the directive is obsolete and ignored — early 2.4 releases logged a warning about it. Delete it. Keeping it misleads the next reader into thinking it still switches something on.
- Two vhosts both claim `api.example.com` — one via ServerName, one via a wildcard ServerAlias listed earlier. Which wins?The one listed earlier, because matching is first-match in configuration order and a wildcard `ServerAlias` is a match like any other. Specificity does not rescue the later block. Resolve it by ordering the includes so specific hosts load before wildcard catch-alls, and confirm with `apachectl -S`, which shows the winner per name.
saying these in an interview costs you the question
- Thinking Apache returns an error when no vhost name matches
- Believing the most specific ServerName wins regardless of order
- Assuming a <VirtualHost> on a port works without a matching Listen
- Still adding NameVirtualHost to enable name-based hosting in 2.4
- Expecting the Host header to pick the TLS certificate during the handshake