TLS

Setting up TLS termination for HTTPS and HTTP/2

2 min read 318 words

Overview

Pounce supports TLS termination using Python's stdlibssl module, with optional truststoreintegration for system certificate stores.

Basic Setup

pounce serve --app myapp:app --ssl-certfile cert.pem --ssl-keyfile key.pem

Or programmatically:

import pounce

pounce.run(
    "myapp:app",
    ssl_certfile="cert.pem",
    ssl_keyfile="key.pem",
)

Note

Bothssl_certfile and ssl_keyfile must be provided together. Setting only one raises ValueError.

Self-Signed Certificates (Development)

For local development, generate a self-signed certificate:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
    -days 365 -nodes -subj '/CN=localhost'

Then run:

pounce serve --app myapp:app --ssl-certfile cert.pem --ssl-keyfile key.pem

Your browser will warn about the self-signed certificate — this is expected in development.

ALPN and HTTP/2

When TLS is enabled andbengal-pounce[h2] is installed, Pounce advertises both h2 and http/1.1via ALPN (Application-Layer Protocol Negotiation). Clients that support HTTP/2 will automatically use it.

To force HTTP/1.1 at a Pounce-owned TLS origin while diagnosing an edge/origin HTTP/2 problem, disable h2 advertisement:

pounce serve --app myapp:app --ssl-certfile cert.pem --ssl-keyfile key.pem --no-http2

For ServerConfig or TOML, set http2_enabled = false. This setting controls only TLS terminated by Pounce; it cannot change protocol negotiation on a TLS connection terminated by a reverse proxy or platform edge.

Truststore Integration

For production, install thetruststoreextra for system certificate store integration:

uv add "bengal-pounce[tls]"

This uses the operating system's trusted CA certificates instead of certifi or a bundled CA file.

Reverse Proxy

In many production setups, TLS is terminated at a reverse proxy (nginx, Caddy, etc.) and Pounce receives plain HTTP. In this case:

  1. Don't setssl_certfile / ssl_keyfileon Pounce
  2. Setroot_pathif the proxy serves at a subpath
  3. Settrusted_hoststo your proxy's address
pounce.run(
    "myapp:app",
    root_path="/api",
    trusted_hosts=("127.0.0.1",),
)

See Also