WebTransportο
py-libp2p ships an experimental libp2p-webtransport transport: HTTP/3
WebTransport (ALPN h3) with Noise XX on the first client-opened stream and
dual self-signed certificate rotation (/certhash/ in listen multiaddrs).
Spec: https://github.com/libp2p/specs/blob/master/webtransport/README.md
Status: prototype (π±). Prefer for DPI / censorship experiments and go/js/Kubo
parity; native quic-v1 remains the default high-performance UDP transport.
Enableο
Pass enable_webtransport=True to new_host / new_swarm. Listen on a
WebTransport multiaddr (note quic-v1 then webtransport):
from multiaddr import Multiaddr
from libp2p import new_host
host = new_host(enable_webtransport=True, enable_tcp=False)
listen = Multiaddr("/ip4/0.0.0.0/udp/0/quic-v1/webtransport")
Advertised addresses include one or two /certhash/<multibase-sha256>
components plus /p2p/<peer-id>. Dialers must use those certhashes;
a wrong hash fails Noise extension verification.
Well-known pathο
After the QUIC/TLS handshake (ALPN h3), the client opens an HTTP/3
CONNECT with :protocol = webtransport to:
/.well-known/libp2p-webtransport?type=noise
That session carries libp2p streams. The first client-opened bidirectional
WebTransport stream runs Noise XX; the server includes the
webtransport_certhashes extension so the dialer can bind Peer ID to the TLS
certificate fingerprints advertised in the multiaddr.
ALPN comparison (censorship story)ο
Transport |
QUIC ALPN |
On-wire look |
|---|---|---|
Native |
|
Distinct from web traffic; easy to DPI |
WebTransport |
|
Ordinary HTTP/3 (same class as modern browsing); CONNECT to a well-known path |
Residual DPI risks: path fingerprinting on
/.well-known/libp2p-webtransport, unusual cert properties, traffic timing,
and blocking all HTTP/3 still apply. WebTransport is camouflage, not a VPN or
MASQUE proxy fleet. For go-libp2p β₯0.49 interop, the server also advertises
draft-15 SETTINGS_WT_ENABLED (0x2c7cf000) alongside aioquicβs draft-06
codepoint, and accepts :protocol values webtransport and
webtransport-h3.
TLS + Noiseο
WebTransport requires TLS (HTTP/3) and Noise for Peer ID authentication. That is intentional double encryption: TLS authenticates the certificate / certhash path; Noise authenticates the libp2p identity. Do not drop Noise.
Self-signed leaves mirror go-libp2p generateCert: empty subject,
BasicConstraints (CA), KeyUsage (digitalSignature | keyCertSign),
ExtKeyUsage (serverAuth | clientAuth), ECDSA P-256, and a default validity
of 13 days (hard ceiling 14 days per the W3C custom-certificate rule).
Those fields are required for Chromium to accept the leaf via
serverCertificateHashes even when the SHA-256 matches /certhash/.
Browser dialsο
Browser clients (js-libp2p @libp2p/webtransport, Chromium
WebTransport) must run in a secure context (https: or
http://localhost / http://127.0.0.1). Prefer Chromium: it supports
hash-pinned self-signed certs through serverCertificateHashes, which maps
to libp2p multiaddr /certhash/ components. Firefox WebTransport pinning
differs and may not accept the same path.
Manual check: listen with enable_webtransport=True, copy a listen multiaddr
that includes /certhash/, convert the SHA-256 digests for
serverCertificateHashes, then confirm await wt.ready succeeds before
Noise / application streams. See examples/webtransport/DEMO.md.
Demoο
See examples/webtransport/webtransport_echo.py and
examples/webtransport/DEMO.md.
go-libp2p interopο
Local harness under tests/interop/go_libp2p/webtransport/ (pinned go-libp2p
v0.49.0). Build with tests/interop/go_libp2p/scripts/setup_go_webtransport.sh
and run pytest tests/interop/go_libp2p/test_webtransport_interop.py.