Choosing between TLS termination and TLS pass-through is not a cosmetic proxy setting. It decides where encryption ends, which system holds session keys, whether Webship can inspect HTTP, and which layer must enforce application security.
Webship defaults to pass-through. That keeps application plaintext and active session keys at the origin. Enable termination only when the edge must understand and act on the HTTP request.
The decision in one sentence
Use TLS pass-through when the origin must own the TLS boundary. Use TLS termination when Webship must route, protect, transform, cache, or observe HTTP traffic.
Neither mode is universally more secure. Pass-through reduces the sensitive material handled by the edge, but removes the edge's HTTP security controls. Termination adds an inspectable enforcement point, but makes Webship part of the trusted TLS boundary.
| Concern | TLS termination | TLS pass-through | | --- | --- | --- | | TLS endpoint | Webship | Origin | | Application plaintext at Webship | Yes | No | | Active downstream session keys at Webship | Yes | No | | Route by HTTP path or method | Yes | No | | WAF, API Shield, and body limits at Webship | Yes | No | | Proxy cache, rewrites, and forwarding headers | Yes | No | | TCP routing input | HTTP authority and route policy | ClientHello SNI | | HTTP/3 routing | HTTP request data | One shared UDP origin | | Origin responsibility | HTTP or separately configured upstream TLS | Full TLS, ALPN, and HTTP stack |
The important question is therefore not “Which switch is faster?” It is “Which component must be allowed to see and control the request?”
What termination gives Webship
With tls_termination = true, Webship completes downstream TLS and feeds the decrypted request into its HTTP reverse-proxy pipeline. That makes the following features possible:
- path, host, and method-aware routing;
- WAF and API Shield inspection;
- request-body limits and policy timeouts;
- proxy caching and generation-safe invalidation;
- forwarding-header management and HTTP access-log fields;
- body-aware QUERY handling, retries where safe, and circuit-breaker policy;
- protocol translation between the client-facing and upstream connections.
This mode also changes the security responsibility. The Webship host must protect the certificate private key, session keys, decrypted request and response data, observability output, and any cached representation. If the next hop must remain encrypted, configure typed upstream TLS separately; otherwise the HTTP upstream is cleartext.
Termination is the right boundary when Webship is expected to behave as an application-aware edge, not only as an encrypted transport relay.
What pass-through preserves
With tls_termination = false—the default—Webship relays encrypted TLS or QUIC traffic without decrypting the HTTP request or response. Application plaintext and active session keys stay at the origin.
That smaller trust boundary is valuable when certificates must remain on the application tier, compliance policy forbids edge decryption, or an origin-specific TLS identity must reach the client unchanged. It also removes HTTP parsing and policy work from the relay path.
The trade-off is strict: Webship cannot inspect what it cannot decrypt. It cannot apply HTTP WAF rules, route by path, rewrite headers, enforce body-aware API policy, or populate HTTP-field access logs. The origin must provide all of those controls itself.
Pass-through is therefore not “termination with fewer features.” It is a different architecture with a different security owner.
Protocol-specific limits matter
For HTTP/1.1 TLS and HTTP/2 TLS, Webship inspects the ClientHello only far enough to select the configured TCP destination by SNI. Each pass-through domain needs a catch-all path_prefix = "/" route because the actual request path remains encrypted. A client without SNI is accepted only when the configuration has one domain.
The origin must negotiate the client's ALPN and support the selected protocol. Webship cannot convert an HTTP/2 client to an HTTP/1.1 origin while the TLS session passes through unchanged.
HTTP/3 uses QUIC over UDP and has a tighter boundary. Pass-through cannot safely route by encrypted HTTP authority, so every configured HTTP/3 route must resolve to the same IP-socket UDP origin. Webship rejects Unix sockets and multiple HTTP/3 pass-through origins during configuration validation rather than silently routing ambiguously.
Cleartext HTTP/1.1 and h2c are unaffected by reverse_proxy.tls_termination. The setting controls downstream HTTP/1.1 TLS, HTTP/2 TLS, and HTTP/3 TLS only.
Measured request capacity
The Webship 1.3.1 Debian capacity benchmark measured the two encrypted reverse-proxy modes separately. Every accepted sample required zero HTTP, socket, protocol, proxy, major-page-fault, and HTTP/3 packet-loss errors.
| Reverse-proxy mode | HTTP/1.1 TLS | HTTP/2 TLS | HTTP/3 TLS | | --- | ---: | ---: | ---: | | TLS termination | 123,344 RPS | 124,957 RPS | 131,529 RPS | | TLS pass-through | 203,950 RPS | 266,845 RPS | 167,010 RPS |
Small-response pass-through has less application work to perform: it relays encrypted transport data instead of terminating TLS, parsing HTTP, evaluating policy, and producing a new downstream TLS stream. The higher pass-through request rates reflect that narrower job.
These rows do not represent identical feature sets, and they should not be used to claim that one security architecture is universally better. Termination pays for HTTP-aware capabilities that pass-through intentionally cannot provide.
Bulk streaming changes the result
The same benchmark used an exact 99,943,778-byte response body for the 100 MB streaming matrix. Here, TLS termination produced higher median payload throughput for all three protocols:
| Reverse-proxy mode | HTTP/1.1 TLS | HTTP/2 TLS | HTTP/3 TLS | | --- | ---: | ---: | ---: | | TLS termination | 3,585.7 MiB/s | 3,355.0 MiB/s | 1,938.6 MiB/s | | TLS pass-through | 2,783.2 MiB/s | 2,135.0 MiB/s | 1,748.5 MiB/s |
Why does the direction change? In termination mode, the benchmark origin sends cleartext HTTP to Webship, and Webship owns the optimized downstream bulk path. Large HTTP/1.1 and HTTP/2 responses can use adaptive Linux kTLS and bounded transport-specific buffering. HTTP/3 uses QUIC pacing, DPLPMTUD, and per-reactor batching instead of kTLS.
In pass-through mode, the origin owns downstream TLS and Webship relays the resulting encrypted stream or QUIC packets. That preserves the origin TLS boundary, but it cannot use Webship's HTTP-aware bulk-response path.
The seven-sample HTTP/3 qualification also checked stability. Terminated streaming reached a 1,938.6 MiB/s median with 2.12% coefficient of variation; pass-through reached 1,748.5 MiB/s with 1.65% coefficient of variation. Both delivered the exact body with zero client, protocol, and packet-loss errors.
Configure pass-through deliberately
A minimal pass-through configuration keeps the TLS identity staged so an operator can enable termination later without changing certificate paths:
[reverse_proxy]
enabled = true
tls_termination = false
[reverse_proxy.protocols]
h1 = true
h2 = true
h3 = true
[reverse_proxy.tls]
cert = "/etc/webship/proxy-cert.pem"
key = "/etc/webship/proxy-key.pem"
[[reverse_proxy.routes]]
domain = "app.example.com"
path_prefix = "/"
upstreams = ["10.0.0.20:443"]
[[reverse_proxy.policies]]
name = "default"
path_prefixes = ["/"]
total_timeout_ms = 30000The staged Webship certificate is validated but is not used by active pass-through sessions. The origin at 10.0.0.20:443 must terminate TLS and support the client-negotiated protocol.
Enable termination when the edge needs HTTP
For an application-aware edge, enable termination and send the resulting HTTP traffic to the selected origin:
[reverse_proxy]
enabled = true
tls_termination = true
[reverse_proxy.protocols]
h1 = true
h2 = true
h3 = true
[reverse_proxy.tls]
cert = "/etc/webship/proxy-cert.pem"
key = "/etc/webship/proxy-key.pem"
[[reverse_proxy.routes]]
domain = "app.example.com"
path_prefix = "/api"
strip_path_prefix = true
upstreams = ["10.0.0.20:8080", "10.0.0.21:8080"]
[[reverse_proxy.policies]]
name = "default"
hosts = ["app.example.com"]
path_prefixes = ["/"]
max_body_bytes = 1048576
request_body_idle_timeout_ms = 5000
upstream_header_timeout_ms = 5000
response_body_idle_timeout_ms = 5000
downstream_write_idle_timeout_ms = 5000
total_timeout_ms = 30000This configuration can route and inspect HTTP. Add upstream TLS when the network between Webship and the origin is not already trusted or isolated.
Switch modes without restarting Webship
Webship can change tls_termination through a configuration-file reload or the version-checked webship.reverse_proxy.apply_config MCP tool. Read the current object and version with webship.reverse_proxy.get_config, change only the intended field in the complete returned object, and submit it with the matching expected_version_id.
New TCP connections use the new mode. HTTP/3 clients reconnect to the replaced UDP transport. Certificate and key path changes remain process-bound and require a restart, so keep a valid termination identity staged before a live switch.
Version checking prevents one operator from overwriting a concurrent configuration change. A rejected update leaves the active runtime and persisted configuration unchanged.
A practical selection checklist
Choose pass-through when all of these are true:
- The origin must retain the certificate boundary and session keys.
- SNI-level TCP routing—or one shared HTTP/3 UDP origin—is sufficient.
- The origin provides the necessary WAF, authorization, logging, body limits, and abuse controls.
- No edge cache, path rewrite, forwarding-header policy, or HTTP protocol translation is required.
Choose termination when any of these are required at Webship:
- Route by host, path, or method.
- Inspect requests with WAF or API Shield.
- Enforce body limits, HTTP timeouts, or edge authentication.
- Cache responses or rewrite HTTP headers.
- Translate between downstream and upstream HTTP protocols.
- Observe HTTP fields at the proxy boundary.
Whichever mode you select, test SNI, ALPN, certificate identity, client cancellation, upstream half-close, and exact response integrity. Measure request capacity and streaming throughput separately: the fastest mode for a small response is not necessarily the fastest mode for a 100 MB body.
Webship makes pass-through the default because a proxy should not silently widen its trust boundary. Termination remains a live, explicit operational choice when HTTP-aware edge behavior is worth that responsibility.
Read the full [reverse-proxy documentation](/docs/1.3.1), compare the accepted [benchmark matrix](/benchmarks), or download Webship from [Downloads](/downloads).
Sources and content method
Performance values are accepted medians from the Webship 1.3.1 unified Debian capacity benchmark dated September 11, 2026; its acceptance gates require zero client, HTTP, socket, protocol, proxy, major-page-fault, and HTTP/3 packet-loss errors.