Troubleshooting HTTPS is difficult because TLS hides the exact bytes that developers often need to inspect. Python’s SSLContext.keylog_filename attribute provides a controlled way to record session secrets in the NSS Key Log format. Wireshark can combine those secrets with a packet capture and decrypt authorized TLS sessions.
The feature does not turn HTTPS into plain HTTP, disable certificate checks, or modify traffic on the wire. Packets remain encrypted. Decryption is possible only for an analyst who has both the matching capture and the key log file. This makes the feature valuable for development, integration testing, API debugging, protocol analysis, and diagnosing TLS interoperability problems.
What keylog_filename does
keylog_filename belongs to an ssl.SSLContext. When you assign a writable path before the handshake, Python appends TLS secrets to that file. The format is understood by browsers and network tools. Depending on the negotiated TLS version, the log may contain CLIENT_RANDOM records or TLS 1.3 traffic-secret labels.
Support depends on the OpenSSL library used by the Python build. Modern installations commonly support it on Linux, macOS, and Windows, but production code should not assume availability without checking the target environment.
Basic urllib example
import ssl
import urllib.request
context = ssl.create_default_context()
context.keylog_filename = "tls-keys.log"
with urllib.request.urlopen(
"https://www.python.org/",
context=context,
timeout=10,
) as response:
print(response.status)
print(response.read(200))
The default context keeps hostname verification and certificate validation enabled. The only additional behavior is writing session secrets. Start a packet capture before running the script, then configure Wireshark to read the generated file.
Configure Wireshark
Open Wireshark preferences, find the TLS protocol settings, and set the key log filename to the absolute path of tls-keys.log. Reload the capture or start a new one. Filters such as tls, http2, and http help locate decrypted application data.
The official Python ssl documentation describes the context API. The Wireshark TLS guide explains key-log configuration and common capture limitations.
Raw socket example
import socket
import ssl
context = ssl.create_default_context()
context.keylog_filename = "session-secrets.log"
with socket.create_connection(("www.python.org", 443), timeout=10) as raw:
with context.wrap_socket(raw, server_hostname="www.python.org") as secure:
secure.sendall(
b"GET / HTTP/1.1\r\nHost: www.python.org\r\nConnection: close\r\n\r\n"
)
data = secure.recv(4096)
print(data.decode("latin-1", errors="replace"))
Set the filename before wrap_socket performs the handshake. Enabling it afterward cannot reconstruct secrets for an already negotiated session.
SSLKEYLOGFILE environment variable
Some applications honor the SSLKEYLOGFILE environment variable. Python-created default contexts may use it in supported situations. Explicit configuration is usually clearer in tests because it documents intent and avoids relying on global process state.
export SSLKEYLOGFILE="$PWD/tls-keys.log"
python client.py
For temporary diagnostic files, use a protected directory and delete the file after the test. The Academify guide to Python tempfile covers temporary-file lifecycles, while Python pathlib helps manage paths reliably.
Treat the file as a secret
A TLS key log is highly sensitive. Anyone who obtains the matching capture and key log may decrypt recorded sessions. Never commit it to Git, attach it to a public issue, or upload it to an untrusted support portal. Add patterns such as *.keylog, tls-keys.log, and session-secrets.log to .gitignore.
Avoid enabling the feature in production. Long-running services can generate large files containing secrets for many users. This creates disclosure, retention, disk-space, and concurrency risks. Restrict file permissions to the service account and keep the diagnostic window short.
A safer helper
from pathlib import Path
import ssl
def create_debug_context(path: Path, enabled: bool = False) -> ssl.SSLContext:
context = ssl.create_default_context()
if enabled:
path.parent.mkdir(parents=True, exist_ok=True)
context.keylog_filename = str(path)
return context
context = create_debug_context(
Path(".debug") / "tls-keys.log",
enabled=True,
)
An explicit flag reduces accidental activation. In larger systems, connect the flag to a local-only setting and reject it during production startup.
Using httpx
import ssl
import httpx
context = ssl.create_default_context()
context.keylog_filename = "httpx-tls.log"
with httpx.Client(verify=context, timeout=10) as client:
response = client.get("https://www.python.org/")
print(response.status_code)
Some HTTP clients accept an SSLContext directly; others require a custom transport or adapter. Review the Academify tutorials on urllib.request and Python requests to distinguish application, DNS, TCP, certificate, and protocol failures.
Common problems
An empty file often means the path was not writable, no new handshake occurred, or the connection pool reused an existing TLS session. Close the client, disable pooling for the test, and force a fresh connection. A packet capture from the wrong network interface is another common cause, especially with containers, VPNs, virtual machines, and WSL.
Old key logs cannot decrypt new sessions, and new key logs cannot decrypt earlier captures unless the matching session secrets were recorded. The capture and key file must correspond to the same handshakes.
TLS 1.3 and HTTP/2
TLS 1.3 uses multiple traffic secrets, which the NSS format represents with dedicated labels. Recent Wireshark versions understand those labels. After TLS decryption, Wireshark still needs to decode the application protocol. Many HTTPS APIs negotiate HTTP/2 through ALPN, so decrypted traffic may appear as HTTP/2 frames rather than familiar HTTP/1.1 text.
Responsible use
Use this capability only on systems, accounts, and networks you are authorized to inspect. It is appropriate for your own services, test environments, staging systems, and approved incident response. It is not appropriate for intercepting third-party traffic, collecting credentials, or bypassing organizational controls.
Practical checklist
- Keep certificate verification enabled.
- Set the path before the TLS handshake.
- Use an absolute path in Wireshark.
- Capture the correct network interface.
- Force a fresh connection when necessary.
- Protect the file with restrictive permissions.
- Delete the key log after diagnosis.
- Never commit it to source control.
Conclusion
SSLContext.keylog_filename is one of the most effective Python tools for authorized TLS troubleshooting. It preserves normal encryption and validation while giving Wireshark the secrets needed to inspect a matching capture. Used with a dedicated context, strict file protection, and a short diagnostic window, it can reveal HTTP headers, redirects, ALPN negotiation, HTTP/2 frames, and API behavior that would otherwise remain hidden.







