Documentation / E2E Encryption

E2E Encryption

True end-to-end encryption where the stunl server never sees your plaintext

Quick Start

Auto-generated self-signed certificate
$ stunl -port 3000 -e2e
With your own certificate
$ stunl -port 3000 -e2e -e2e-cert ./cert.pem -e2e-key ./key.pem
Let's Encrypt autocert (requires custom domain)
$ stunl -port 3000 -e2e -autocert -domain tunnel.example.com

How It Works

With E2E encryption enabled, TLS is terminated on your machine rather than on the stunl server. Traffic passes through the server fully encrypted -- it acts as a blind relay.

┌─────────┐   TLS encrypted   ┌──────────────┐   encrypted (gRPC)   ┌──────────────┐       ┌───────────┐
│ Browser │ ────────────────► │ stunl server │ ───────────────────► │ stunl client │ ────► │ Local app │
│         │ ◄──────────────── │ (blind relay)│ ◄─────────────────── │ (TLS termination)│ ◄──── │ :3000     │
└─────────┘                   └──────────────┘                     └──────────────┘       └───────────┘
                                    │
                              Server NEVER sees
                              plaintext traffic

Flags

Flag Description
-e2e Enable end-to-end encryption. Without -e2e-cert/-e2e-key, generates a self-signed certificate.
-e2e-cert Path to your TLS certificate (PEM). Must be used with -e2e-key.
-e2e-key Path to your TLS private key (PEM). Must be used with -e2e-cert.
-autocert Use Let's Encrypt to obtain a trusted certificate. Requires a custom domain with a CNAME to stunl.

Certificate Modes

Self-Signed (default) -e2e

When you pass -e2e without specifying certificate paths, stunl generates a self-signed ECDSA P-256 certificate with 1-year validity. The certificate is saved to ~/.stunl/ and reused on subsequent runs.

$ stunl -port 8080 -e2e

  ● E2E encryption enabled (self-signed)
  Certificate: ~/.stunl/e2e-cert.pem
User-Provided -e2e-cert + -e2e-key

Bring your own certificate and key. Both flags must be specified together. The key file must have 0600 permissions.

$ stunl -port 443 -e2e \
    -e2e-cert /etc/ssl/cert.pem \
    -e2e-key /etc/ssl/key.pem
Let's Encrypt Autocert -autocert

Obtains a trusted certificate from Let's Encrypt. The private key is generated locally on your machine and never transmitted. The client sends a CSR (Certificate Signing Request) to the stunl server, which completes the ACME HTTP-01 challenge and returns the signed certificate.

Requires a custom domain with a CNAME record pointing to stunl.

# 1. Add CNAME record: tunnel.example.com → stunl.io
# 2. Run with autocert:
$ stunl -port 3000 -e2e -autocert -domain tunnel.example.com

Security Details

Validation Rules

  • E2E is only available for HTTP tunnels (not TCP or UDP)
  • Requires authentication -- anonymous tunnels cannot use E2E
  • -e2e-cert and -e2e-key must be specified together

Certificate Path Security

  • Path traversal protection (no .. in paths)
  • Symlink validation -- paths are resolved and checked
  • Key file must have 0600 permissions (owner read/write only)

Autocert Key Safety

With -autocert, the private key is generated locally using ECDSA P-256 and never leaves your machine. Only the CSR is sent to the stunl server, which uses it to complete the ACME challenge with Let's Encrypt. The signed certificate is returned to the client.

Examples

Development: quick E2E with self-signed cert
$ stunl -port 3000 -e2e -id my-dev-app
Production: trusted cert on custom domain
$ stunl -port 8080 -e2e -autocert \
    -domain api.example.com -id production
Enterprise: company-issued certificate
$ stunl -port 443 -e2e \
    -e2e-cert /etc/pki/tls/certs/company.pem \
    -e2e-key /etc/pki/tls/private/company-key.pem

Next Steps