MASQUE

MASQUE (Multiplexed Application Substrate over QUIC Encryption) is a framework for proxying and tunneling arbitrary traffic over HTTP. It carries UDP and IP packets inside an HTTP connection using the extended CONNECT method, HTTP Datagrams, and the Capsule Protocol, so tunneled traffic shares a single HTTP/2 or HTTP/3 connection alongside ordinary web requests.

What MASQUE is

MASQUE is a set of HTTP extensions that turn an HTTP server into a proxy for non-HTTP traffic. The name stands for Multiplexed Application Substrate over QUIC Encryption. Rather than defining a new protocol on a new port, MASQUE reuses the HTTP machinery already running on port 443. A client opens a tunnel by sending an extended CONNECT request, and the proxy relays the client's UDP datagrams or IP packets to their destination.

The framework rests on three building blocks. Proxying UDP in HTTP defines a connect-udp tunnel for single UDP flows. Proxying IP in HTTP defines a connect-ip tunnel for raw IP packets. Both rely on HTTP Datagrams and the Capsule Protocol, which give HTTP a way to move datagram-style payloads through a request stream. Together these pieces let a proxy forward QUIC, DNS, full VPN traffic, or any other packet flow over the same connection that serves regular pages.

Why MASQUE exists

MASQUE exists to move proxying and VPN-style tunneling onto modern HTTP transport so tunneled traffic blends in with normal web traffic. Older tunneling approaches run on dedicated ports and protocols that network middleboxes recognize and sometimes block. MASQUE traffic looks like an HTTPS connection, because that is what it is. The tunnel rides inside HTTP/2 or HTTP/3, encrypted by TLS or QUIC, multiplexed with other streams on the same connection.

The practical driver is privacy proxying at scale. Apple iCloud Private Relay uses MASQUE to send Safari traffic through a two-hop relay, hiding the client IP from the destination while hiding the destination from the first relay. Running the tunnel over HTTP/3 means it survives network changes, benefits from QUIC connection migration, and avoids the head-of-line blocking that affects tunnels built on a single TCP stream. Multiplexing also matters: one QUIC connection can carry many independent tunnels plus ordinary requests at once.

MASQUE and OHTTP

MASQUE and Oblivious HTTP both serve privacy goals but operate at different levels. MASQUE creates a persistent connection-level tunnel for all traffic, similar to a VPN. OHTTP encrypts and routes individual request-response pairs. A single server can act as a MASQUE proxy and an OHTTP relay at the same time.

The extended CONNECT method

MASQUE tunnels start with the extended CONNECT method, which adds a :protocol pseudo-header to the classic CONNECT request. The original CONNECT method establishes a TCP tunnel to a host and port named in the request target. Extended CONNECT keeps the CONNECT method but introduces :protocol to select what kind of tunnel to build. For MASQUE, that value is connect-udp or connect-ip.

Extended CONNECT requires HTTP/2 or HTTP/3. The server advertises support by sending the SETTINGS_ENABLE_CONNECT_PROTOCOL setting, the same setting that enables WebSocket over HTTP/2 and HTTP/3. A MASQUE request carries a full set of pseudo-headers rather than a bare authority:

Pseudo-header Role
:method Always CONNECT
:protocol connect-udp or connect-ip
:scheme The request scheme, usually https
:authority The proxy's host and port
:path The expanded tunnel path on the proxy

The :path comes from a URI template the client configures ahead of time. Template variables fill in the tunnel target, which keeps the proxy endpoint discoverable through a well-known URI while letting the path encode where the traffic should go.

HTTP Datagrams and the Capsule Protocol

HTTP Datagrams are a convention for carrying multiplexed, possibly unreliable datagrams inside an HTTP connection. A MASQUE tunnel needs to move packet-style data that does not fit the request-response model, and HTTP Datagrams provide that channel. Each datagram begins with a context ID encoded as a variable-length integer, followed by the payload. Context ID zero carries the tunneled UDP or IP payload, and other context values are reserved for extensions.

The Capsule Protocol carries this data and related control messages through the request stream. A capsule is a type-length-value tuple: a variable-length integer type, a length, and a value. Capsules flow in the message content after a 101 or 2xx response, in both directions, for the life of the tunnel. The Capsule-Protocol header field, set to the Boolean value ?1, signals that the stream content uses the Capsule Protocol so intermediaries handle it correctly. Receivers silently drop capsule types they do not recognize, and intermediaries forward unknown types unchanged, which keeps the protocol extensible.

The transport mapping differs by HTTP version. HTTP/3 runs over QUIC and uses native QUIC DATAGRAM frames for unreliable delivery, enabled through the SETTINGS_H3_DATAGRAM setting. In HTTP/3 a datagram references its tunnel using a quarter stream ID, the stream ID divided by four. HTTP/2 has no unreliable datagram support, so the Capsule Protocol carries the datagrams as reliable, ordered DATAGRAM capsules instead. The Capsule Protocol applies only to extended CONNECT tunnels, which keeps web platform APIs from reaching capsule-based protocols directly.

Proxying UDP in HTTP

Proxying UDP in HTTP defines the connect-udp tunnel, which relays a single UDP flow between a client and a target host and port. The client sends an extended CONNECT request with :protocol set to connect-udp and a :path that names the target. After the proxy returns a 2xx response, each UDP packet travels as an HTTP Datagram with context ID zero. The proxy strips the framing and forwards the UDP payload to the target, then relays return packets back through the tunnel.

The default URI template encodes the target host and port as template variables:

https://proxy.example.re:443/.well-known/masque/udp/{target_host}/{target_port}/

A client tunneling to 192.0.2.6 on port 443 expands the template and sends the request to that path. The connect-udp tunnel is the common path for proxying QUIC and HTTP/3 traffic, since QUIC itself runs on UDP. A client behind a MASQUE proxy reaches an HTTP/3 origin by wrapping its QUIC packets in connect-udp datagrams.

Proxying IP in HTTP

Proxying IP in HTTP defines the connect-ip tunnel, which relays full IP packets rather than a single transport flow. The client sends an extended CONNECT request with :protocol set to connect-ip. Once the tunnel opens, complete IP packets travel as HTTP Datagrams with context ID zero, letting the tunnel carry any IP-based protocol at once. This is the basis for remote-access VPNs, site-to-site VPNs, and general packet forwarding over HTTP.

The default template uses optional target and protocol variables, which a wildcard fills when the client wants an unrestricted tunnel:

https://proxy.example.re:443/.well-known/masque/ip/{target}/{ipproto}/

IP proxying adds control capsules that UDP proxying does not need, because an IP tunnel often has to configure addressing and routing. The ADDRESS_ASSIGN capsule lets one endpoint assign its peer a list of IP addresses or prefixes to use as source addresses. The ROUTE_ADVERTISEMENT capsule communicates which address ranges an endpoint will route traffic toward. These capsules set up a working tunnel in-band, so a client that starts with no network configuration receives an address and routes through the tunnel itself.

UDP proxying vs IP proxying

The difference between connect-udp and connect-ip comes down to the layer each tunnel operates on. UDP proxying relays one named UDP flow to a specific target host and port. IP proxying relays whole IP packets and can carry many flows and protocols across a single tunnel.

Property connect-udp connect-ip
Layer UDP flow IP packets
Target One host and port One or more hosts, optionally any
Payload UDP payload Full IP packet
Control capsules None required ADDRESS_ASSIGN, ROUTE_ADVERTISEMENT
Typical use Proxying QUIC and HTTP/3 VPN-style full tunneling

UDP proxying suits a client that needs to reach one UDP service, most often a QUIC or HTTP/3 origin behind the proxy. IP proxying suits full-tunnel scenarios where the client routes all of its traffic through the proxy and needs an assigned address. Both run on the same HTTP Datagram and Capsule Protocol foundation, so a proxy can offer either over the same HTTP connection.

Example

A client establishes a connect-udp tunnel to a target UDP service through a MASQUE proxy over HTTP/2. The client has already configured the proxy's URI template and expands it with the target host 192.0.2.6 and port 443. The request uses extended CONNECT, so the :protocol pseudo-header selects the tunnel type and the :path carries the expanded well-known URI. The capsule-protocol field set to ?1 marks the stream as Capsule Protocol content.

Request

HEADERS
:method = CONNECT
:protocol = connect-udp
:scheme = https
:authority = proxy.example.re
:path = /.well-known/masque/udp/192.0.2.6/443/
capsule-protocol = ?1

The proxy accepts the tunnel with a 2xx response. After this point the HTTP stream carries HTTP Datagrams rather than a normal response body.

Response

HEADERS
:status = 200
capsule-protocol = ?1

Once the tunnel is open, each UDP packet travels as an HTTP Datagram with context ID zero. The proxy forwards the UDP payload to 192.0.2.6:443 and relays return packets back to the client. The same connection continues to serve other HTTP/2 streams in parallel, so the tunnel multiplexes alongside ordinary requests.

See also

Last updated: June 5, 2026