Skip to content

sebseager/waxseal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

waxseal

A lightweight self-hosted SSL/TLS integrity checker. Runs a Go server that handles its own TLS and serves a dashboard that performs security and network checks to identify TLS interception.

Client dashboard

How It Works

waxseal checks for nefariousness (like MITM interception) or misconfiguration across multiple protocol layers. It also provides some network performance testing tools.

Security Checks

  • Certificate Identity (Ed25519 Signature) -- Verifies the TLS certificate fingerprint using a DNS-anchored Ed25519 signature. The server signs the cert fingerprint + a one-time nonce with its identity key. The client fetches the corresponding public key from a DNS TXT record via DoH and verifies the signature using WebCrypto.
  • TLS Fingerprint Analysis -- Captures and analyzes the raw TLS ClientHello before Go's TLS library processes it. Checks for GREASE values (RFC 8701), proxy cipher suites, missing TLS 1.3 extensions, and known proxy fingerprints.
  • HTTP Header Inspection -- Detects proxy injection headers (Via, X-Forwarded-For, Proxy-Connection, etc.) and checks for missing browser security headers.
  • DNS Consistency -- Cross-checks the server's reported IP against an independent DoH lookup of the hostname.
  • HTTP/2 Multiplexing Probe -- Fires 5 parallel ping requests and measures the response time spread. Genuine HTTP/2 servers handle these in parallel; transparent proxies serialize them.

Network Performance

  • Latency / RTT -- 20 sequential pings measuring min/avg/max/jitter.
  • Download Speed -- Streams random data from the server, measuring throughput.
  • Upload Speed -- POSTs data to the server, measuring throughput.

Quick Start

Build from Source

git clone https://github.com/sebseager/waxseal.git
cd waxseal
go build -o waxseal .

Run with BYO Certificates

If you already have TLS certificates:

TLS_CERT=cert.pem TLS_KEY=key.pem ./waxseal

Then visit https://localhost:8443.

Run with Let's Encrypt (autocert)

If your server has port 443 reachable and you have a domain pointed at it:

DOMAIN=waxseal.yourdomain.com ./waxseal --listen :443

Run with Docker Compose

DOMAIN=waxseal.yourdomain.com docker compose up -d

This uses Let's Encrypt autocert. The identity.pem file should be in the project root (see below). Adjust the volume mount in docker-compose.yml if your key is elsewhere.

Identity Key Setup

The identity key enables automated cryptographic verification of the server's TLS certificate. Without it, users must manually compare certificate fingerprints.

Generate with the built-in keygen:

./waxseal keygen --domain yourdomain.com --out identity.pem

This outputs a private key and the DNS TXT record you need to add:

_waxseal.yourdomain.com  TXT  "v=waxseal1 pk=BASE64_PUBKEY"

Or generate with OpenSSL:

openssl genpkey -algorithm Ed25519 -out identity.pem
openssl pkey -in identity.pem -pubout -outform DER | tail -c 32 | base64

Use the base64 output in the DNS TXT record above.

Then set the environment variable when running the server:

IDENTITY_KEY=identity.pem ./waxseal

Configuration

All options can be set via environment variables or CLI flags (--domain, --listen, etc.).

Variable Default Description
DOMAIN (required for autocert) Let's Encrypt domain
LISTEN_ADDR :8443 TCP listen address
TLS_CERT / TLS_KEY (empty) BYO cert paths; skips autocert if set
IDENTITY_KEY (empty) Path to Ed25519 private key PEM
LOG_LEVEL info debug / info / warn / error
DOH_RESOLVER https://cloudflare-dns.com/dns-query DoH endpoint
EXTERNAL_IP (auto-detected) Server public IP override

Deployment

waxseal must handle its own TLS. Any reverse proxy in front must forward raw TCP without terminating TLS. If a proxy terminates TLS, it is the MITM, and waxseal will correctly detect it.

Docker Compose

DOMAIN=waxseal.yourdomain.com docker compose up -d

The autocert cache is stored in a Docker volume so certificates persist across restarts. To use BYO certificates instead, uncomment the TLS_CERT and TLS_KEY variables in docker-compose.yml and mount your cert files.

Nginx Proxy Manager

Configure NPM to forward raw TCP (not HTTP proxy):

  1. Go to the Streams tab (not Proxy Hosts)
  2. Create a new stream:
    • Incoming Port: 443 (or your chosen port)
    • Forward Host: waxseal container IP or hostname
    • Forward Port: 8443
    • TCP Forwarding: enabled (no SSL termination)

Traefik

Use a TCP router with TLS passthrough:

# traefik dynamic config
tcp:
  routers:
    waxseal:
      rule: "HostSNI(`waxseal.yourdomain.com`)"
      service: waxseal
      tls:
        passthrough: true
  services:
    waxseal:
      loadBalancer:
        servers:
          - address: "waxseal:8443"

Caddy (with L4 module)

Caddy requires the caddy-l4 module for TCP-level routing:

{
    layer4 {
        :443 {
            @waxseal tls sni waxseal.yourdomain.com
            route @waxseal {
                proxy waxseal:8443
            }
        }
    }
}

License

See LICENSE.

About

Lightweight self-hosted SSL/TLS integrity checker

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors