Huginn Proxy is a reverse proxy built on Tokio, Hyper, and Rustls. It routes incoming connections to backend services while passively extracting TLS (JA4), HTTP/2 (Akamai), and TCP SYN (p0f-style) fingerprints and injecting them as headers. TCP SYN fingerprinting is implemented via an XDP eBPF program using Aya. Fingerprinting libraries are provided by Huginn Net.
Inspired by production-grade proxies like Pingora, Sozu, and rust-rpxy.
See examples/ for the full setup guide, including:
- Building from source (standard and with eBPF/TCP SYN fingerprinting)
- Generating TLS certificates
- Running with Docker Compose
- Configuration examples (rate limiting, routing, …)
- HTTP/1.x & HTTP/2 - Full support for both protocol versions
- Load Balancing - Round-robin load balancing across multiple backends
- Connection Pooling - Automatic connection reuse to backends for reduced latency (bypasses pooling per-route for fingerprinting)
- Path-based Routing - Route matching with prefix support, path stripping, and path rewriting
- Rate Limiting - Token bucket algorithm with multiple strategies (IP, Header, Route, Combined), global and per-route limits
- Header Manipulation - Add or remove request/response headers globally or per-route for security and customization
- Security Headers - HSTS, CSP, X-Frame-Options, and custom headers
- IP Filtering (ACL) - Allowlist/denylist with CIDR notation support
- TLS Termination - Server-side TLS with ALPN, certificate hot reload (single certificate per configuration)
- TLS Session Resumption - Support for TLS 1.2 session IDs and TLS 1.3 session tickets
- mTLS (Mutual TLS) - Client certificate authentication for secure service-to-service communication
- Granular Timeouts - TLS handshake and connection handling timeouts for resource protection
- Host Header Preservation - Configurable forwarding of original Host header for virtual hosting
- Passive Fingerprinting - Automatic TLS (JA4), HTTP/2 (Akamai), and TCP SYN (p0f-style via eBPF) fingerprint extraction
- X-Forwarded- Headers* - Automatic injection of proxy forwarding headers
- Comprehensive Telemetry - Prometheus metrics covering requests, throughput, rate limiting, TLS, backends, and security features
- High Performance - Built on Tokio and Hyper
- Easy Deployment - Single binary, Docker-ready
See FEATURES.md for detailed descriptions and limitations of each feature.
For deployment instructions, see DEPLOYMENT.md.
Fingerprints are automatically extracted and injected as headers:
- TLS (JA4):
x-huginn-net-ja4: sorted cipher suites and extensions, SHA-256 hashed. Standard FoxIO JA4. using huginn-net-tls - TLS (JA4_r):
x-huginn-net-ja4_r: original ClientHello order, SHA-256 hashed (FoxIO JA4_r) - TLS (JA4_o):
x-huginn-net-ja4_o: sorted, raw hex values without hashing (FoxIO JA4_o, useful for debugging) - TLS (JA4_or):
x-huginn-net-ja4_or: original order, raw hex values without hashing (FoxIO JA4_or) - HTTP/2 (Akamai):
x-huginn-net-akamai: Extracted from HTTP/2 connections only using huginn-net-http - TCP SYN (p0f-style):
x-huginn-net-tcp- Raw TCP SYN signature extracted via eBPF/XDP using huginn-net-tcp. Requirestcp_enabled = trueand theebpf-tcpfeature. Present on all requests of a connection (the fingerprint is captured once at TCP accept time and reused). IPv4 only, not captured for direct IPv6 connections (transparent when a load balancer forwards internally over IPv4). See EBPF-SETUP.md for setup, kernel requirements, and deployment options. - The proxy automatically injects standard
X-Forwarded-*headers to inform backends about the original client request:
Examples:
x-huginn-net-ja4: t13d3112h2_e8f1e7e78f70_b26ce05bbdd6,
x-huginn-net-ja4_r: t13d3112h2_002f,0033,0035,0039,003c,003d,0067,006b,009c,009d,009e,009f,00ff,1301,1302,1303,c009,c00a,c013,c014,c023,c024,c027,c028,c02b,c02c,c02f,c030,cca8,cca9,ccaa_000a,000b,000d,0015,0016,0017,002b,002d,0031,0033_0403,0503,0603,0807,0808,0809,080a,080b,0804,0805,0806,0401,0501,0601,0303,0301,0302,0402,0502,0602,
x-huginn-net-ja4_o: t13d3112h2_d7c3e2abb617_cad92ccb4254,
x-huginn-net-ja4_or: t13d3112h2_1302,1303,1301,c02c,c030,009f,cca9,cca8,ccaa,c02b,c02f,009e,c024,c028,006b,c023,c027,0067,c00a,c014,0039,c009,c013,0033,009d,009c,003d,003c,0035,002f,00ff_0000,000b,000a,0010,0016,0017,0031,000d,002b,002d,0033,0015_0403,0503,0603,0807,0808,0809,080a,080b,0804,0805,0806,0401,0501,0601,0303,0301,0302,0402,0502,0602,
x-huginn-net-ja4_r: t13d3112h2_d7c3e2abb617_cad92ccb4254,
x-huginn-net-akamai: 3:100;4:10485760;2:0|1048510465|0|m,s,a,p,
x-huginn-net-tcp: 4:64+0:0:1460:mss*44,10:mss,sok,ts,nop,ws:df,id+:0,
x-forwarded-for: 172.18.0.1,
x-forwarded-port: 50908,
x-forwarded-proto: https,
x-forwarded-host: localhost
These headers always override any client-provided values to prevent spoofing.
fingerprinting(bool, default:true) - Enable/disable TLS (JA4) and HTTP/2 (Akamai) fingerprint extraction and header injection- TLS fingerprints are captured once per TLS session and reused for all HTTP requests on that connection this is by design. To observe per-connection variation (e.g. Chrome's extension-order randomization), set
alpn = ["http/1.1"]andkeep_alive.enabled = falsefor debugging only; this is a protocol downgrade not suitable for production.
When telemetry.metrics_port is configured, Huginn Proxy exposes health check endpoints on the observability server (
separate from the main proxy port):
/health- General health check (200 OKif process is running)/ready- Readiness check (200 OKif backends configured,503otherwise) - for Kubernetes readiness probes/live- Liveness check (200 OKif process is running) - for Kubernetes liveness probes/metrics- Prometheus metrics endpoint
All endpoints return JSON responses (except /metrics which returns Prometheus format) and follow Kubernetes health
check conventions.
- Fingerprinting Overhead: ~2.2% (minimal impact)
- Concurrent Connections: Handles thousands of concurrent connections
- Latency: Sub-millisecond overhead for fingerprint extraction
See benches/README.md for detailed benchmark results from development environment.
See ROADMAP.md for a detailed list of planned features and upcoming phases.
Docker images
Images published to ghcr.io/biandratti/huginn-proxy (linux/amd64, linux/arm64).
| Image tag | Base image | User | eBPF | Capabilities |
|---|---|---|---|---|
:latest / :v0.0.1-beta.1 |
debian:bookworm-slim |
10001 |
✅ reads pinned maps | CAP_BPF |
:latest-plain / :v0.0.1-beta.1-plain |
debian:bookworm-slim |
10001 |
❌ | none |
:latest-ebpf-agent / :v0.0.1-beta.1-ebpf-agent |
debian:bookworm-slim |
root |
✅ loads XDP, pins maps | CAP_BPF + CAP_NET_ADMIN + CAP_PERFMON |
See DEPLOYMENT.md for Docker and Kubernetes setup, and EBPF-SETUP.md for eBPF runtime requirements.
Release binaries
| Artifact | Suffix | OS | Arch | libc | eBPF |
|---|---|---|---|---|---|
huginn-proxy |
x86_64-unknown-linux-musl |
Linux | amd64 | musl (static) | ❌ |
huginn-proxy |
aarch64-unknown-linux-musl |
Linux | arm64 | musl (static) | ❌ |
huginn-proxy |
x86_64-unknown-linux-gnu-ebpf |
Linux | amd64 | glibc | ✅ (reader) |
huginn-proxy |
aarch64-unknown-linux-gnu-ebpf |
Linux | arm64 | glibc | ✅ (reader) |
huginn-proxy |
x86_64-apple-darwin |
macOS | amd64 | - | ❌ |
huginn-proxy |
aarch64-apple-darwin |
macOS | arm64 | - | ❌ |
huginn-ebpf-agent |
x86_64-unknown-linux-gnu-ebpf-agent |
Linux | amd64 | glibc | ✅ (loader) |
huginn-ebpf-agent |
aarch64-unknown-linux-gnu-ebpf-agent |
Linux | arm64 | glibc | ✅ (loader) |
- musl (static): zero runtime dependencies, runs on any Linux kernel and distro.
- glibc (eBPF): extracted from the Docker image, requires glibc and Linux kernel ≥ 5.11.
For module structure and design decisions, see ARCHITECTURE.md.
| Fingerprint | Header | eBPF agent required |
|---|---|---|
| TLS (JA4) | x-huginn-net-ja4 |
No |
| HTTP/2 (Akamai) | x-huginn-net-akamai |
No |
| TCP SYN (p0f) | x-huginn-net-tcp |
Yes — Linux only, kernel ≥ 5.11 |
TCP SYN Fingerprinting — Deployment Architecture
┌─────────────────────────────────────────────────────────┐
│ Node │
│ │
│ ┌─────────────────────────┐ │
│ │ huginn-ebpf-agent │ CAP_BPF + CAP_NET_ADMIN │
│ │ │ + CAP_PERFMON │
│ │ XDP program (kernel) │ + seccomp:unconfined │
│ │ ┌─────────────────┐ │ + apparmor:unconfined │
│ │ │ tcp_syn_map │ │ (no open ports) │
│ │ │ syn_counter │ │ │
│ │ └────────┬────────┘ │ │
│ │ │ pin_maps() │ │
│ └───────────┼─────────────┘ │
│ │ /sys/fs/bpf/huginn/ │
│ ┌───────────┼─────────────┐ │
│ │ huginn-proxy (×N) │ CAP_BPF only │
│ │ │ │ seccomp: default │
│ │ ┌────────┴────────┐ │ USER 10001 │
│ │ │ from_pinned() │ │ │
│ │ │ map lookup │ │ │
│ │ └─────────────────┘ │ │
│ │ │ │
│ │ HTTP/TLS → backends │ │
│ │ x-huginn-net-tcp ──► │ │
│ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
The agent loads the XDP program once per node and pins BPF maps under /sys/fs/bpf/huginn/.
Multiple proxy replicas read the shared maps in read-only mode.
Dual-licensed under MIT or Apache 2.0.
Huginn Proxy uses the Huginn Net fingerprinting libraries:
- JA4: TLS fingerprinting follows the JA4 specification by FoxIO, LLC
- Akamai HTTP/2: HTTP/2 fingerprinting follows the Blackhat EU 2017 specification
- p0f v3: TCP SYN fingerprinting follows the p0f v3 specification by Michal Zalewski
Contributions are welcome! Please see our contributing guidelines for details.
