ALPN (Application-Layer Protocol Negotiation)
A TLS extension (RFC 7301): the client lists the application protocols it supports in the ClientHello and the server returns exactly one, so the protocol is settled inside the TLS handshake with no extra round trip. Common identifiers are h2, http/1.1, h3 over QUIC and acme-tls/1.
Also known as Application-Layer Protocol Negotiation, application_layer_protocol_negotiation.
Full Explanation
ALPN stands for Application-Layer Protocol Negotiation. It is a TLS extension, defined in RFC 7301. It lets a client and a server agree on which application protocol will run over the connection. For example, they might agree on h2 (HTTP/2) or http/1.1 (HTTP/1.1). This agreement happens inside the TLS handshake that was going to happen anyway. The client lists what it supports in the ClientHello. The server picks exactly one. The choice costs no extra round trip.
ALPN is not a protocol, not a tunnel, and not an in-band upgrade mechanism. It carries one opaque, IANA-registered identifier list one way, and one identifier back, and nothing else. It does not encrypt, and it does not alter how the chosen protocol then behaves. It has no cleartext equivalent, because it exists only inside a TLS handshake. ALPN replaced NPN, the earlier extension used to select SPDY on port 443. In NPN, the client made the final choice (draft-agl-tls-nextprotoneg sections 1 and 4). With ALPN, the server chooses. This is what allows a server to select a certificate or reroute a connection based on the negotiated protocol (RFC 7301 section 4). For a CDN, that is the whole story in one line. Which HTTP version a visitor gets at the edge, whether the edge can reach the origin the same way, and even how some certificates are validated: all of this follows from this one extension. It is decided once per connection, at no cost.
How it works
The client includes extension type 16, application_layer_protocol_negotiation, in its ClientHello. Its payload is a ProtocolNameList. This list has the protocols the client supports, in descending order of preference. Each protocol is named by an IANA-registered, opaque, non-empty byte string (RFC 7301 section 3.1). http/1.1 was one of the registry's original entries (RFC 7301 section 6). The extension sits beside SNI in the same ClientHello. That is why an edge can choose both the certificate and the protocol from a single message.
The server is expected to keep its own preference-ordered list. It SHOULD select the protocol it most prefers that the client also advertised. The ServerHello copy of the extension MUST contain exactly one ProtocolName (RFC 7301 sections 3.1 and 3.2). In TLS 1.2 that answer travels in the ServerHello. In TLS 1.3 it moves into the EncryptedExtensions message. That means the server's selection is encrypted, while the client's offered list is not (RFC 8446 section 4.2 and section 4.3.1).
If the server supports none of the advertised protocols, it SHALL abort with a fatal no_application_protocol alert, value 120 (RFC 7301 section 3.2). Otherwise the selected name is definitive for the connection until renegotiated. The server SHALL NOT then use a different protocol for application data (RFC 7301 section 3.2). Renegotiation is not possible once TLS 1.3 has been negotiated (RFC 8446 section 4.1.3). So on a modern connection, the first answer is the only answer.
ALPN establishes properties of the connection, not of the session. When resumption or session tickets are used, the previous contents of the extension are irrelevant. Only the values in the new handshake are considered (RFC 7301 section 3.1). TLS 1.3 adds one constraint on top of that freedom. To accept 0-RTT early data, the server MUST verify that the selected ALPN protocol is the same as the one associated with the pre-shared key, alongside the TLS version and cipher suite (RFC 8446 section 4.2.10). A resumed connection may switch protocol. It just cannot carry early data across the switch.
For HTTP, the identifiers are fixed by the HTTP specifications. h2 identifies HTTP/2 over TLS. Implementations of HTTP/2 MUST use TLS 1.2 or higher (RFC 9113 section 3.1 and section 9.2). HTTP/2 connections over TLS MUST use ALPN (RFC 9113 section 3.3). The h2c identifier MUST NOT be sent by a client or selected by a server, because it describes a protocol that does not use TLS (RFC 9113 section 3.2). What was deprecated is the h2c token in the HTTP Upgrade header. That usage was never widely deployed. Cleartext HTTP/2 itself survives, but only through prior knowledge, where no negotiation of any kind takes place (RFC 9113 sections 3.1 and 3.3).
HTTP/3 uses the same mechanism one layer down. HTTP/3 support is indicated by selecting the ALPN token h3 in the TLS handshake carried inside QUIC (RFC 9114 section 3.1 and section 3.2). QUIC makes the extension mandatory. Unless another mechanism is used to agree on an application protocol, endpoints MUST use ALPN. A failed negotiation closes the connection with a no_application_protocol TLS alert, QUIC error code 0x0178. RFC 7301 only requires servers to send that alert. QUIC requires clients to send it too (RFC 9001 section 8.1). The Alt-Svc response header does not negotiate anything. It only advertises that an equivalent HTTP/3 endpoint exists, using the h3 token (RFC 9114 section 3.1.1).
ALPN identifiers can also be published ahead of the connection in DNS. The alpn SvcParamKey of an SVCB or HTTPS resource record lists the ALPN identifiers a service endpoint offers, and therefore the protocol suites it offers. Clients intersect that list with what they support. The surviving identifiers also determine the transport: QUIC over UDP, or TLS over TCP (RFC 9460 section 7.1). For HTTPS records, the default set is the single value http/1.1 (RFC 9460 section 9). The in-handshake negotiation still happens. The DNS record just saves the client from guessing which transport to try first.
Why it matters for a CDN
ALPN is the reason a browser reaches a CDN edge on HTTP/2 on its very first connection, instead of its second. The negotiation is folded into a handshake that had to occur anyway. That is why it is desirable: it adds no network round-trips (RFC 7301 section 1). HTTP/2's field compression and concurrent exchanges on one connection (RFC 9113) become available immediately. A client that never offers h2 simply gets http/1.1 from the same handshake.
Because the server holds the choice, an edge can act on it. RFC 7301 section 4 gives certificate selection and connection rerouting, based on the negotiated protocol, as the motivation for that design. A CDN uses this on both legs of delivery: with the browser at the edge, and again when the edge opens its own TLS connection to the origin, where the origin's HTTP/2 support is discovered the same way. If the origin leg does not negotiate h2, multiplexing stops at the edge.
The extension is also load-bearing for CDN certificate automation. The ACME TLS-ALPN-01 challenge proves domain control entirely inside a TLS handshake. The connection MUST use TCP port 443. The ACME server MUST offer an ALPN extension containing the single protocol name acme-tls/1, plus an SNI extension containing only the name being validated (RFC 8737 section 2). That identifier MUST only be used for validating tls-alpn-01 challenges, and it carries no application data (RFC 8737 section 4). It avoids port 80 and DNS TXT records, but not DNS itself. The name still has to resolve to a host that answers on 443 with the right certificate.
What CDNs do
- Cloudflare negotiates HTTP/2 with clients over ALPN. It falls back to HTTP/1.1 when the server side does not support it. HTTP/2 to the origin is enabled by default. Cloudflare connects to origins that announce HTTP/2 via ALPN, and it initiates HTTP/1.1 when they do not (HTTP/2 to origin). HTTP/3 is available on all plans, but it must be switched on per zone. Cloudflare's docs state that HTTP/3 to the origin is not yet supported (HTTP/3 with QUIC).
- Akamai requires the HTTP/2 behaviour to be enabled in a property. Otherwise the edge server responds using HTTP/1.1. The same is true for the HTTP/3 behaviour. Its Service Binding feature publishes the ALPN attribute in an SVCB record, so clients can select HTTP/3 (QUIC), HTTP/2, or both before connecting.
- AWS CloudFront lets you turn HTTP/2 and HTTP/3 on or off per distribution. A viewer must support TLS 1.2 or later with SNI to get HTTP/2. On the origin leg, CloudFront forwards requests to a custom origin using HTTP/1.1 (request and response behaviour). The documented exception is gRPC. It is built on HTTP/2, requires HTTP/2 in the distribution's supported versions, and is proxied straight through to an HTTPS origin.
- Fastly services automatically support and negotiate HTTP/2 at the protocol level, if the chosen TLS configuration supports it. Fastly's documentation describes its HTTP/3 support as limited availability. It notes that HTTP/3 needs an Alt-Svc header to move a client off HTTP/1.1 or HTTP/2, because HTTP/3 uses UDP.
- Azure Front Door has HTTP/2 enabled for all configurations with no extra action. This is only for requests from clients to Front Door. Communication from Front Door to back ends uses HTTP/1.1.
Watch out for
- The client's offered list is not confidential. RFC 7301 section 5 warns that in TLS 1.2 and below, the client sends these identifiers in the clear. TLS 1.3 does not change that for the ClientHello. It only moves the server's answer into EncryptedExtensions. Hiding the list requires Encrypted ClientHello, which protects SNI and other sensitive fields such as the ALPN list (RFC 9849 section 1).
- A TLS-terminating intermediary in front of your application, such as a load balancer, WAF, or API gateway, can silently strand every client on HTTP/1.1 if it does not advertise h2. The failure is invisible in the response. Only the negotiated protocol shows it.
- If the two lists have nothing in common, the handshake does not degrade. It fails, with a fatal no_application_protocol alert (RFC 7301 section 3.2). Offering h2 alone to a client that only speaks http/1.1 is an outage, not a fallback.
- Cleartext HTTP/2 by prior knowledge involves no ALPN at all (RFC 9113 section 3.3). ALPN tooling tells you nothing about it. Do not debug an h2c-style origin with openssl s_client.
- 0-RTT early data is rejected when the newly selected ALPN protocol differs from the one bound to the resumption ticket (RFC 8446 section 4.2.10). A client that changes its offered list between connections quietly loses its 0-RTT saving.
- An application protocol may restrict which QUIC versions it runs over. A server MUST select an application protocol compatible with the QUIC version the client chose. An incompatible selection is a connection error (RFC 9001 section 8.1).
- HTTP/3 depends on UDP reaching the edge. Where UDP is blocked, the QUIC connection never establishes. Clients SHOULD attempt TCP-based versions of HTTP instead (RFC 9114 section 3.1). So h3 is never negotiated, and Alt-Svc advertisements go unused.
Best practice
- Advertise h2 and http/1.1 together on every HTTPS listener, edge and origin alike. Never advertise a single protocol on a public port: the overlap is what turns a version mismatch into a fallback instead of a fatal alert.
- Verify what was actually negotiated, rather than what is configured. openssl s_client -alpn h2,http/1.1 -connect host:443 -servername host reports the selected protocol. curl -w '%{http_version}' confirms it end to end. Check this before investigating any HTTP/2 performance problem.
- Negotiate ALPN on the origin leg too, or accept deliberately that HTTP/2 stops at the edge. Several CDNs speak HTTP/1.1 to origins by default or by design. Multiplexing that ends at the edge is a capacity decision worth making on purpose.
- Treat every TLS-terminating hop as an ALPN hop. Audit each load balancer, proxy and gateway in the path for h2 advertisement whenever a protocol regression appears.
- For HTTP/3, do all three: select h3 in the QUIC handshake, advertise the endpoint with Alt-Svc or an HTTPS record carrying the alpn parameter, and keep UDP/443 open end to end. Any one of the three missing means clients stay on TCP.
- Keep the ALPN list stable across connections if you rely on 0-RTT. Remember that the identifier is visible to the network unless ECH is deployed.
Examples
# Check ALPN negotiation with openssl
openssl s_client -alpn h2,http/1.1 -connect example.com:443 \
-servername example.com 2>/dev/null | grep -i alpn
# ALPN protocol: h2
# Check with curl (verbose shows protocol)
curl -vso /dev/null https://example.com 2>&1 | grep ALPN
# * ALPN: offers h2,http/1.1
# * ALPN: server accepted h2
# Nginx configuration for ALPN/HTTP2
server {
listen 443 ssl;
http2 on;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
# Nginx automatically advertises h2 and http/1.1 via ALPN
}
# Check negotiated protocol with curl
curl -w '%{http_version}\n' -so /dev/null https://example.com
# 2 (means HTTP/2)
Frequently Asked Questions
A TLS extension (RFC 7301): the client lists the application protocols it supports in the ClientHello and the server returns exactly one, so the protocol is settled inside the TLS handshake with no extra round trip. Common identifiers are h2, http/1.1, h3 over QUIC and acme-tls/1.
# Check ALPN negotiation with openssl
openssl s_client -alpn h2,http/1.1 -connect example.com:443 \
-servername example.com 2>/dev/null | grep -i alpn
# ALPN protocol: h2
# Check with curl (verbose shows protocol)
curl -vso /dev/null https://example.com 2>&1 | grep ALPN
# * ALPN: offers h2,http/1.1
# * ALPN: server accepted h2
# Nginx configuration for ALPN/HTTP2
server {
listen 443 ssl;
http2 on;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
# Nginx automatically advertises h2 and http/1.1 via ALPN
}
# Check negotiated protocol with curl
curl -w '%{http_version}\n' -so /dev/null https://example.com
# 2 (means HTTP/2)
Yes. ALPN (Application-Layer Protocol Negotiation) is also known as Application-Layer Protocol Negotiation, application_layer_protocol_negotiation. A TLS extension (RFC 7301): the client lists the application protocols it supports in the ClientHello and the server returns exactly one, so the protocol is settled inside the TLS handshake with no extra round trip. Common identifiers are h2, http/1.1, h3 over QUIC and acme-tls/1.
Related CDN concepts include:
- TLS (Transport Layer Security) (TLS) — TLS (Transport Layer Security) is the protocol that turns a plain byte stream into a …
- ACME (Automated Certificate Management) (ACME) — ACME (Automatic Certificate Management Environment) is the IETF protocol in RFC 8555 that automates issuing, …