1 unstable release

Uses new Rust 2024

new 0.1.0 Feb 13, 2026

#3 in #tcp-proxy

MIT license

470KB
10K SLoC

pyx

A high-performance reverse proxy written in Rust, designed as a drop-in replacement for h2o with configuration compatibility.

Features

  • Protocol Support: HTTP/1.1, HTTP/2 (end-to-end via ALPN), HTTP/3 (QUIC), TLS 1.2/1.3
  • Reverse Proxy: Connection pooling, header manipulation, X-Forwarded-* injection, streaming
  • TCP Proxy: Layer 4 proxying with weighted load balancing and health checks
  • Static Files: Directory listing, gzip pre-compression, range requests, ETag support
  • TLS: SNI-based certificate selection, wildcard certificates, session resumption, transparent upgrade
  • Load Balancing: Weighted distribution, latency-aware routing, active health monitoring
  • Security: Request body limits, directory traversal protection, rate limiting

Installation

cargo build --release

Binary will be at target/release/pyx.

Usage

pyx [OPTIONS]

Options:
  -c, --config <CONFIG>       Configuration file [default: /etc/pyx/pyx.yaml]
  -l, --log-level <LEVEL>     Log level: trace, debug, info, warn, error [default: info]
      --json-logs             Enable JSON structured logging
  -t, --test                  Test configuration and exit
  -w, --workers <WORKERS>     Worker threads [default: auto-detect]
  -h, --help                  Print help
  -V, --version               Print version

Configuration

pyx uses h2o-compatible YAML configuration.

Minimal Example

hosts:
  "example.com:80":
    listen:
      host: 0.0.0.0
      port: 80
    paths:
      "/":
        proxy.reverse.url: "http://localhost:8080"

Full Example

# Global settings
num-threads: 4
pid-file: /var/run/pyx.pid

# Protocol settings
http2-enabled: ON
http2-idle-timeout: 180
http2-max-concurrent-streams: 256
http3-enabled: OFF

# Request limits
limit-request-body: 10485760

# Proxy defaults
proxy.preserve-host: ON
proxy.timeout.io: 30000

# Static file settings
file.send-gzip: ON

hosts:
  "example.com:443":
    listen:
      host: 0.0.0.0
      port: 443
      ssl:
        certificate-file: /etc/ssl/certs/example.pem
        key-file: /etc/ssl/private/example.key
        minimum-version: "TLSv1.2"

    paths:
      "/":
        proxy.reverse.url: "http://backend:8080"
        header.set:
          - "X-Forwarded-Proto: https"

      "/static/":
        file.dir: /var/www/static
        file.index:
          - index.html
        expires: "7 days"

      "/api/":
        proxy.reverse.url: "http://api-backend:3000"
        proxy.preserve-host: OFF
        header.set:
          - "Cache-Control: no-store"

TCP Proxy with Load Balancing

hosts:
  "tcp.example.com:3306":
    listen:
      host: 0.0.0.0
      port: 3306
      type: tcp

    backends:
      - host: "db1.internal"
        port: 3306
        weight: 100
      - host: "db2.internal"
        port: 3306
        weight: 50

    health:
      interval: 5000
      timeout: 2000
      unhealthy-threshold: 3
      healthy-threshold: 3
      latency-aware: ON

Header Manipulation

# Set header (overwrite if exists)
header.set:
  - "X-Custom: value"

# Set only if header doesn't exist
header.setifempty:
  - "X-Powered-By: pyx"

# Append to existing header
header.merge:
  - "Cache-Control: public"

# Remove header
header.unset:
  - "Server"
  - "X-Powered-By"

Configuration Reference

Setting Default Description
num-threads CPU count Worker thread count
pid-file (none) PID file path
limit-request-body 10485760 Max request body size (bytes)
file.send-gzip OFF Serve pre-compressed .gz files
proxy.preserve-host OFF Preserve Host header when proxying
proxy.timeout.io 30000 Proxy I/O timeout (ms)
http2-enabled ON Enable HTTP/2
http2-idle-timeout 180 HTTP/2 idle timeout (seconds)
http2-max-concurrent-streams 256 Max streams per connection
http2-initial-stream-window 1048576 HTTP/2 stream window size (bytes)
http2-initial-connection-window 2097152 HTTP/2 connection window size (bytes)
http2-max-frame-size 16384 HTTP/2 max frame size (bytes)
http3-enabled OFF Enable HTTP/3 (QUIC)
http3-idle-timeout 30 HTTP/3 idle timeout (seconds)
http3-max-concurrent-streams 256 HTTP/3 max streams per connection

Routing

Routes use longest-prefix matching. More specific paths take priority:

paths:
  "/":           # Catch-all
  "/api":        # Matches /api, /api/users, /api/v1
  "/api/v2":     # Matches /api/v2, /api/v2/users (takes priority over /api)
  "/static/":    # Only matches paths starting with /static/

Path matching prevents false prefixes: /api does not match /apikey.

TLS

Basic TLS

listen:
  host: 0.0.0.0
  port: 443
  ssl:
    certificate-file: /path/to/cert.pem
    key-file: /path/to/key.pem

SNI with Multiple Certificates

Configure multiple hosts on the same port. pyx selects certificates based on SNI:

hosts:
  "site-a.com:443":
    listen:
      port: 443
      ssl:
        certificate-file: /certs/site-a.pem
        key-file: /keys/site-a.key
    paths:
      "/":
        proxy.reverse.url: "http://backend-a:8080"

  "site-b.com:443":
    listen:
      port: 443
      ssl:
        certificate-file: /certs/site-b.pem
        key-file: /keys/site-b.key
    paths:
      "/":
        proxy.reverse.url: "http://backend-b:8080"

Transparent TLS Upgrade (TCP Proxy)

Accept both plain and TLS connections on the same port for TCP proxy:

hosts:
  "tcp.example.com:8080":
    listen:
      host: 0.0.0.0
      port: 8080
      type: tcp
    tls:
      certificate-file: /path/to/cert.pem
      key-file: /path/to/key.pem
      transparent-upgrade: ON
    backends:
      - host: "backend.internal"
        port: 8080

Static File Serving

paths:
  "/static/":
    file.dir: /var/www/static
    file.index:
      - index.html
      - index.htm
    file.dirlisting: ON
    expires: "30 days"

Features:

  • Automatic MIME type detection
  • Serves .gz files when Accept-Encoding: gzip is present
  • ETag and If-None-Match support
  • Range request support (partial content)
  • Directory traversal protection

Health Checks

For TCP proxy backends:

health:
  interval: 5000          # Check every 5 seconds
  timeout: 2000           # 2 second timeout per check
  unhealthy-threshold: 3  # 3 failures to mark unhealthy
  healthy-threshold: 3    # 3 successes to mark healthy
  latency-aware: ON       # Route less traffic to slow backends
  sigma-threshold: 2.0    # Latency std deviation threshold

Development

# Build
cargo build                    # Debug
cargo build --release          # Release

# Test
cargo test                     # All tests
cargo test --lib               # Unit tests
cargo test --test integration_tests

# Lint
cargo clippy
cargo fmt

# Benchmark
cargo bench
cargo bench --bench routing
cargo bench --bench proxy

License

See LICENSE file.

Dependencies

~39–59MB
~1M SLoC