Files
konduit-public/docs/stealth-setup.md

3.4 KiB

Stealth Mode: HAProxy + Konduit

Konduit's stealth mode makes the VPN server indistinguishable from a normal HTTPS site. It implements a fake TLS handshake — embedding the client's ephemeral key inside the TLS SessionID field. For this to work, konduit must see the raw TCP stream from the client. Any proxy that terminates TLS before konduit breaks stealth mode.

Architecture

Client
  │  raw TCP (looks like TLS to observers)
  ▼
HAProxy :443  ── TCP passthrough ──► konduit-server :8443
                                           │
                              valid handshake │ handshake fails (real browser)
                                           │         ▼
                                           │   HAProxy :4443  (SSL termination)
                                           │         │
                                           │         ▼
                                           │   real HTTPS backend
                                        VPN tunnel

HAProxy Configuration

# VPN ingress — raw TCP passthrough, no SSL termination
frontend vpn-ingress
    bind *:443
    mode tcp
    option tcplog
    default_backend konduit-vpn

backend konduit-vpn
    mode tcp
    server konduit 127.0.0.1:8443

# Camouflage backend — receives failed handshakes from konduit via PROXY protocol
# SSL is terminated here, not on the ingress
frontend camouflage
    bind *:4443 ssl crt /etc/haproxy/ssl/your-domain.pem accept-proxy
    mode http
    http-request set-header X-Real-IP %[src]
    http-request set-header X-Forwarded-Proto https
    default_backend web

backend web
    mode http
    server web1 127.0.0.1:80 check

Konduit server.toml

[server]
listen_addr = "0.0.0.0"
listen_port = 8443
public_addr = "your-domain.com"
public_port = 443   # port clients connect to (HAProxy front)

[stealth]
enabled = true
camouflage = "127.0.0.1:4443"  # where to proxy non-konduit connections

Bootstrap with --public-port so generated client configs reference port 443:

echo "your mantra" | ./konduit-ctl bootstrap -l your-domain.com:8443 --public-port 443 -p -

How It Works

Konduit client (stealth handshake):

  1. Client sends fake TLS ClientHello with identity proof embedded
  2. HAProxy passes raw TCP to konduit on port 8443
  3. Konduit verifies identity, completes handshake, establishes VPN tunnel
  4. Traffic looks like TLS Application Data to any observer

Real browser or censor probe:

  1. Browser sends a real TLS ClientHello
  2. HAProxy passes it raw to konduit
  3. Konduit cannot verify identity — proxies the connection to 127.0.0.1:4443 with a PROXY protocol header preserving the real client IP
  4. HAProxy at 4443 terminates TLS and serves your website
  5. Observer sees a normal HTTPS site

Common Mistakes

# WRONG — TLS terminated by HAProxy before konduit, fake handshake never works
Client → HAProxy SSL termination → konduit

# CORRECT — raw TCP passed through, konduit handles the fake TLS
Client → HAProxy TCP passthrough → konduit → HAProxy SSL termination (on failure)

The camouflage frontend uses accept-proxy — do not use it as the VPN ingress.

Verify

# Browser should see your real website, not an error
curl -sk https://your-domain.com/

# Check konduit logs for stealth handshakes
journalctl -u konduit-server -f | grep -E "Stealth|Authenticated|camouflage"