Written with AI. This project was developed with the help of an AI assistant (Anthropic's Claude, via Claude Code). The code has been reviewed and tested, but treat it accordingly: read it before you run it, and see the security model below for what it does and does not protect.
tlsgate is a TCP proxy that fingerprints TLS ClientHellos with JA3 or JA4
and allows or blocks connections using an approval store. Routes are generic;
fronting mail submission and retrieval ports is the common case.
It can run standalone or report observations to
Gatehub, the shared control plane for
the *gate tools.
brag.mp4
tlsgate sits in front of one or more TLS backends and reads the ClientHello
before forwarding traffic. Unknown fingerprints are blocked by default. During
enrollment, --allow-unknown records new fingerprints as pending while
allowing them through; remove it after approving known clients.
client ──► tlsgate ── approved fingerprint ──► TLS backend
└─ unknown or blocked ───► drop
The proxy does not terminate TLS. Approved traffic continues to the real backend unchanged.
A TLS fingerprint is not a credential. JA3 and JA4 are trivially spoofable.
Treat this as a noise filter against opportunistic scanners and generic
credential-stuffing traffic, not as authentication or access control. The real
security boundary remains the backend's TLS termination, authentication,
rate-limiting, and abuse controls. Do not weaken backend security because
tlsgate is present.
The proxy also enforces per-source and global connection limits and bounds fingerprint-store growth. Those controls reduce resource abuse but do not make fingerprints identities.
Use --fingerprint ja3 (the default) or --fingerprint ja4.
- JA3 is order-sensitive and has a large public corpus, but clients that shuffle TLS extensions can produce unstable fingerprints.
- JA4 sorts ciphers and extensions before hashing, making it more stable for a small self-seeded allowlist.
The database records which method created its keys. Starting with a different method fails rather than silently invalidating existing decisions. Switching methods requires an explicit reset and re-enrollment.
Download a static Linux binary from the GitHub releases page, or build and test with Go 1.27.1 or newer:
go build -o tlsgate .
go test ./...Use an unprivileged high port for a temporary enrollment window, leaving the real public listener untouched while you test:
./tlsgate serve \
--route '[::]:1993=127.0.0.1:10993' \
--db ./tlsgate.db \
--fingerprint ja4 \
--allow-unknownAfter connecting known clients, review and approve their fingerprints:
./tlsgate list -v --db ./tlsgate.db
./tlsgate approve --db ./tlsgate.db --label "Alice phone" <fingerprint>Remove --allow-unknown for normal operation.
Validate the same startup inputs without opening the database, connecting to a backend, or binding a port:
./tlsgate doctor \
--route '[::]:1993=127.0.0.1:10993' \
--db ./tlsgate.db \
--fingerprint ja4The included Ansible playbook is the primary deployment path:
cd ansible
cp inventory.example inventory
cp group_vars/tlsgate.example.yml group_vars/tlsgate.yml
# Edit both local files for your deployment.
ansible-playbook --syntax-check playbook.yml
ansible-playbook playbook.yml --ask-become-passThe real inventory and group variables are ignored so deployment-specific host names, network ranges, fingerprints, and notification credentials are not committed accidentally.
The backend must first move from its public port to an internal-only port. Deployment changes on an inline proxy need graceful handoff so active connections are not dropped.
See deployment for Ansible variables, graceful upgrades, Docker, and PROXY protocol configuration.
- Deployment
- Operations — fingerprint management, alerts, Gatehub sync, storage limits, logs, and enrollment
- SMTP TLS correlation — observe STARTTLS and join fingerprints to explicit spam/ham verdicts in a report-only workflow
- SMTP deployment example — place the report-only observer ahead of a PROXY-aware MTA using reserved example infrastructure
- How the five Gate projects fit together
- Repository guidance
MIT. See LICENSE.

