Back to HTTP Headers

Host general request

Specifies which host and port the client wants to reach — the only mandatory HTTP/1.1 request header.

What it does

Host tells the server which hostname and port the client wants to reach. It's the only header that is mandatory in HTTP/1.1 requests — a request without Host must be rejected with 400 Bad Request.

The reason it exists: a single server's IP address can host thousands of websites (virtual hosting). When a request arrives, the IP address alone doesn't tell the server which site is being requested. Host provides that disambiguation — the server inspects it and routes the request to the correct site.

Syntax

Host: <hostname>
Host: <hostname>:<port>

Port is only included if it's non-standard (i.e., not 80 for HTTP or 443 for HTTPS):

Host: example.com
Host: api.example.com
Host: example.com:8080
Host: localhost:3000

Why it's mandatory

Before HTTP/1.1 (1997), HTTP/1.0 had no Host header. Every server had its own IP address — one IP, one site. This was fine when the internet was small. As the web grew, IP address exhaustion became a real concern, and the model of "one IP per website" became impractical.

HTTP/1.1 introduced Host as a mandatory header precisely to enable name-based virtual hosting: one IP address, one web server, thousands of domains. Nginx, Apache, and every modern web server use Host to route requests to the right virtual host configuration.

Virtual hosting in practice

A server at IP 203.0.113.1 might host:

example.com
blog.example.com
api.example.com
another-site.com

All four requests arrive at the same IP. The Host header tells the server which site to serve:

GET /about HTTP/1.1
Host: blog.example.com

vs.

GET /about HTTP/1.1
Host: another-site.com

Without Host, both requests are identical at the network layer and the server can't distinguish them.

HTTP/2 and HTTP/3

In HTTP/2 and HTTP/3, Host is replaced by the :authority pseudo-header (part of the binary framing layer). However, Host is still accepted for compatibility. HTTP/2 frames carry :authority: example.com in the HEADERS frame rather than a Host: header line — it's the same concept, different wire format.

Host and security

Host header injection. Some applications use the Host header to generate URLs (password reset links, absolute redirect URLs). If the server trusts a user-supplied Host without validation, an attacker can send a forged Host: evil.com and the app generates links to evil.com in legitimate-looking emails — a host header injection attack.

Mitigation: always validate Host against an allowlist of known good values. Most frameworks do this, but custom routing logic can have gaps.

Routing in load balancers and reverse proxies. Load balancers use Host to route traffic. If a request arrives with an unexpected Host, it may be routed to the wrong backend or rejected. When debugging routing issues, always check what Host value is being forwarded.

Common mistakes and gotchas

Forgetting Host on raw HTTP/1.1 requests. When hand-crafting HTTP requests (with netcat, raw socket code, or testing tools), forgetting Host causes immediate 400 Bad Request. It's the most common mistake when building low-level HTTP clients from scratch.

Mismatched Host in development. Running a service on localhost:3000 but proxying through nginx with a different host? The proxied Host header may not match what your app expects. Use proxy_set_header Host $host; in nginx to forward the original host.

Ports in Host for HTTPS. Host: example.com:443 is technically correct but unusual — port 443 is the default for HTTPS and is normally omitted. Some servers handle this gracefully; others may not match the virtual host correctly. Stick to Host: example.com for standard HTTPS.

Real-world examples

Standard browser request:

GET /docs HTTP/1.1
Host: developer.example.com
User-Agent: Mozilla/5.0
Accept: text/html

Non-standard port (local development):

GET /api/users HTTP/1.1
Host: localhost:8080
Content-Type: application/json

400 response for missing Host:

GET /index.html HTTP/1.1

HTTP/1.1 400 Bad Request
Content-Type: text/html

400 Bad Request: Missing Host header

FAQ

Can there be multiple Host headers?

No — Host must appear exactly once. A request with multiple Host headers (or a Host with a comma-separated list) is malformed. Servers must reject it with 400 Bad Request. This is also a security concern — some proxies may handle multiple Host headers inconsistently, enabling host header smuggling attacks.

Does Host matter for HTTPS?

Yes, but TLS adds SNI (Server Name Indication) at the handshake level, which serves a similar purpose — telling the server which certificate to present before the HTTP layer begins. For HTTPS virtual hosting, both SNI (at the TLS layer) and Host (at the HTTP layer) need to be correct.

What happens if Host doesn't match any virtual host?

The server either serves a default site (usually the first configured virtual host) or returns 400/404. nginx and Apache both have a "default server" concept for requests with unrecognised Host values. This is also how you can catch misconfigured clients or scanning tools sending arbitrary Host values.

Fun fact

The Host header's mandatory status is unique in HTTP — it's the only request header the spec requires servers to reject if absent. This reflects just how fundamental virtual hosting became to the web. Before Host, roughly 1996–1997, every website needed its own IP address. The IPv4 address space would have been exhausted years earlier if virtual hosting hadn't been invented. A single mandatory HTTP header is a big part of why we didn't run out of IP addresses in the early 2000s.

Related Headers