GitHub
Overview

What is Certstream?

Real-time Certificate Transparency log aggregation.

The idea

Certstream aggregates certificates from Certificate Transparency logs and streams them in real-time. This Rust implementation is a drop-in replacement for certstream-server (Elixir) and certstream-server-go.

How it stays lean

  • Pre-serialized broadcast via Arc<PreSerializedMessage> with zero-copy Utf8Bytes text frames — no per-subscriber re-encoding
  • Idle-server guard — JSON is skipped entirely when no clients are connected
  • A single shared issuer cache across all static-CT watchers
  • SIMD-accelerated JSON via simd-json, enabled by default
  • Single binary, no runtime dependencies
Message format

certificate_update

JSON structure for certificate update messages.

Two timestamps appear in each message: seen is the wall-clock time this server processed the entry, while submission_timestamp is the moment the CT log itself accepted the certificate and issued a Signed Certificate Timestamp (SCT) — as defined by RFC 6962 §3.1. Both are Unix timestamps (seconds since epoch, with millisecond precision).

JSON certificate_update
{
  "message_type": "certificate_update",
  "data": {
    "update_type": "X509LogEntry",
    "leaf_cert": {
      "subject": {
        "CN": "example.com",
        "O": "Example Inc",
        "C": "US",
        "aggregated": "/C=US/CN=example.com/O=Example Inc"
      },
      "issuer": {
        "CN": "R3",
        "O": "Let's Encrypt",
        "aggregated": "/CN=R3/O=Let's Encrypt"
      },
      "serial_number": "048A3F...",
      "not_before": 1703721600,
      "not_after": 1735257600,
      "fingerprint": "AB:CD:EF:01:...",
      "sha1": "AB:CD:EF:01:...",
      "sha256": "AB:CD:EF:01:...",
      "signature_algorithm": "sha256, rsa",
      "is_ca": false,
      "all_domains": [
        "example.com",
        "www.example.com"
      ],
      "extensions": {
        "keyUsage": "Digital Signature, Key Encipherment",
        "extendedKeyUsage": "serverAuth, clientAuth",
        "basicConstraints": "CA:FALSE",
        "subjectAltName": "DNS:example.com, DNS:www.example.com"
      },
      "as_der": "BASE64..."  // full-stream only
    },
    "chain": [...],  // full-stream only
    "cert_index": 1234567890,
    "seen": 1703808000.123,
    "submission_timestamp": 1703721600.456,  // when the CT log accepted this cert (RFC 6962 §3.1)
    "source": {
      "url": "ct.googleapis.com/logs/argon2025",
      "name": "Google Argon 2025"
    }
  }
}
Message format

dns_entries

The /domains-only WebSocket and /sse?stream=domains endpoints use a distinct schema.

JSON domains-only stream
{
  "message_type": "dns_entries",
  "data": [
    "example.com",
    "www.example.com",
    "*.example.com"
  ]
}

Unlike the full and lite streams, message_type is "dns_entries" (not "certificate_update"), and data is a bare JSON array of strings — not an object with nested fields. Use this stream when you only need domain names and want minimal bandwidth.

Stream types

Choose the right stream

Three output formats, one for each level of detail.

Lite — default

Certificate metadata, domains, issuer info, and timestamps. No DER-encoded certificate or chain. Best for most monitoring use cases.

Full

Everything in the lite stream plus the base64-encoded DER certificate and full chain. Use when you need to verify or store complete certificates.

Domains only

Just the domain names — the lowest-bandwidth option. Note the schema differs: message_type is "dns_entries" and data is a bare array of strings.

Endpoints

WebSocket, SSE & HTTP

Connect over your transport of choice.

WebSocket

EndpointDescription
ws://host:8080/Lite stream (no DER / chain)
ws://host:8080/full-streamFull data with DER and chain
ws://host:8080/domains-onlyDomain names only (message_type: "dns_entries")

SSE

EndpointDescription
http://host:8080/sseLite (default)
http://host:8080/sse?stream=fullFull
http://host:8080/sse?stream=domainsDomains only

HTTP

EndpointDescription
/healthBasic health check (returns "OK")
/health/deepDetailed health: log status, connections, uptime (JSON)
/metricsPrometheus metrics
/example.jsonExample message

REST API — opt-in

Enable with CERTSTREAM_API_ENABLED=true.

EndpointDescription
GET /api/statsServer statistics (uptime, connections, throughput, cache)
GET /api/logsCT log health status (healthy / degraded / unhealthy)
GET /api/cert/{hash}Lookup certificate by SHA256, SHA1, or fingerprint
Client examples

Connect from any language

Pick your stack and start consuming the stream.

Python certstream
# pip install certstream
import certstream

def callback(message, context):
    if message['message_type'] == 'certificate_update':
        domains = message['data']['leaf_cert']['all_domains']
        print(domains)

certstream.listen_for_events(callback, url='ws://localhost:8080/')
Go certstream-go
import "github.com/CaliDog/certstream-go"

stream, _ := certstream.CertStreamEventStream(false)
for event := range stream {
    fmt.Println(event.Data.LeafCert.AllDomains)
}
JavaScript Node.js
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8080/');

ws.on('message', (data) => {
    const msg = JSON.parse(data);
    if (msg.message_type === 'certificate_update') {
        console.log(msg.data.leaf_cert.all_domains);
    }
});
Bash with auth
# WebSocket with token
wscat -c ws://localhost:8080/ -H "Authorization: Bearer your-token"

# SSE with token
curl -H "Authorization: Bearer your-token" http://localhost:8080/sse
Self-hosting

Run your own instance

Docker, Docker Compose, or a build from source.

Docker recommended
# Quick start
docker run -d -p 8080:8080 \
  ghcr.io/reloading01/certstream-server-rust:latest

# With custom config
docker run -d -p 8080:8080 \
  -v ./config.yaml:/app/config.yaml \
  -v ./state:/app/state \
  ghcr.io/reloading01/certstream-server-rust:latest
Build from source
# Cargo build
cargo build --release
./target/release/certstream-server-rust

# Docker Compose
docker compose up -d
YAML docker-compose.yml
services:
  certstream:
    image: ghcr.io/reloading01/certstream-server-rust:latest
    ports:
      - "8080:8080"
    volumes:
      - ./config.yaml:/app/config.yaml
      - ./state:/app/state
    restart: unless-stopped
Configuration

Environment variables

Every setting can be driven by an environment variable.

General

VariableDefaultDescription
CERTSTREAM_HOST0.0.0.0Bind address
CERTSTREAM_PORT8080HTTP / WebSocket port
CERTSTREAM_LOG_LEVELinfodebug, info, warn, error
CERTSTREAM_BUFFER_SIZE1000Broadcast buffer

Protocols

VariableDefaultDescription
CERTSTREAM_WS_ENABLEDtrueEnable WebSocket
CERTSTREAM_SSE_ENABLEDtrueEnable SSE
CERTSTREAM_METRICS_ENABLEDtrueEnable /metrics endpoint
CERTSTREAM_HEALTH_ENABLEDtrueEnable /health endpoint
CERTSTREAM_EXAMPLE_JSON_ENABLEDtrueEnable /example.json endpoint
CERTSTREAM_API_ENABLEDfalseEnable REST API endpoints

Stream types

VariableDefaultDescription
CERTSTREAM_STREAM_FULL_ENABLEDtrueFull stream (DER + chain)
CERTSTREAM_STREAM_LITE_ENABLEDtrueLite stream
CERTSTREAM_STREAM_DOMAINS_ONLY_ENABLEDtrueDomains-only stream

Disabling a stream type removes its route and skips JSON serialization entirely, saving CPU and outbound bandwidth.

Connection limiting

VariableDefaultDescription
CERTSTREAM_CONNECTION_LIMIT_ENABLEDfalseEnable connection limits
CERTSTREAM_CONNECTION_LIMIT_MAX_CONNECTIONS10000Max total connections
CERTSTREAM_CONNECTION_LIMIT_PER_IP_LIMIT100Max per IP

Authentication

VariableDefaultDescription
CERTSTREAM_AUTH_ENABLEDfalseEnable token auth
CERTSTREAM_AUTH_TOKENSComma-separated tokens
CERTSTREAM_AUTH_HEADER_NAMEAuthorizationAuth header

Rate limiting

VariableDefaultDescription
CERTSTREAM_RATE_LIMIT_ENABLEDfalseEnable per-IP rate limiting (token bucket + sliding window)

CT log settings

VariableDefaultDescription
CERTSTREAM_CT_LOG_STATE_FILEcertstream_state.jsonState file path
CERTSTREAM_CT_LOG_RETRY_MAX_ATTEMPTS3Max retry attempts
CERTSTREAM_CT_LOG_REQUEST_TIMEOUT_SECS30Request timeout
CERTSTREAM_CT_LOG_BATCH_SIZE256Entries per batch
CERTSTREAM_DEDUP_CAPACITY200000Cross-log dedup capacity
CERTSTREAM_DEDUP_TTL_SECS900Dedup window (seconds)

Hot reload

VariableDefaultDescription
CERTSTREAM_HOT_RELOAD_ENABLEDfalseEnable hot reload
CERTSTREAM_HOT_RELOAD_WATCH_PATHConfig file to watch
Configuration

YAML config file

A full example covering every section.

YAML config.yaml
host: "0.0.0.0"
port: 8080
log_level: "info"
buffer_size: 1000

protocols:
  websocket: true
  sse: true
  metrics: true
  health: true
  example_json: true
  api: false

streams:
  full: true
  lite: true
  domains_only: true

ct_log:
  state_file: "/data/state.json"
  batch_size: 256
  poll_interval_ms: 500
  retry_max_attempts: 3
  request_timeout_secs: 30

dedup:
  capacity: 200000
  ttl_secs: 900

connection_limit:
  enabled: true
  max_connections: 10000
  per_ip_limit: 100

auth:
  enabled: false
  tokens:
    - "secret-token-1"
  header_name: "Authorization"

rate_limit:
  enabled: false
  max_tokens: 100
  refill_rate: 10

hot_reload:
  enabled: true

# Static CT logs (static-ct-api protocol).
# Use the monitoring prefix (mon.*) for read access.
# Trusted logs are also auto-discovered from the Google + Apple log lists.
static_logs:
  - name: "Let's Encrypt 'Willow' 2026h1"
    url: "https://mon.willow.ct.letsencrypt.org/2026h1/"
  - name: "Let's Encrypt 'Sycamore' 2026h1"
    url: "https://mon.sycamore.ct.letsencrypt.org/2026h1/"

Config search order: CERTSTREAM_CONFIG env var → ./config.yaml./config.yml/etc/certstream/config.yaml

Performance

What to expect under load

Default config, 100 concurrent WebSocket clients on the lite stream, 10-minute plateau window.

~118MiB
Stable RSS · 100 clients
±5MiB
Plateau swing
~13%
CPU · 100 clients
~1K/s
Sustained ingest

Memory plateaus within roughly five minutes of startup and holds flat — no growth over time. Reproduce these numbers locally with the scripts in soak/.

Observability

Prometheus metrics

Key series exposed at the /metrics endpoint.

Core

MetricTypeDescription
certstream_messages_sentcounterTotal certificate messages broadcast
certstream_parse_failurescounterFailed certificate parses (RFC 6962)
certstream_ct_logs_countgaugeRFC 6962 CT logs monitored
certstream_worker_panicscounterWorker panic count (auto-recovered)

Static CT

MetricTypeDescription
certstream_static_ct_logs_countgaugeStatic CT logs monitored
certstream_static_ct_tiles_fetchedcounterTiles fetched from static CT logs
certstream_static_ct_entries_parsedcounterEntries parsed from tiles
certstream_static_ct_checkpoint_errorscounterCheckpoint fetch / parse failures
certstream_issuer_cache_sizegaugeCached issuer certificates
certstream_duplicates_filteredcounterDuplicate certificates filtered by dedup
certstream_dedup_cache_sizegaugeCurrent dedup cache entries
Coverage

CT logs monitored

Every Chrome- and Apple-trusted Certificate Transparency log, with cross-log deduplication.

Google

Argon, Xenon

Cloudflare

Nimbus, Raio (static CT)

DigiCert

Wyvern, Sphinx

Sectigo

Elephant, Tiger, Mammoth, Sabre

Let's Encrypt

Willow, Sycamore (static CT)

TrustAsia · Geomys · IPng

HETU, Luoshu, Tuscolo, Halloumi, Gouda