Skip to content

feat: HTTP/2 by default for NetScript services (feasibility + rollout) #234

Description

@rickylabs

Summary

Investigate and roll out HTTP/2 by default for NetScript services. HTTP/2 is largely "free" at the protocol layer — Deno's runtime already speaks it — but making it the default is gated almost entirely by TLS provisioning in local dev, because browsers only negotiate HTTP/2 over TLS (ALPN). This issue captures the feasibility verdict, the concrete requirements, a phased rollout, and the open questions.

Motivation

Current state (grounded)

  • packages/service/src/builder/service-listener.ts starts a plain Deno.serve({ port, signal, onListen })no cert/key, and the startup banner hardcodes http://${hostname}:${port}. The file docstring already anticipates this: "Kept separate from the builder class so the listener concern can evolve (e.g. TLS, clustering)…".
  • The SDK client (packages/sdk/src/client/http-client-link.ts / service-client.ts) and the tutorial's OpenAPILink/RPCLink are built on fetch. Deno's fetch already negotiates HTTP/2 automatically over TLS — no client code change is needed for the happy path, only trust of the dev cert.
  • So the runtime pieces are present; the gap is TLS wiring + dev-cert trust + Aspire scheme, not a new HTTP/2 implementation.

Feasibility verdict

Feasible with no new dependency. Deno.serve serves HTTP/2 automatically when given a TLS cert/key and the client negotiates h2 via ALPN (Deno.serve({ cert, key, ... })). The work is plumbing and dev-ergonomics, not protocol implementation.

Key constraint: browsers do not support h2c (cleartext HTTP/2). So "h2 by default" for a browser-facing service necessarily means "TLS by default in dev." That TLS-in-dev requirement is the real cost of this issue.

Requirements

  1. Dev TLS certificate + local trust (the hard part). Browsers reject untrusted certs, so the generated dev experience needs a trusted localhost cert. Options to evaluate:
    • Lean on Aspire dev-certs (dotnet dev-certs https --trust) — Aspire already provisions/trusts a localhost cert for its own HTTPS endpoints; reuse it for NetScript service endpoints.
    • mkcert-style locally-trusted CA (extra install step).
    • Self-signed + explicit trust env for non-browser clients only (DENO_CERT / NODE_EXTRA_CA_CERTS) — insufficient for browsers.
    • Cross-platform trust friction (Windows cert store vs. macOS keychain vs. linux) is the dominant UX risk.
  2. Service listener TLS support. Extend ServeOptions with an optional tls: { cert, key } (or certFile/keyFile), branch startServiceListener to pass them to Deno.serve, and flip the onListen banner to https:// when TLS is active. Keep plain HTTP as a fallback (opt-out / no-cert path).
  3. Aspire AppHost scheme. Generated AppHost endpoints, service-discovery URLs, and health-check probes must flip httphttps when services serve TLS. (Note: the Aspire dashboard URL was already corrected to https in the docs; this is about the service endpoints.)
  4. Client / SDK trust. fetch gets h2 for free over TLS, but Deno must trust the dev cert (DENO_CERT, --cert, or the OS trust store via Aspire dev-certs). Verify OpenAPILink/RPCLink and generated typed clients work end-to-end over h2.
  5. Fresh / Vite dev server. Separate listener from the service. Vite's dev server + HMR over HTTPS/h2 has its own config (server.https); confirm HMR still works. Decide whether the web layer also goes TLS-by-default or stays HTTP in dev while only backend services go h2.
  6. Production. Essentially free: TLS typically terminates at the ingress/proxy in an Aspire-published deployment, which already speaks h2 to browsers. Internal service-to-service h2 is optional and can be a later phase.

Proposed phased rollout

Risks / open questions

Non-goals

  • HTTP/3 / QUIC (separate, larger effort).
  • Rewriting the client transport — fetch already handles h2.

Filed out of the alpha.18 docs-conformance work (the streams HTTP/1.1 ~6-connection caveat is the motivating case). Tracked standalone rather than folded into docs. Related: #218, #231, #215, docs umbrella #232.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions