Cache certificate setup
Choose a cache-mode TLS option#
No
_cache-password suffix? Change nothing. Ordinary proxy mode keeps end-to-end TLS and requires no certificate installation or client TLS changes for the plaintexthttp://proxy endpoint. Thehttps://proxy endpoint is the one exception: its hub certificate chains to this same root, so trust it for the proxy connection as described in HTTP vs HTTPS proxy endpoint. That trust alone never enables cache mode.
With cache mode active, choose one:
| Option | Certificate verification | Best for |
|---|---|---|
| Trust the Litport root (Recommended) | On | Ongoing cache clients and dedicated automation profiles |
| Skip certificate verification | Off | Isolated public-data automation where you accept the security tradeoff |
Skipping verification means the client cannot authenticate target certificates. Never use that option for logins, payments, private APIs, cookies, or sensitive traffic.
The proxy URL may begin with http:// because it identifies the HTTP proxy endpoint. The target
still remains https://example.com/...; proxy endpoint scheme and target scheme are different.
Skip verification for isolated public-data automation#
Use this option only in a dedicated cache client that fetches public static data. It disables the client's target-certificate authentication; it does not make private traffic safe to intercept. Keep the proxy credentials in a secret store and remove the cache suffix when the isolated workload ends.
curl#
curl --insecure --proxy 'http://hub-us-7.litport.net:PORT' \
--proxy-user 'USER:PASSWORD_cache-scripts' \
'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js'
Python Requests#
import requests
requests.get(
'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js',
proxies={'https': 'http://USER:[email protected]:PORT'},
verify=False,
timeout=30,
)
Node#
NODE_TLS_REJECT_UNAUTHORIZED=0 node scraper.mjs
Configure the HTTP proxy in that isolated Node process. This environment setting disables certificate verification for that process; do not set it for a general-purpose service.
Browser automation#
import { chromium } from 'playwright'
const browser = await chromium.launch({ proxy: {
server: 'http://hub-us-7.litport.net:PORT',
username: 'USER',
password: 'PASSWORD_cache-scripts',
}})
const context = await browser.newContext({ ignoreHTTPSErrors: true })
await (await context.newPage()).goto('https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js')
Use a dedicated browser profile for this workload. Do not browse signed-in or sensitive sites with it.
Go#
proxyURL, err := url.Parse("http://USER:[email protected]:PORT")
if err != nil { log.Fatal(err) }
client := &http.Client{Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // public-data-only isolated client
}}
response, err := client.Get("https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js")
Trust Litport root (Recommended)#
Two verified TLS legs#
Cache mode terminates the client-facing TLS connection at the selected Litport hub so it can read an eligible response and serve a later local copy. The client verifies the issued target certificate against the Litport cache root. Separately, the hub verifies the real origin certificate and hostname before reading the origin response. Keep verification enabled at both trust boundaries.
An HTTP target has no authenticated origin identity and stays on the ordinary proxy path. Use an HTTPS target for cache mode.
Published root identity#
Download: https://litport.net/certificates/litport-cache-root.crt
Machine-readable identity (optional): litport-cache-root.json
| Field | Value |
|---|---|
| Subject | O=Litport, CN=Litport cache root CA |
| Issuer | O=Litport, CN=Litport cache root CA |
| PEM format | PEM-encoded X.509 certificate |
| Valid from (UTC) | 2026-09-08T18:54:30.000Z |
| Valid to (UTC) | 2036-09-08T18:59:30.000Z |
| X.509 SHA-256 fingerprint | 6E:0D:49:97:67:B0:D5:E3:41:E3:C7:B8:CC:65:85:C2:FD:04:EE:64:E7:64:E8:5A:79:18:27:F6:DD:1E:FD:38 |
| Downloaded PEM file SHA-256 | b5a687754f15ab2fe7a00fc77738bc8f9e608e890159e4eccf5cbd48a46a9b7a |
The fingerprint hashes the certificate's DER representation. The file checksum hashes the downloaded PEM bytes, including textual encoding and line endings, so these SHA-256 values differ.
curl --fail --remote-name https://litport.net/certificates/litport-cache-root.crt
openssl x509 -in litport-cache-root.crt -noout -subject -issuer -dates -fingerprint -sha256
sha256sum litport-cache-root.crt
The download contains public certificate material, never a private key. One root works for every selected hub. A hub switch can cause a cache miss because entries are hub-local; it does not require a new root.
What installing the root permits#
The public root allows your client to validate target certificates issued by Litport's cache CA
hierarchy. The same root also validates the certificate a hub presents on its https:// proxy
endpoint; see HTTP vs HTTPS proxy endpoint. Litport keeps the root private key offline; it is not deployed to hubs. Each hub receives
its own intermediate certificate and private key, so the root key is not exposed if one hub is
compromised.
For a cache-enabled connection, the selected hub can read the HTTPS request and response. Installing
the root system-wide also makes every application using that system store accept certificates issued
by the Litport cache hierarchy. Scope trust to the cache client or its dedicated container, use cache
mode only for public static data, and remove the root when the workload no longer needs it. Without a
valid _cache- suffix, Litport keeps the HTTPS tunnel opaque even if the root remains installed.
Client setup#
Prefer per-process, per-profile, or dedicated-container trust. System trust is broad: all applications
using that store can trust certificates issued by this root. Replace USER, PASSWORD, and
PORT; percent-encode reserved URL characters and never commit proxy secrets.
curl
curl --proxy 'http://hub-us-7.litport.net:PORT' \
--proxy-user 'USER:PASSWORD_cache-scripts' \
--cacert ./litport-cache-root.crt \
'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js'Python
import requests
requests.get(
"https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js",
proxies={"https": "http://USER:[email protected]:PORT"},
verify="litport-cache-root.crt",
timeout=30,
)Node
NODE_EXTRA_CA_CERTS=./litport-cache-root.crt node scraper.js
// Configure the Litport HTTP proxy in your Node client.
// Keep rejectUnauthorized at its default true.Browser automation
// Trust litport-cache-root.crt in the isolated browser/profile
// trust store actually used by the automation browser.
// Keep ignoreHTTPSErrors: false.
// Do not use --ignore-certificate-errors.Go
pool, _ := x509.SystemCertPool()
pem, _ := os.ReadFile("litport-cache-root.crt")
pool.AppendCertsFromPEM(pem)
transport := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{RootCAs: pool, MinVersion: tls.VersionTLS12},
}Java
keytool -importcert -alias litport-cache \
-file litport-cache-root.crt \
-keystore ./litport-cache-truststore.p12 \
-storetype PKCS12
java -Djavax.net.ssl.trustStore=./litport-cache-truststore.p12 AppAndroid
<network-security-config>
<base-config>
<trust-anchors><certificates src="system" /></trust-anchors>
</base-config>
<debug-overrides>
<trust-anchors>
<certificates src="@raw/litport_cache_root" />
</trust-anchors>
</debug-overrides>
</network-security-config>iPhone / iPad
1. Install the Litport root profile.
2. Open Settings → General → About → Certificate Trust Settings.
3. Enable full trust for the Litport root.
4. Remove the profile when cache-mode testing is finished.curl#
--cacert replaces curl's default CA bundle for this request. Combine required roots in a dedicated
bundle if the target needs another private CA.
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-scripts' \
--cacert ./litport-cache-root.crt --verbose \
'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js'
Python Requests, httpx, and aiohttp#
Requests' verify file replaces its default bundle. For httpx and aiohttp, create the default
context first, then call load_verify_locations() to append this root to the system roots.
import asyncio, ssl
import aiohttp, httpx, requests
proxy = 'http://USER:[email protected]:PORT'
url = 'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js'
requests.get(url, proxies={'https': proxy}, verify='litport-cache-root.crt', timeout=30)
context = ssl.create_default_context()
context.load_verify_locations(cafile='litport-cache-root.crt')
httpx.get(url, proxy=proxy, verify=context, timeout=30)
async def fetch():
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=context)) as session:
async with session.get(url, proxy=proxy) as response: return await response.read()
asyncio.run(fetch())
Node HTTPS clients#
NODE_EXTRA_CA_CERTS appends roots to Node. A real HTTPS proxy agent routes traffic; keep
rejectUnauthorized at its default true.
npm install https-proxy-agent
NODE_EXTRA_CA_CERTS=./litport-cache-root.crt node scraper.mjs
import https from 'node:https'
import { HttpsProxyAgent } from 'https-proxy-agent'
const agent = new HttpsProxyAgent('http://USER:[email protected]:PORT')
https.get('https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js', { agent }, response => response.resume())
This setting does not configure Chromium, Playwright, or Puppeteer traffic.
Browser automation#
Install the root in the isolated browser profile's OS or NSS store. Keep
ignoreHTTPSErrors: false and do not use --ignore-certificate-errors.
import { chromium } from 'playwright'
const browser = await chromium.launch({ proxy: {
server: 'http://hub-us-7.litport.net:PORT', username: 'USER', password: 'PASSWORD_cache-scripts',
}})
const context = await browser.newContext({ ignoreHTTPSErrors: false })
await (await context.newPage()).goto('https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js')
Go#
pool, err := x509.SystemCertPool()
if err != nil || pool == nil { pool = x509.NewCertPool() }
pem, err := os.ReadFile("litport-cache-root.crt")
if err != nil || !pool.AppendCertsFromPEM(pem) { log.Fatal("could not add Litport root") }
proxyURL, err := url.Parse("http://USER:[email protected]:PORT")
if err != nil { log.Fatal(err) }
client := &http.Client{Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{RootCAs: pool, MinVersion: tls.VersionTLS12},
}}
response, err := client.Get("https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js")
SystemCertPool plus AppendCertsFromPEM preserves system roots and appends this root.
Java#
A dedicated truststore is process-scoped, but replaces Java's default bundle. Import other required roots into that dedicated store.
keytool -importcert -noprompt -alias litport-cache -file litport-cache-root.crt \
-keystore ./litport-cache-truststore.p12 -storetype PKCS12 -storepass changeit
java -Djavax.net.ssl.trustStore=./litport-cache-truststore.p12 \
-Djavax.net.ssl.trustStoreType=PKCS12 -Djavax.net.ssl.trustStorePassword=changeit App
Install and remove from broad trust stores#
Use these only when process/profile trust is unavailable; they affect other applications too.
Debian and Ubuntu#
sudo install -m 0644 litport-cache-root.crt /usr/local/share/ca-certificates/litport-cache-root.crt
sudo update-ca-certificates
# Remove: sudo rm /usr/local/share/ca-certificates/litport-cache-root.crt && sudo update-ca-certificates
RHEL and Fedora#
sudo install -m 0644 litport-cache-root.crt /etc/pki/ca-trust/source/anchors/litport-cache-root.crt
sudo update-ca-trust extract
# Remove: sudo rm /etc/pki/ca-trust/source/anchors/litport-cache-root.crt && sudo update-ca-trust extract
macOS#
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain litport-cache-root.crt
# Remove: sudo security delete-certificate -c 'Litport cache root CA' /Library/Keychains/System.keychain
Windows#
Run in elevated PowerShell:
certutil -addstore -f Root .\litport-cache-root.crt
# Remove: certutil -delstore Root "Litport cache root CA"
Firefox and NSS#
Set FIREFOX_PROFILE to the profile directory with cert9.db; on Debian/Ubuntu install
libnss3-tools first.
certutil -A -n 'Litport cache root' -t 'C,,' -i litport-cache-root.crt -d "sql:$FIREFOX_PROFILE"
# Remove: certutil -D -n 'Litport cache root' -d "sql:$FIREFOX_PROFILE"
Containers and Kubernetes#
Use a dedicated workload image or read-only runtime mount instead of host trust. For Node:
COPY litport-cache-root.crt /opt/litport/litport-cache-root.crt
ENV NODE_EXTRA_CA_CERTS=/opt/litport/litport-cache-root.crt
A distro system-store update trusts every process in the container. For Kubernetes, create a ConfigMap from the downloaded public PEM, then mount it only into the workload requiring cache mode:
kubectl create configmap litport-cache-root --from-file=litport-cache-root.crt
# Pod template fragment
spec:
containers:
- name: client
env:
- name: NODE_EXTRA_CA_CERTS
value: /var/run/litport-ca/litport-cache-root.crt
volumeMounts:
- { name: litport-cache-root, mountPath: /var/run/litport-ca, readOnly: true }
volumes:
- name: litport-cache-root
configMap: { name: litport-cache-root }
Android#
Android 7.0+ apps normally do not trust user-added CAs. A bundled CA is narrow: include this PEM in
the debug build and trust only it. src="user" trusts every user-installed CA and is broader than
most production apps should accept. Android documents these trust sources and debug overrides in
Network Security Configuration.
<!-- AndroidManifest.xml -->
<application android:networkSecurityConfig="@xml/network_security_config" />
The release build keeps its normal system roots:
<!-- src/main/res/xml/network_security_config.xml -->
<network-security-config><base-config><trust-anchors><certificates src="system" /></trust-anchors></base-config></network-security-config>
The debug build appends the bundled Litport root:
<!-- src/debug/res/xml/network_security_config.xml -->
<network-security-config>
<base-config><trust-anchors><certificates src="system" /></trust-anchors></base-config>
<debug-overrides><trust-anchors><certificates src="@raw/litport_cache_root" /></trust-anchors></debug-overrides>
</network-security-config>
Place the PEM at src/debug/res/raw/litport_cache_root.pem.
A third-party app whose trust policy cannot change is incompatible with verified cache mode; remove
the _cache- suffix.
iPhone and iPad#
Install the downloaded root profile, then complete installation in Settings → General → VPN & Device Management. In Settings → General → About → Certificate Trust Settings, enable full trust for the Litport root. Remove it through VPN & Device Management → profile → Remove Profile. Managed devices should install and remove the same payload through MDM. An app with its own policy or certificate pinning can still reject the connection. Apple documents the separate full-trust step in Trust manually installed certificate profiles.
Verify the configuration#
- Make a no-suffix control request: it needs no root and uses ordinary proxy behavior.
- Make the same HTTPS request with a valid cache-enabled password and verification enabled.
- Repeat that identical request to the same hub. Inspect cache statistics for a miss then a hit; do not assume proprietary cache headers.
- Add
--verboseto the verified curl request and confirm that certificate verification succeeds and the displayed issuer belongs to the Litport cache hierarchy. - A hub switch can miss because entries are hub-local; it does not require a new root.
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-scripts' \
--cacert ./litport-cache-root.crt --verbose --output /dev/null \
'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js'
Focused certificate symptoms#
| Symptom | Cause | Fix |
|---|---|---|
unknown authority, unable to get local issuer, or CERTIFICATE_VERIFY_FAILED |
Caller does not trust the root. | Add it to that process, profile, container, or store; keep verification enabled. |
| curl works, application fails | curl's CA setting is scoped to curl. | Configure the application's own trust bundle, preserving needed roots. |
| Browser error | Browser/profile uses another store. | Install in its actual OS/NSS profile store; retain browser verification. |
| Pinned app fails | Pinning rejects the issued target certificate. | Only its owner can alter pins; use ordinary mode. |
| HTTP target | No authenticated origin TLS leg. | Use an HTTPS target, not merely an HTTP proxy endpoint. |
Rotation and credential safety#
During rotation, verify the new PEM's published fingerprint and file checksum, trust both roots for
the stated overlap, test cache mode, then remove the old root from every dedicated bundle, browser
profile, image, and managed-device payload after overlap. Use quoted proxy URLs and --proxy-user
where available; use a secret store or injected environment variable, percent-encode reserved URL
characters, and never commit proxy secrets or password-bearing command history.
Return to the cache quickstart or options and troubleshooting.