PQ CRYPTA PLATFORM

🏠 Main

🧪 Interactive Apps

📰 News

🛡️ PQ Crypta Proxy

👤 Account

⟨ QUANTUM ERROR PORTAL ⟩

Navigate the Error Dimensions

PQ Crypta Logo

The Whole Surface, Side by Side

PQ Crypta Proxy measured against NGINX, HAProxy, Envoy, Caddy, Traefik and LiteSpeed across 217 features — including the ones we lose

217 features 9 proxies Source-validated Allan Riddel · Architect, PQ Crypta · September 2026
Abstract

Feature charts are usually written by the vendor who wins them. This one is too — so every value in the PQ Crypta column below was established from the pqcrypta-proxy source tree at v0.2.2 (57,441 lines of Rust across 49 modules), from the running configuration on the live edge, or from a probe against the production endpoint, rather than from a description of the software. The evidence for each is listed on the Method tab, so the claims can be checked. Competitor columns come from each project's own documentation, release notes and issue tracker. 217 features across 13 categories. 54 of them have no equivalent anywhere else in the field; 5 are ones where somebody beats us, and those are named rather than omitted.

What This Compares

Nine proxies, chosen because they are what an operator actually evaluates: the two incumbents in both their free and paid forms, the service-mesh data plane, the two config-simplicity challengers, and the web server that shipped HTTP/3 before anyone else.

ProxyEdition comparedWhy it is here
PQ Crypta Proxy0.2.2, MIT/Apache-2.0The subject. Rust, single binary.
NGINXOpen Source, mainlineThe default answer for two decades.
NGINX PlusF5, licensed, with App ProtectWhere NGINX's WAF, active health checks and cache purge actually live.
HAProxyCommunityThe load-balancing reference implementation.
HAProxy EnterpriseHAProxy TechnologiesWhere its WAF, native JA3/JA4 and PQC builds live.
EnvoyCNCF, currentThe service-mesh data plane; the only other proxy here with CONNECT-UDP.
Caddy2.10+The only other proxy in this set with automated server-side ECH.
Traefik3.5+Container-native ingress; added X25519MLKEM768 in 3.5.0.
LiteSpeedLSWS / OpenLiteSpeedShipped HTTP/3 in 2019, before anyone else on this list.

The Scorecard

Each graded row scores 2 for a native implementation, 1 for a partial one — an add-on module, a third-party plugin, or a capability locked behind a paid tier — and 0 for absent. 215 of the 217 rows are graded this way; the rest carry a literal value such as a rule count. This is a breadth measure and nothing more: it counts whether a capability exists, never how fast, how mature, or how well audited it is. A proxy that does eight things superbly can score below one that does forty adequately, and for many deployments the first is the right choice.

Breadth of native capability across 215 graded features
  1. PQ Crypta Proxy 0.2.2 98% 210 native · 2 partial
  2. HAProxy Enterprise 55% 99 native · 40 partial
  3. NGINX Plus F5, licensed 53% 95 native · 39 partial
  4. Envoy CNCF 48% 85 native · 35 partial
  5. HAProxy Community 43% 67 native · 52 partial
  6. Caddy v2.10+ 43% 63 native · 60 partial
  7. Traefik v3.5+ 38% 62 native · 41 partial
  8. NGINX Open Source 38% 64 native · 36 partial
  9. LiteSpeed LSWS / OLS 35% 49 native · 51 partial

Each bar is one proxy's 215 graded rows: the solid segment is what it implements natively, the second segment what it reaches only through a module, a third-party plugin or a paid tier. The full row-by-row data is the table on the Matrix tab.

How to Read a Cell

Native — in the core, no extra parts Partial — add-on module, third-party plugin, or paid tier only Not available

The distinction between the first two symbols is where most of the argument lives, so it is drawn strictly. NGINX can serve X25519MLKEM768 — if you rebuild it against OpenSSL 3.5, which the distribution packages do not do, so that is a full mark for the software and a caveat in the note. HAProxy Community's post-quantum curves are only present in builds shipped by HAProxy Technologies, so that is partial. NGINX's ModSecurity WAF reached end of life in March 2024 and the replacement is the licensed App Protect, so NGINX Open Source scores zero for a WAF and NGINX Plus scores full. A capability that exists only as a community plugin is partial no matter how good the plugin is, because it is not what you get when you install the thing.

A note on our own column. Validation was done to establish what the code does, not to check the documentation — but it doubles as a check, and every claim tested traced back to an implementation. The evidence for each is on the Method tab, so the working is visible rather than asserted.

Show 217 features compared
Native Partial / module / plugin / paid tier Absent   Hover any symbol for its meaning; scroll the table sideways for the full field.

PQ Crypta Proxy 0.2.2 against the field — 217 features

Feature support by proxy: native, partial or absent, across 217 features.
Feature PQ Crypta Proxy 0.2.2 NGINX Open Source NGINX Plus F5, licensed HAProxy Community HAProxy Enterprise Envoy CNCF Caddy v2.10+ Traefik v3.5+ LiteSpeed LSWS / OLS
Protocols & Transport
HTTP/1.1 reverse proxying
HTTP/2 (RFC 9113)
HTTP/3 (RFC 9114)
QUIC v1 (RFC 9000)
Advertise QUIC v1 only in Version NegotiationThe QUIC stack default also lists draft-29..34, which it cannot actually handshake; the listener overrides supported_versions so VN advertises only what the endpoint really speaks, plus the RFC 9287 GREASE version.
Multipath QUIC (draft-ietf-quic-multipath)Concurrent data-carrying paths, per-path packet-number spaces, per-path loss recovery and congestion control, ACK_MP / PATH_ABANDON / PATH_STATUS / MAX_PATH_ID / PATHS_BLOCKED, per-path CID spaces and a scheduler. Budget set by server.max_concurrent_multipath_paths.
QUIC connection migration — operator controlEvery QUIC stack implements migration; only here is it a config switch (enable_quic_migration).
QUIC Retry / source-address validation
QUIC ACK Frequency extension (draft-ietf-quic-ack-frequency)Negotiated, so inert against clients that lack it; cuts ACK traffic and CPU on high-throughput connections.
WebTransport — native server sessionsBidirectional streams, unidirectional streams and datagrams, handled in-process rather than passed through.
WebTransport origin validation (allowlist)
WebTransport per-origin rate limitingMax sessions per origin, streams per session, datagrams per second.
WebTransport per-domain SNI certificate selection
MASQUE / CONNECT-UDP (RFC 9298)UDP relayed over HTTP/3 Extended CONNECT, with host:port allowlist, per-session idle timeout and per-connection session cap.
HTTP Datagrams (RFC 9297)
Extended CONNECT (RFC 8441 / 9220)
WebSocket proxying
gRPC-aware proxyingPQ Crypta carries gRPC over its HTTP/2 path but has no gRPC-specific features (no transcoding, no gRPC health protocol). Envoy is the reference implementation here.
103 Early Hintspreload, dns-prefetch, preconnect, modulepreload and speculative prerender, scoped per host/path and hot-reloadable.
RFC 9218 Extensible Priorities
Alt-Svc built from the actual listener ports at startupRather than a hardcoded constant, the value is assembled from udp_port plus additional_ports.
Per-host Alt-Svc: clear (force TCP for named hosts)tcp_only_hosts evicts cached QUIC upgrades so a browser returns to TCP/TLS.
Per-host HTTP/1.1-only ALPN suppressionhttp11_only_hosts drops the h2 ALPN entry so a browser opens one TCP connection per fetch instead of coalescing — required for a truthful parallel-stream test.
PROXY protocol v2
Unix-socket backends
FastCGI / uwsgi / SCGI backend protocolsPQ Crypta speaks HTTP over a Unix socket to PHP-FPM, not the FastCGI wire protocol.
Generic L4 stream proxying (arbitrary TCP/UDP)PQ Crypta does SNI-based TLS passthrough but is not a general stream load balancer.
Any number of additional listener ports, QUIC on each
Request coalescing (dedupe identical in-flight requests)
Post-Quantum Cryptography
Hybrid PQC key exchange — X25519MLKEM768Verified on the live edge: OpenSSL s_client reports "Negotiated TLS1.3 group: X25519MLKEM768".
SecP256r1MLKEM768
SecP384r1MLKEM1024 and X448MLKEM1024
Pure ML-KEM-1024 group
Configurable KEM preference order
ML-DSA-87 (FIPS 204) server certificatesHAProxy states plainly that PQC signatures are not supported yet. Envoy's PQC issue is closed as not planned, blocked on a BoringSSL upgrade. Go's crypto/tls has no ML-DSA, which rules out Caddy and Traefik.
ML-DSA certificate selection per SNI
PQC downgrade detectionThe negotiated group is read off the live connection via SSL_get0_group_name rather than assumed. That distinction is the whole feature: a detector that assumes the group it is looking for can never fire, and would report a clean result on a connection that had silently fallen back to classical.
Downgrade action: block (421) / log / allow
require_hybrid and minimum PQC security level
PQC-sealed TLS 1.3 session ticketsEach ticket carries its own ML-KEM-1024 encapsulation; resumption state is sealed with an AES-256-GCM key derived by HKDF-SHA384, KEM ciphertext as associated data. Keypair rolls on the ticket lifetime, one previous generation retained.
Legacy pre-NIST Kyber768, feature-gated off by defaultCompile-time opt-in with a deprecation warning, for peers that have not migrated to FIPS 203.
FIPS-validated crypto build
TLS, Certificates & ECH
TLS 1.3 as the default minimum on every listenerOthers permit TLS 1.2 by default and require configuration to raise the floor.
TLS termination
TLS re-encryption to backend, with mTLS
TLS passthrough (SNI-routed, no decryption)
Client certificate authentication (mTLS)
Server-side Encrypted Client Hello (draft-ietf-tls-esni-25)Written into a rustls fork because upstream rustls is client-side only in every version to 0.23.42. HPKE decryption is delegated to rustls's own Hpke::open — no new cryptography, only ClientHello reconstruction ahead of the unmodified handshake. NGINX 1.29.4 has ECH but needs an OpenSSL branch carrying it; HAProxy has a feature request and no implementation; Envoy has an open issue.
ECH on QUIC as well as TCPECH is a TLS 1.3 extension and QUIC is TLS 1.3, so the same handshake resolves it — provided the QUIC listener is wired to it. Caddy is marked full here because it documents ECH and HTTP/3 without qualifying either; no limitation is published, and a gap will not be asserted from inference.
ECH HPKE key rotation with previous configs retainedRotated by ech-keygen / ech-rotate.timer; old configs kept so clients holding a cached DNS record still complete. Live: the pqcrypta.com HTTPS record publishes ech=AD/+DQA7ZA...
ECH outcome exposed to the backendx-tls-ech carries accepted / rejected / not-offered.
0-RTT early data
0-RTT replay protection with a nonce storestrict / session / none. Everyone else forwards an Early-Data header and makes replay the application's problem.
Per-route 0-RTT control with RFC 8470 425 Too Early
OCSP stapling
ACME certificate automationNGINX's native ACME module is a preview supporting HTTP-01 only. HAProxy Community has none.
ACME DNS-01 challenge
ACME External Account Binding / arbitrary CA
Certificate Transparency submission after issuanceNew certs POSTed to configured CT logs at /ct/v1/add-chain.
Certificate hot reload without restart or dropped connections
Private key file permission validation at startupstrict_key_permissions aborts boot on insecure permissions.
Multi-certificate SNI resolver
Handshake facts injected to the backendx-tls-version, x-tls-cipher, x-tls-group, x-tls-alpn, x-tls-ech — each stripped from the inbound request before being set, so a caller cannot assert a handshake it did not have.
TLS Fingerprinting & Bot Management
JA3 fingerprinting on TCPHAProxy Community needs a Lua plugin; Enterprise has it natively. NGINX needs a third-party source patch.
JA4 fingerprinting on TCP
JA3 / JA4 fingerprinting over QUIC and HTTP/3Over QUIC the ClientHello arrives inside encrypted Initial CRYPTO frames, so the vendored rustls and noq forks surface it through HandshakeData for the same extractor the TCP paths use. The JA4 transport marker is q over QUIC, t over TCP.
Operator-supplied fingerprint classification databaseConsulted before the built-in table, matching JA3 then JA4.
Automatic blocking on known-malicious fingerprints
Automatic blocking on scanner fingerprints
JA3 / JA4 replay detectionFlags one fingerprint arriving from many IPs inside a window — credential stuffing and fingerprint spoofing.
JA3 / JA4 drift detectionFlags cipher or extension composition changing under a stable hash — a library upgrade, or evasion.
Fingerprint-keyed rate limiting (NAT-friendly)Distinguishes clients sharing one corporate IP.
Observed fingerprint corpus persisted and reloadedPre-hash JA3 string, per-fingerprint connection counts and the User-Agents seen carrying them, bounded and evicted least-recently-seen. Evidence only — it never feeds classification or blocking.
Verified crawler check (reverse plus forward-confirmed DNS)A declared Googlebot is only treated as one when rDNS and the forward lookup agree.
Fingerprint classification cache with TTL and background cleanup
Web Application Firewall
WAF inside the core binary — no module, no sidecar, no licenceNGINX ModSecurity reached end of life in March 2024 and the replacement is the licensed App Protect. HAProxy Community routes to an external ModSecurity daemon over SPOE.
Rules shipped in-treeEvery rule carries a stable PQW-* identifier. 256 0 CRS CRS vendor 0 CRS CRS CRS
Severity-weighted anomaly scoring rather than first-match blockingInfo 1, Low 3, Medium 5, High 8, Critical 10. Medium equals the default threshold so one Medium rule blocks alone; Low is over half, so one weak signal is never enough and two corroborating ones are.
SQLi, XSS and path traversal detection
NoSQLi, SSTI, JNDI, prototype pollution, GraphQL detection
Command injection, XXE, insecure deserialization, LFI, CRLF
Structural request-smuggling detectionA second Content-Length, or Content-Length beside Transfer-Encoding — scored as a rule, not merely rejected by the parser.
Scanner probe paths blocked before pattern scanning54 rules covering .git, .env, .aws, wp-login.php, terraform state, SSH keys and CI/CD files — automated scanners never reach the backend or pollute the error-rate metrics.
Bad-bot User-Agent rule set60 rules.
Request body scanning, JSON aware, size capped
Compressed request bodies decoded before scanning
All headers scanned, with header count and size caps
Multi-pass decoding of nested encodings
Per-path rule and category exclusions
Detect-only mode alongside block mode
Per-route WAF enable and mode override
X-Forwarded-For exempted from SSRF patternsLoopback and RFC1918 addresses in a forwarded chain are legitimate proxy hops, not SSRF — this is a false-positive class that bites everyone running behind another proxy.
Regression corpus, baseline and history gating CIpentests/regression: a labelled corpus, a committed baseline and a run history; the gate fails the build on exit code. It has already caught a loopback false positive.
Rate Limiting & DoS Protection
Per-IP request rate limiting
Connection rate limiting — new connections per secondDistinct from a concurrency cap: a client that opens and closes as fast as it can never trips max_connections_per_ip.
Concurrent connections per IP
Multi-dimensional keys: IP, JA3, JA4, JWT subject, API key, headerA resolution table, not a single string; the first key derivable from the request wins, with a configured fallback.
Composite keys (several dimensions combined)
JWT subject limiting with signature verification firstHMAC-SHA256 verified before the sub claim is trusted; unsigned tokens and non-HMAC algorithms rejected. Limiting on an unverified claim is limiting on attacker-chosen input.
Per-route limit overrides
Adaptive baseline / statistical anomaly detectionLearns normal traffic and flags deviation by standard-deviation multiplier.
Distributed limiting across instancesPQ Crypta uses Redis with atomic Lua token-bucket and fixed-window scripts. HAProxy uses stick-table peers; Envoy needs an external RLS; NGINX Plus uses zone sync.
IPv6 subnet aggregationA /64 is one client, not 2^64 of them.
Automatic IP blocking on threshold, with expiry
Error-rate driven automatic banningWindowed 4xx/5xx rate with a minimum-request floor, so one early error cannot ban a client.
GeoIP country blocking (MaxMind)
GeoIP block expirygeoip_block_duration_secs sets how long a country block holds, default 24 hours, so a block ages out on its own rather than accumulating indefinitely.
Database-synced IP and CIDR blocklistsCIDR ranges match whole subnets. The reload reconciles in both directions — entries that disappear are released, so unblocking in the dashboard actually lifts a live block. Only DatabaseSync entries reconcile; blocks the proxy raised itself are untouched.
Immediate unblock endpoint that reaches every listenerPOST /blocklist/unblock/:ip drops the IP and any CIDR entry covering it without waiting for the next sync.
One shared security state across every listener and transportBlocked IPs, rate-limiter counters, the fingerprint corpus and synced blocklists live in one SecurityState that QUIC and all three TCP paths share, so a block raised on any transport is enforced on every one of them and the admin API reaches them all. A per-listener copy would let a client refused on one port simply continue on another.
Request body size limit with 413
Header count and size limits
Zero-Trust & Hardening
zero_trust_mode startup validationRefuses to boot unless mTLS is required, no backend is plaintext, no CIDR is trusted and the admin API carries HMAC proof-of-possession.
Per-route HMAC proof-of-possessionHMAC-SHA256 over the full path and query string.
Nonce-bound replay preventionX-Request-Nonce folded into the signature, 300-second window.
internal = true routes default to requiring a client certificate
Admin API HMAC proof-of-possession alongside bearer token
Admin API loopback enforcementrequire_loopback defaults on and aborts startup when the admin API is bound to a non-loopback address — a plain-HTTP token on a public interface is a credential leak, not a warning.
Admin brute-force lockout with exponential back-offPer-IP and global, 5 minutes base up to 30.
SSRF protection on backend addresses at config loadLink-local rejected outright; RFC1918 warns and needs explicit acknowledgement.
Insecure backend TLS blocked unless explicitly flaggedtls_skip_verify = true is refused at config load without --allow-insecure-backends.
Log injection preventionNewlines and control characters stripped from every user-controlled field before it reaches an access or audit log.
Subprocess environment sanitisationEvery openssl subprocess runs with env_clear() against PATH and LD_PRELOAD injection.
Memory-safe core with unsafe code denied at the lint levelunsafe_code = "deny" crate-wide; one targeted allow in pqc_tls.rs for the OpenSSL FFI binding. NGINX, HAProxy and LiteSpeed are C or C++.
Runtime self-verification at startupA real in-memory TLS 1.3 handshake against the proxy's own ServerConfig, plus live probes of the WAF, rate limiter, mTLS and every bound listener. Anything not probed is labelled "configured" and is never allowed to masquerade as a measurement.
Load Balancing & Resilience
Load balancing algorithms shippedHAProxy remains the reference for breadth here. 6 4 6 10+ 10+ 6 8 2 3
least_connections
round_robin
Smooth weighted round-robin
Random selection
IP hash / consistent hashing
Least response time (moving average)
Backend pools per route
Per-server weight
Per-server priority failover tiers
Sticky sessions — cookie
Sticky sessions — custom header
Session affinity TTL eviction, per-mode mapsEach affinity mode keeps its own map and evicts stale entries.
Passive health-aware routing
Proactive active health checksBackground TCP-connect checks mark a backend unreachable before traffic hits it. NGINX Open Source has passive checks only.
Circuit breaker with automatic recovery
Per-backend circuit-breaker overridesFailure threshold, half-open delay and success threshold per backend.
Per-backend retry with exponential backoffRetry on 5xx, connect failure or timeout.
Connection draining on backend removalIn-flight requests complete before the backend leaves rotation.
Request queuing when every backend is saturated
Slow start for recovering backendsAvoids the thundering herd when a circuit breaker reopens.
Per-backend connection pool tuningIdle timeout, max idle, max total, acquire timeout.
Backend request timeout bounding the whole requestA hung backend returns 504 instead of holding the client connection open — connection-setup timeouts alone do not do this.
Canary / percentage traffic splitting
Sticky canary assignmentA PQCPROXY_CANARY cookie keeps a client on the same side for the duration of the experiment.
Canary auto-rollback on sliding-window error rateThe canary suspends itself when its error rate crosses the threshold — no human in the loop.
Live canary control without restartGET /canary, POST /canary/suspend/:id, /resume/:id, /weight/:id.
Traffic shadowing / mirroringFire-and-forget copy to a secondary backend; the client only ever sees the primary response. Active on HTTP/1.1, HTTP/2 and HTTP/3.
Per-server QUIC keep-alive interval
Caching & Compression
Response cacheHAProxy's is a deliberately small object cache. Envoy's cache filter is alpha. Traefik has none.
RFC 9111 Cache-Control parsingmax-age, s-maxage, no-cache, no-store, private, public.
ETag / If-None-Match conditional 304Strong and weak comparison.
Last-Modified / If-Modified-Since conditional 304
Vary support with a guard on unsafe Vary valuesA stored Vary: Cookie or Vary: Authorization is a cross-user leak waiting to happen; those responses are not stored.
Cache purge API — everything, by host, by prefix, or one exact URLpath= without host= is refused rather than silently widened. Audit-logged with scope and target. In NGINX this is a Plus-only feature.
One cache instance per process, shared by every listenerThe key is METHOD|host|path, with no port or protocol in it, so one entry serves h2, h3 and every listening port, and a purge clears the resource everywhere at once. Per-listener caches would store the same URL several times over and let a purge miss most of the copies.
Correct HEAD semantics (RFC 9110 §9.3.2)A HEAD response carries the headers a GET would. Synthesizing content-length: 0 from an empty buffered body tells every link checker, uptime monitor and scanner that a dynamic page is empty. Fixed on all three transports.
Hop-by-hop header stripping before caching and forwardingTransfer-Encoding, Connection, Keep-Alive, Proxy-Connection, Upgrade, TE, Trailer, Proxy-Authenticate, Proxy-Authorization — leaving these on causes ERR_QUIC_PROTOCOL_ERROR on HTTP/3.
Brotli
Zstandard
gzip and deflate
Content-type aware compression, already-compressed skipped
Routing & Request Handling
Host-based routing
Path prefix and exact matching
Path regex matching with a ReDoS size guardEveryone matches regex; the pattern size limit is what stops a config from becoming a denial of service.
Per-route timeout override
Per-route request and response header add / remove
Per-route CORS with preflight handling
CORS headers on 429 rate-limit responsesWithout them a browser reports a rate limit as a CORS failure and the developer chases the wrong bug.
Per-route redirect
Per-route security policy blockWAF on/off and mode, rate limits, JA3 allowlist, mTLS, HMAC signing, and skip_bot_blocking for routes that serve automated clients — applied before the global checks.
Response JSON field strippingRemoves named fields from a backend JSON response before it reaches the client.
Cookie security attribute enforcementSecure, HttpOnly and SameSite injected onto backend Set-Cookie headers.
Path normalization as an explicit switch
HTTP to HTTPS redirect with Host validationAn unknown Host receives 400 rather than an open redirect.
Client identity forwarding to backendX-Real-IP, X-Forwarded-For, X-Forwarded-Proto, plus client certificate details.
Observability
Prometheus metrics endpointNGINX Open Source exposes stub_status only.
Latency percentiles p50 / p95 / p99
JSON metrics endpoint
Health-check traffic excluded from metricsOtherwise a 1-second liveness probe dominates every percentile you compute.
OpenTelemetry OTLP export
W3C TraceContext propagation
B3 multi-header and single-header propagation
Trace propagation on HTTP/3 and WebTransportA composite propagator on every transport, not only the TCP ones.
Trace ID correlated into the access log
Structured access log, JSON or text
Structured security audit logAdmin actions, auth failures, WAF blocks and detects, IP blocks, rate-limit hits, PQC downgrades, JA3 replay and drift, config and TLS reloads — written asynchronously as JSON.
Server-Timing header with proxy latency breakdownLive: server-timing: proxy;dur=4.45;desc="PQCProxy Processing", quic;desc="QUIC v1".
NEL and Report-To headers
Health endpoints for QUIC and WebTransport specifically
Operations
Hot configuration reload without dropping connections
Config file watching with automatic reload--watch-config; no signal, no orchestration.
Environment config overlay--env <name> merges config.<name>.toml over the base config.
Config schema versioningA version field; warns when absent, errors when newer than the binary understands.
Startup validation of conflicting settingsNot a syntax check: PQC with passthrough, 0-RTT on non-safe routes without replay protection, mTLS required with no CA configured.
Log rotation via SIGHUP, logrotate compatible
Graceful shutdown drain polling active connectionsPolls at 100 ms and exits the moment connections reach zero — an idle restart is not penalised.
Admin / runtime control API22 routes: health, metrics, reload, TLS reload, shutdown, blocklist, cache, canary, backends, ACME, OCSP, rate limits.
Single static binary, no runtime dependencies
Linux, macOS and Windows
Windows service integration
Dynamic service discovery (Docker, Kubernetes, Consul, xDS)This is Traefik's and Envoy's home ground. PQ Crypta is configured from a file.
Scripting / plugin extension (Lua, WASM, Go modules)
Testing & Assurance
HTTP/3 client conformance suite as a public service51 anomalies, each citing the RFC clause it exercises: reserved frame types, a duplicated SETTINGS identifier, a control stream opening with the wrong frame, an unknown QUIC frame, a Stateless Reset, a path-MTU black hole, refused 0-RTT. Every test binds its own UDP port because anomalies like supported_versions are endpoint-wide.
Verdicts asymmetric by class, with evidence required to failIgnoring a reserved HTTP/3 frame is a pass; ignoring a reserved QUIC frame is a failure, because QUIC reserves no ignorable frame types. A failure needs positive evidence the client read the anomaly — a rejection whose CONNECTION_CLOSE was lost looks exactly like no rejection, so silence is inconclusive, never a pass and never a fail.
Machine-readable catalogue, JSON reports and an SVG badge
Conformance driver binary for third-party CIh3-conformance drives any client from a pipeline.
QUIC impairment engine (telemetry wall)Six independent uni-streams at 20 Hz; a control stream accepts delay, loss, bandwidth cap, jitter and disconnect scoped to individual channels, leaving the others untouched — the opposite of TCP head-of-line blocking.
QUIC versus TCP speed test serverDatagram RTT probing, stream download and upload throughput, packet-loss measurement, MTR hop traceroute with GeoIP city, ASN and country annotation.
Black-box pentest suite in-tree32 scripts across 12 phases: WAF bypass and advanced evasion, bot detection, header injection, rate limits, TLS, HTTP smuggling, SSRF, cache poisoning, timing oracles, race conditions, XXE, SSTI, file upload, gRPC and AI/LLM attack surface.
QPACK dynamic-table emission proof harnessEvery reachable HTTP/3 client advertises a QPACK table capacity of zero, which forbids the dynamic table outright — so both tests correctly report inconclusive against real clients and the emission behind them is never exercised. An unrun path is not a working path, and from outside a literal fallback is indistinguishable from a working dynamic table. So a client that grants what the specification requires is built in-tree, and the bytes on the wire are asserted.
0-RTT reject proof harnesscurl does not attempt early data over HTTP/3, so every live run proves nothing. A resuming client is built in-tree: it sends early data, the server answers HelloRetryRequest, the socket counts the 0-RTT packets that arrived, and the request completes on 1-RTT keys.

CRS in the rule-count row means the proxy ships no rules of its own and relies on the OWASP Core Rule Set through ModSecurity or Coraza. vendor means a proprietary rule set supplied under licence. PQ Crypta's 256 rules are counted from the PQW-* identifiers in src/waf.rs: 60 bot, 54 scanner-probe, 18 XSS, 18 SQLi, 17 SSRF, 16 traversal, 15 command injection, 13 deserialization, 10 anomaly, 9 SSTI, 7 NoSQLi, 7 JNDI, 6 LFI, 5 XXE, 3 prototype pollution, 3 CRLF, 2 GraphQL.

Where We Stand Alone

54 of the 217 rows are ones where PQ Crypta has a native implementation and no other proxy in the field has even a partial one. They cluster, and the clusters say something about what the product is for.

Post-quantum, past the key exchange
  • Everyone credible now does X25519MLKEM768. That race is over and it was never the hard part.
  • ML-DSA-87 server certificates are the next step and nobody else has taken it. HAProxy says so in writing; Envoy's issue is closed as not planned; Go's crypto/tls has no ML-DSA, which rules out Caddy and Traefik at the language level.
  • PQC downgrade detection that reads the negotiated group off the connection rather than assuming it — the check was hardcoded here once too, and could not fire.
  • ML-KEM-1024-sealed session tickets. A hybrid handshake protects the connection; the ticket that resumes it was still classical.
  • And the certificate machinery around it is not a lesser story: server-side ECH on TCP and QUIC with rotating HPKE keys published in DNS, ACME with HTTP-01 and DNS-01, External Account Binding for any CA, and Certificate Transparency submission after issuance — which nothing else in the field does at all.
The transports nobody else terminates
  • Multipath QUIC with concurrent data-carrying paths. No other proxy here negotiates the extension at all.
  • WebTransport as a first-class server — sessions, streams and datagrams handled in-process, with origin validation and per-origin limits. Envoy passes extended CONNECT through; it does not run sessions.
  • MASQUE CONNECT-UDP is the one place Envoy is also present.
  • JA3/JA4 over QUIC. The ClientHello is inside encrypted Initial CRYPTO frames, so this needs the QUIC stack to surface it — which is why every fingerprinting implementation in the field is TCP-only.
Proof instead of assertion
  • Runtime self-verification. A real TLS 1.3 handshake against the proxy's own config at startup, plus live probes of the WAF, rate limiter and mTLS. Anything not probed is labelled configured, never verified.
  • A conformance suite that fails honestly. 51 anomalies; a failure needs positive evidence the client read it, because a rejection whose CONNECTION_CLOSE was lost looks exactly like no rejection.
  • Proof harnesses for the untestable paths — QPACK dynamic table and 0-RTT reject, both driven by clients built in-tree because no real client exercises them.
  • 32 black-box pentest scripts and a gating WAF regression corpus in the repository, not in a report.
Operational honesty at the edges
  • Bidirectional blocklist reconciliation. Unblocking in a dashboard has to actually lift the block; a sync that only ever adds is a support ticket generator.
  • CORS headers on 429s, so a rate limit reads as a rate limit and not as a CORS bug.
  • Health-check traffic excluded from metrics, so a one-second liveness probe does not own every percentile.
  • Admin loopback enforcement that aborts startup rather than logging a warning nobody reads.

Where They Beat Us

A chart that only shows wins is an advertisement. These are the places where the honest answer is that another proxy is the better tool, and no amount of protocol coverage changes it.

HAProxy — load balancing depth
  • Ten-plus algorithms to our six, and stick-tables are a more general primitive than anything we expose.
  • The peers protocol synchronises state across a fleet without the Redis dependency we take.
  • Two decades of tuning at the top of the throughput charts, and a runtime API with far more surface than our 22 admin routes.
NGINX — ecosystem and backends
  • FastCGI, uwsgi and SCGI. We speak HTTP over a Unix socket to PHP-FPM; we do not speak the FastCGI wire protocol at all.
  • A module ecosystem, mail proxying, and a stream module that makes it a general L4 balancer. Our L4 story is SNI passthrough and stops there.
  • proxy_cache has been load-bearing on the public internet for fifteen years. Ours has been in production for months.
Envoy — dynamic configuration
  • xDS. We are configured from a file with a watcher on it. Envoy reconfigures from a control plane, continuously, at fleet scale.
  • gRPC is native: transcoding, the gRPC health protocol, per-method routing. We carry gRPC over HTTP/2 and offer nothing gRPC-specific.
  • WASM and ext_authz filters mean someone else's logic runs in the data path. We have no extension mechanism at all.
Traefik and Caddy — getting out of the way
  • Service discovery. Traefik reads Docker labels, Kubernetes CRDs and Consul. For a container fleet that is the entire job, and we do not do it.
  • Caddy's on-demand TLS issues a certificate for a hostname it has never seen, mid-handshake. Nothing in our ACME implementation does that.
  • Both are configured in a fraction of the lines. Our config surface is 367 fields across 36 structures, which is the cost of the column we won.
All of them — maturity
  • A CVE history, third-party audits, distribution packaging, and an operator base measured in millions. We have none of that yet, and it is not a feature you can implement.
  • LiteSpeed shipped HTTP/3 in 2019 and has served it at scale for longer than this project has existed.
  • Breadth is cheap to claim and expensive to keep correct. The 217 rows above are a snapshot of one release, validated once.

Who Should Pick What

If your problem is…PickBecause
The widest algorithm set, and raw throughput above all elseHAProxyTen-plus algorithms, stick-tables as a general primitive, peers-based state sync without a Redis dependency, and twenty years at the top of the throughput charts. PQ Crypta does full L7 balancing — six algorithms, pools, canary, shadowing — but not at that depth or that speed.
Serving files, and FastCGI or uwsgi application backendsNGINXIt is a web server as well as a proxy. PQ Crypta is only a proxy: it serves no static files of its own and does not speak the FastCGI wire protocol. Its RFC 9111 cache is real, but proxy_cache has fifteen more years of production behind it.
A service mesh data plane driven by a control planeEnvoyxDS and native gRPC are not things the others approximate.
Container ingress that configures itselfTraefikDocker labels and Kubernetes CRDs, no file to write.
HTTPS for hostnames you do not know in advanceCaddyOn-demand TLS issues a certificate mid-handshake for a host it has never seen, and the config is a fraction of the lines. Not ECH or ACME as such — PQ Crypta has both, and adds DNS-01, EAB and Certificate Transparency submission on top.
A quantum-resistant edge that must prove what it negotiatedPQ CryptaML-DSA-87 certificates, downgrade detection off the live connection, PQC-sealed tickets, and a startup that verifies rather than announces.
Terminating HTTP/3, WebTransport and MASQUE in one processPQ CryptaMultipath QUIC, native WebTransport sessions, CONNECT-UDP and JA3/JA4 over QUIC.
A WAF, fingerprinting and adaptive rate limiting without a licencePQ Crypta256 scored rules, JA3/JA4 on every transport and Redis-distributed limiting in the core binary.

How Our Column Was Validated

The rule was that a description of the software is not evidence of it. Every entry was established from an implementation in src/, from the configuration the production process is actually running, or from a probe against the live endpoint — and each one is listed below with the check that established it, so the column can be audited rather than taken on trust.

ClaimHow it was checkedResult
Hybrid PQC key exchange is live, not merely compiled inopenssl s_client -connect pqcrypta.com:443 -tls1_3 against the production edgeNegotiated TLS1.3 group: X25519MLKEM768
The negotiated group is read, not assumedFFI binding to SSL_get0_group_name in src/pqc_tls.rs:1032, reading the group off the live SSL*Confirmed in code
Server-side ECH is deployed and publishedHPKE keypair and config list on disk at /etc/pqcrypta/ech-configs; dig HTTPS pqcrypta.comRecord carries ech=AD/+DQA7ZA…
ECH is a genuine server-side implementation817 lines at vendor/rustls-fixed/rustls/src/server/ech.rs; upstream rustls is client-side only to 0.23.42Confirmed in code
Multipath QUIC is negotiated, not aspirationaltransport_config.max_concurrent_multipath_paths() at src/quic_listener.rs:200, over the vendored noq stackConfirmed in code
The WAF ships 256 rules with anomaly scoringCounted the unique PQW-* identifiers in src/waf.rs; read the severity-to-score mappingExactly 256; Info 1 / Low 3 / Medium 5 / High 8 / Critical 10
The conformance suite carries 51 anomaliesCounted unique test identifiers in src/conformance/catalog.rs; fetched /conformance/51 IDs; endpoint returns 200
MASQUE and the conformance vhost are enabled in productionRead /etc/pqcrypta/proxy-config.toml as the running process loads it[masque] enabled = true, [conformance] enabled = true
The pentest suite is 32 scripts across 12 phasesListed pentests/scripts/32 scripts, 01–32
NEL, Report-To and Server-Timing are actually emittedcurl -I https://pqcrypta.com/All three present, plus alt-svc: h3=":443", h3=":4434"

Capabilities the Config Never Surfaces

A configuration file is a poor inventory of what software does. Reading only config.rs — 367 fields across 36 structures — would have missed a whole class of behaviour that has no knob because it is not optional. These were found by reading the modules instead, and several are among the strongest entries in the chart.

Startup runtime self-verification
  • 1,228 lines in src/startup_verify.rs with no configuration surface at all.
  • Performs a real TLS 1.3 handshake against the proxy's own ServerConfig, entirely in memory — no socket, no port, so it cannot be firewalled or collide with a bound address.
  • Then probes the WAF, the rate limiter, mTLS and every bound listener.
  • Its stated rule: assert the capability, never the configuration. The hazard it closes is a real one across this whole product category — a startup banner that reads a version string off a subprocess is not reading the cryptography the server will actually serve. Measured here across three hosts loading three different libcryptos, the negotiated group was X25519MLKEM768 on all three, independent of what any of them reported at the command line. An operator reading a banner is being told the security boundary they deployed, so it had better come from the serving stack.
Correctness that is simply always on
  • Hop-by-hop header stripping before caching and forwarding — leaving these on produces ERR_QUIC_PROTOCOL_ERROR on HTTP/3.
  • RFC 9110 HEAD semantics. A HEAD response carries the header fields a GET would. A proxy that instead synthesizes content-length: 0 from its own empty buffered body tells every link checker, uptime monitor and security scanner that a dynamic page is empty — so the length is taken from the backend, on all three transports.
  • Handshake facts stripped from the request before being set, so a caller cannot assert a TLS handshake it did not have.
  • Log injection sanitisation and structural request-smuggling detection — neither has an off switch.
Evidence machinery with no operator surface
  • Verified crawler checking (crawler_verify.rs) — reverse DNS plus a forward confirmation before a declared Googlebot is treated as one.
  • The observed fingerprint corpus, persisted every five minutes and reloaded at startup. Explicitly evidence only: it never feeds classification or blocking.
  • The QPACK and 0-RTT proof harnesses, which exist because no reachable client exercises those paths and an unrun path is not a working path.
  • The impairment engine behind the telemetry wall — 1,118 lines of deliberate protocol misbehaviour with no config entry.

How Their Columns Were Sourced

Competitor values come from each project's own material: official documentation first, then release notes and vendor engineering blogs, then the issue tracker where a feature's absence is the thing being established. Where a maintainer has stated a position plainly it is quoted rather than inferred — HAProxy's blog says post-quantum signatures are step two and not yet supported; Envoy's post-quantum issue is closed as not planned pending a BoringSSL upgrade; NGINX's ModSecurity WAF reached end of life in March 2024. No competitor cell was set from a benchmark article or a third-party comparison post.

Known Limits of This Comparison

  • Breadth is not quality. The scorecard counts whether a capability exists. It says nothing about throughput, latency, memory behaviour, or how a feature holds up under an adversary. On raw performance HAProxy and NGINX have decades of evidence and we have months.
  • We graded ourselves. Our column was established from source and a live endpoint, which is a stronger basis than a description — but the person who chose which 217 rows to include is the person who wrote the software. A row that exists partly because we have it is still a row that flatters us.
  • Editions blur. Splitting NGINX and HAProxy into free and paid columns is fairer than one column each, but a large operator running Plus or Enterprise sees a different chart than the one an open-source evaluator sees.
  • Documentation lags code. A competitor cell marked absent means the project does not document it. Several of these projects move quickly, and QUIC-adjacent features in particular are shipping continuously.
  • One snapshot. Everything here reflects PQ Crypta Proxy 0.2.2 as deployed in September 2026, and each competitor at the version named in its column header.

References

  1. HAProxy Technologies. How to enable post-quantum cryptography and TLS termination with HAProxy — source for the PQC curve, edition and signature rows.
  2. HAProxy. Post-Quantum Cryptography (PQC) Support · Issue #3171.
  3. nginx. Support for QUIC and HTTP/3 — source for 0-RTT, QUIC Retry, GSO and the supported SSL libraries.
  4. nginx. Module ngx_http_acme_module; Let's Encrypt, Native ACME Support Comes to NGINX.
  5. NGINX Community. Post-Quantum Cryptography support in NGINX and Encrypted Client Hello Comes to NGINX.
  6. F5. F5 NGINX ModSecurity WAF Is Transitioning to End-of-Life — end of life March 2024.
  7. Envoy. BoringSSL upgrade for Post-Quantum Cryptography support · Issue #42893 (closed as not planned) and Support for TLS ECH · Issue #44165.
  8. Caddy. Release notes — 2.10 introduced automated ECH and x25519mlkem768; tls directive documentation lists x25519mlkem768 as the only PQC curve.
  9. Traefik. Post-Quantum Key Exchange support for HTTPS · Issue #10755; OCSP documentation.
  10. LiteSpeed. QUIC and HTTP/3 Support.
  11. IETF. draft-ietf-quic-multipath, RFC 9298 (CONNECT-UDP), RFC 9297 (HTTP Datagrams), RFC 9111 (HTTP Caching), RFC 9218 (Extensible Priorities).
  12. PQ Crypta. pqcrypta-proxy — the source tree every value in our column was read from; proxy documentation, multipath QUIC whitepaper, HTTP/3 conformance suite.