warpdrive-proxy 0.1.0

A high-performance HTTP proxy with PostgreSQL coordination and distributed caching
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
# WarpDrive

WarpDrive [shah-wahr-muh] is a high-performance reverse proxy built on [Pingora](https://github.com/cloudflare/pingora) (Cloudflare's Rust proxy framework). We built it because Cloudflare already gave us the Engine — no need to reinvent the wheel in space. It routes traffic to multiple upstream services with protocol awareness, load balancing, and path transformation.

## Features

**Routing & Load Balancing:**
- Multi-upstream routing with path, host, method, and header matching
- Built-in load balancing (always uses Pingora's LoadBalancer, even for single backends)
- Path transformation (strip_prefix, rewrite)
- Protocol support: HTTP, HTTPS, WebSocket (ws/wss), gRPC
- Unix domain socket support (~30% faster than TCP)

**Middleware Chain:**
- **Direct static file serving** (bypasses backend, 600+ req/s)
- X-Forwarded-* header management
- Request/response logging with Prometheus metrics
- X-Sendfile support (backend-controlled file serving)
- Gzip compression (including pre-compressed .gz files)
- Per-IP rate limiting (GCRA token bucket)
- Circuit breaker (automatic failure detection)
- Concurrency limiting (max concurrent requests)
- Custom middleware extensibility

**Caching & Coordination:**
- **L1 Cache**: In-memory LRU (64MB default, probabilistic eviction, won't kill your Raspberry Pi)
- **L2 Cache**: Redis distributed cache (optional, auto-fallback to L1 on errors)
- **Invalidation**: PostgreSQL LISTEN/NOTIFY for cross-instance coordination
- **Graceful Degradation**: Works without Redis/PostgreSQL (memory-only mode)

**Observability:**
- **Prometheus Metrics**: HTTP requests, cache hits/misses, circuit breaker state
- **Structured Logging**: tracing-based logs with request context
- **Metrics Endpoint**: `/metrics` on configurable port (default 9090)

**Operations:**
- Two modes: Simple (env vars) or Advanced (TOML routing config)
- Process supervisor for Ruby/Node/Python upstreams
- Docker support with Ruby 3.4 Alpine base
- Environment-based configuration with sensible defaults
- Graceful shutdown with configurable timeout

> **⚠️ Version 0.1.0 Limitations**: ACME auto-renewal and process crash recovery are experimental. See [LIMITATIONS.md]LIMITATIONS.md for production deployment guidance.

## Getting Started

### Prerequisites

- **Unix-based OS** (Linux/macOS/FreeBSD/etc) — Windows not supported (at Wrap speed, Windows will break and cause hull breach)
- Rust 1.90+
- Optional: Redis, PostgreSQL (for caching/coordination)

### Quick Start

**Simple Mode** (single upstream):
```bash
cargo build --release
WARPDRIVE_TARGET_PORT=3001 WARPDRIVE_HTTP_PORT=8080 ./target/release/warpdrive
```

**Advanced Mode** (multi-upstream routing):
```bash
# Create config.toml
cat > config.toml << 'EOF'
[upstreams.rails]
protocol = "http"
host = "127.0.0.1"
port = 3000

[upstreams.cable]
protocol = "ws"
socket = "/tmp/cable.sock"

[[routes]]
path_prefix = "/cable"
upstream = "cable"

[[routes]]
path_prefix = "/"
upstream = "rails"
EOF

# Run with TOML config
WARPDRIVE_CONFIG=config.toml ./target/release/warpdrive
```

### Configuration

> 📝 **See [.env.example].env.example for a complete, documented list of all configuration options.**

**Simple Mode** (env vars only):

*Basic Proxy:*
- `WARPDRIVE_TARGET_HOST=127.0.0.1` — upstream host
- `WARPDRIVE_TARGET_PORT=3000` — upstream port
- `WARPDRIVE_HTTP_PORT=8080` — HTTP listener port (default: 8080, unprivileged)
- `WARPDRIVE_HTTPS_PORT=8443` — HTTPS listener port (default: 8443, unprivileged)

*Static File Serving:*
- `WARPDRIVE_STATIC_ENABLED=true` — enable direct static file serving (default: true)
- `WARPDRIVE_STATIC_ROOT=./public` — static files directory (default: ./public)
- `WARPDRIVE_STATIC_PATHS=/assets,/packs` — URL paths to serve statically
- `WARPDRIVE_STATIC_CACHE_CONTROL="..."` — cache header for static files

*Caching (Optional):*
- `WARPDRIVE_CACHE_SIZE=67108864` — memory cache size in bytes (default 64MB)
- `WARPDRIVE_MAX_CACHE_ITEM_SIZE=1048576` — max item size in bytes (default 1MB)
- `WARPDRIVE_REDIS_URL=redis://localhost:6379` — Redis L2 cache (optional)
- `WARPDRIVE_DATABASE_URL=postgresql://localhost/warpdrive` — PostgreSQL for invalidation (optional)

*Observability:*
- `WARPDRIVE_METRICS_ENABLED=true` — enable Prometheus metrics endpoint
- `WARPDRIVE_METRICS_PORT=9090` — metrics HTTP server port
- `WARPDRIVE_LOG_LEVEL=info` — log level (error, warn, info, debug)

*Resilience:*
- `WARPDRIVE_RATE_LIMIT_ENABLED=true` — enable per-IP rate limiting
- `WARPDRIVE_RATE_LIMIT_RPS=100` — requests per second per IP
- `WARPDRIVE_RATE_LIMIT_BURST=200` — burst size (tokens)
- `WARPDRIVE_CIRCUIT_BREAKER_ENABLED=true` — enable circuit breaker
- `WARPDRIVE_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5` — failures before opening
- `WARPDRIVE_CIRCUIT_BREAKER_TIMEOUT_SECS=60` — seconds before trying half-open
- `WARPDRIVE_MAX_CONCURRENT_REQUESTS=0` — max concurrent requests (0 = unlimited)

*Process Supervision:*
- `WARPDRIVE_UPSTREAM_COMMAND=bundle exec puma` — command to spawn upstream
- `WARPDRIVE_UPSTREAM_ARGS=-p 3000` — arguments for upstream command

**Advanced Mode** (TOML config):
- `WARPDRIVE_CONFIG=/path/to/config.toml` — routing configuration

See `config.example.toml` for full TOML examples with:
- Path transformation (strip_prefix, rewrite)
- Load-balanced pools
- WebSocket/gRPC routing
- Unix domain sockets

**Deployment Modes:**

```bash
# Mode 1: Memory-only (dev)
WARPDRIVE_TARGET_PORT=3000 ./warpdrive

# Mode 2: + Redis cache (staging)
WARPDRIVE_REDIS_URL=redis://localhost:6379 \
WARPDRIVE_TARGET_PORT=3000 ./warpdrive

# Mode 3: Full distributed (production)
WARPDRIVE_REDIS_URL=redis://localhost:6379 \
WARPDRIVE_DATABASE_URL=postgresql://localhost/warpdrive \
WARPDRIVE_METRICS_ENABLED=true \
WARPDRIVE_RATE_LIMIT_ENABLED=true \
WARPDRIVE_CIRCUIT_BREAKER_ENABLED=true \
WARPDRIVE_TARGET_PORT=3000 ./warpdrive
```

### Static File Serving

WarpDrive can serve static files directly from disk, bypassing your application backend entirely. This is significantly faster than X-Sendfile.

**Key Differences:**
- **Direct Static Serving**: WarpDrive serves files from configured paths (e.g., `/assets/*`) without touching the backend
- **X-Sendfile**: Backend returns `X-Sendfile` header, then WarpDrive serves the file
- **Performance**: Static serving is 10-100x faster than backend serving, ideal for assets/images/fonts

**Basic Setup:**
```bash
# Serve files from ./public directory
WARPDRIVE_STATIC_ENABLED=true \
WARPDRIVE_STATIC_ROOT=./public \
WARPDRIVE_STATIC_PATHS=/assets,/packs,/images,/favicon.ico \
./warpdrive
```

**Directory Structure:**
```
./public/
├── assets/
│   ├── application.css
│   └── application.js
├── images/
│   ├── logo.png
│   └── hero.jpg
└── favicon.ico
```

**URL Mapping:**
- `GET /assets/application.js``./public/assets/application.js`
- `GET /images/logo.png``./public/images/logo.png`
- `GET /favicon.ico``./public/favicon.ico`

**Features:**
- **Content-Type Detection**: 28 MIME types (js, css, html, png, svg, woff2, etc.)
- **ETag Generation**: `"{size}-{mtime_nanos}"` format for cache validation
- **304 Not Modified**: Automatic `If-None-Match` handling
- **Gzip Support**: Serves `.gz` files when `Accept-Encoding: gzip` present
- **Directory Indexes**: Serves `index.html` for directory requests
- **Security**: Directory traversal prevention, hidden file blocking
- **Fallthrough**: Continues to backend if file not found (configurable)

**Environment Variables:**
```bash
WARPDRIVE_STATIC_ENABLED=true            # Enable/disable (default: true)
WARPDRIVE_STATIC_ROOT=./public           # Root directory (default: ./public)
WARPDRIVE_STATIC_PATHS=/assets,/packs    # URL prefixes (default: /assets,/packs,/images,/favicon.ico)
WARPDRIVE_STATIC_CACHE_CONTROL="public, max-age=31536000, immutable"  # Cache header
WARPDRIVE_STATIC_GZIP=true               # Serve .gz files (default: true)
WARPDRIVE_STATIC_INDEX_FILES=index.html  # Directory indexes (default: index.html)
WARPDRIVE_STATIC_FALLTHROUGH=true        # Pass to backend if not found (default: true)
```

**Example Responses:**
```bash
# JavaScript with ETag and caching
$ curl -I http://localhost/assets/app.js
HTTP/1.1 200 OK
Content-Type: application/javascript
Content-Length: 1024
Cache-Control: public, max-age=31536000, immutable
ETag: "1024-1759606090065974032"

# 304 Not Modified on subsequent request
$ curl -I -H 'If-None-Match: "1024-1759606090065974032"' http://localhost/assets/app.js
HTTP/1.1 304 Not Modified
ETag: "1024-1759606090065974032"
Cache-Control: public, max-age=31536000, immutable
```

**Performance:**
- **Sequential**: ~100 req/s (single curl loop)
- **Concurrent**: 600+ req/s (500 parallel requests)
- **Latency**: Sub-millisecond for cached files
- **No backend overhead**: Rails/app server never touched

**Production Tips:**
- Use CDN for hot assets (CloudFlare, Fastly) for global distribution
- Enable gzip pre-compression: `gzip -k public/assets/*.{js,css}`
- Set long cache TTL: files are immutable with content hashing
- Monitor with Prometheus: `static_files_served_total` metric (future)

### TLS & ACME Configuration

WarpDrive supports TLS/HTTPS in three ways:

**1. Manual Certificates** (self-signed or custom):
```bash
# Self-signed certificate (development)
openssl req -x509 -newkey rsa:4096 -nodes \
  -keyout server.key -out server.crt -days 365 \
  -subj "/CN=localhost"

WARPDRIVE_TLS_CERT_PATH=server.crt \
WARPDRIVE_TLS_KEY_PATH=server.key \
WARPDRIVE_HTTPS_PORT=443 \
./warpdrive
```

**2. ACME/Let's Encrypt** (automatic certificates):
```bash
# Production with automatic Let's Encrypt certificates
WARPDRIVE_TLS_DOMAINS=example.com,www.example.com \
WARPDRIVE_STORAGE_PATH=/var/lib/warpdrive \
WARPDRIVE_HTTP_PORT=80 \
WARPDRIVE_HTTPS_PORT=443 \
./warpdrive
```

**Environment Variables:**
- `WARPDRIVE_TLS_DOMAINS=domain1.com,domain2.com` — domains for ACME certificates
- `WARPDRIVE_STORAGE_PATH=/var/lib/warpdrive` — certificate storage directory
- `WARPDRIVE_ACME_DIRECTORY=https://acme-v02.api.letsencrypt.org/directory` — ACME server URL
- `WARPDRIVE_EAB_KID=...` — External Account Binding key ID (optional, for some CAs)
- `WARPDRIVE_EAB_HMAC_KEY=...` — EAB HMAC key (optional)

**ACME Workflow:**
1. WarpDrive provisions certificates on startup for all `TLS_DOMAINS`
2. HTTP-01 challenges handled at `/.well-known/acme-challenge/*`
3. Certificates stored in `{STORAGE_PATH}/certs/{domain}.pem`
4. Private keys stored with 0600 permissions
5. HTTPS listener starts with provisioned certificates

**Certificate Storage Layout:**
```
/var/lib/warpdrive/
├── account.json              # ACME account credentials
└── certs/
    ├── example.com.pem       # Certificate chain
    ├── example.com.key.pem   # Private key
    ├── www.example.com.pem
    └── www.example.com.key.pem
```

**3. Docker with TLS** (self-signed generation):
```bash
# Docker automatically generates self-signed cert at build time
docker run -p 80:80 -p 443:443 \
  -e WARPDRIVE_TARGET_PORT=3000 \
  warpdrive
```

**Let's Encrypt Staging** (testing):
```bash
# Use staging server for testing (avoids rate limits)
WARPDRIVE_TLS_DOMAINS=test.example.com \
WARPDRIVE_ACME_DIRECTORY=https://acme-staging-v02.api.letsencrypt.org/directory \
WARPDRIVE_STORAGE_PATH=/tmp/warpdrive \
./warpdrive
```

**Protocol Support:**
- HTTP/1.1 and HTTP/2 (automatic via ALPN)
- WebSocket over TLS (wss://)
- HTTP/3/QUIC (tracked, blocked on Pingora support)

### Docker

Run WarpDrive with Puma and Falcon backends:

```bash
docker-compose up warpdrive
```

Test routing:
```bash
curl http://localhost:8080/              # → Puma
curl http://localhost:8080/puma/test     # → Puma (/test)
curl http://localhost:8080/falcon/test   # → Falcon (/test)
```

See `DOCKER.md` for details.

### Tests

**Quick Start** (Docker Compose with PostgreSQL and Redis):
```bash
# Run all tests in isolated environment
docker-compose up --build test
```

**Local Development:**
```bash
# Start services
docker-compose up -d postgres redis

# Run tests
export WARPDRIVE_DATABASE_URL=postgresql://warpdrive:warpdrive_test@localhost:5432/warpdrive_test
export WARPDRIVE_REDIS_URL=redis://localhost:6379
cargo test --workspace --all-features
```

**Test Categories:**
```bash
# Unit tests only
cargo test --lib

# Integration tests
cargo test --test '*'

# Specific test suites
cargo test --lib cache
cargo test --test redis_test
cargo test --test postgres_test
```

See [`TESTING.md`](TESTING.md) for comprehensive testing guide including:
- Docker Compose test setup
- CI/CD configuration examples
- Coverage reports
- Troubleshooting guide

### Environment Variables Reference

**Complete list of all configuration options:**

```bash
# Core Proxy
WARPDRIVE_TARGET_HOST=127.0.0.1          # Upstream host (simple mode)
WARPDRIVE_TARGET_PORT=3000               # Upstream port (simple mode)
WARPDRIVE_HTTP_PORT=80                   # HTTP listener port
WARPDRIVE_HTTPS_PORT=443                 # HTTPS listener port

# TLS & ACME
WARPDRIVE_TLS_DOMAINS=example.com,www.example.com  # ACME domains (comma-separated)
WARPDRIVE_TLS_CERT_PATH=/path/to/cert.pem          # Manual certificate path
WARPDRIVE_TLS_KEY_PATH=/path/to/key.pem            # Manual key path
WARPDRIVE_STORAGE_PATH=/var/lib/warpdrive          # Certificate storage directory
WARPDRIVE_ACME_DIRECTORY=https://...               # ACME server URL
WARPDRIVE_EAB_KID=...                              # External Account Binding key ID
WARPDRIVE_EAB_HMAC_KEY=...                         # External Account Binding HMAC key

# Caching
WARPDRIVE_CACHE_SIZE=67108864            # Memory cache size in bytes (64MB)
WARPDRIVE_MAX_CACHE_ITEM_SIZE=1048576    # Max item size in bytes (1MB)
WARPDRIVE_REDIS_URL=redis://localhost:6379         # Redis L2 cache (optional)
WARPDRIVE_DATABASE_URL=postgresql://...            # PostgreSQL for invalidation (optional)

# Observability
WARPDRIVE_METRICS_ENABLED=true           # Enable Prometheus metrics
WARPDRIVE_METRICS_PORT=9090              # Metrics server port
WARPDRIVE_LOG_LEVEL=info                 # Log level (error/warn/info/debug/trace)
WARPDRIVE_LOG_REQUESTS=true              # Log all HTTP requests

# Resilience
WARPDRIVE_RATE_LIMIT_ENABLED=true        # Enable per-IP rate limiting
WARPDRIVE_RATE_LIMIT_RPS=100             # Requests per second per IP
WARPDRIVE_RATE_LIMIT_BURST=200           # Burst size (tokens)
WARPDRIVE_CIRCUIT_BREAKER_ENABLED=true   # Enable circuit breaker
WARPDRIVE_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5      # Failures before opening
WARPDRIVE_CIRCUIT_BREAKER_TIMEOUT_SECS=60          # Seconds before retry
WARPDRIVE_MAX_CONCURRENT_REQUESTS=0      # Max concurrent requests (0 = unlimited)
WARPDRIVE_UPSTREAM_TIMEOUT=30            # Upstream request timeout in seconds

# Headers & Middleware
WARPDRIVE_FORWARD_HEADERS=true           # Add X-Forwarded-* headers
WARPDRIVE_X_SENDFILE_ENABLED=true        # Enable X-Sendfile support
WARPDRIVE_GZIP_COMPRESSION_ENABLED=true  # Enable gzip compression

# Static File Serving
WARPDRIVE_STATIC_ENABLED=true            # Enable direct static file serving
WARPDRIVE_STATIC_ROOT=./public           # Static files directory
WARPDRIVE_STATIC_PATHS=/assets,/packs,/images,/favicon.ico  # URL paths to serve
WARPDRIVE_STATIC_CACHE_CONTROL="public, max-age=31536000, immutable"  # Cache header
WARPDRIVE_STATIC_GZIP=true               # Serve .gz files when available
WARPDRIVE_STATIC_INDEX_FILES=index.html  # Directory index files
WARPDRIVE_STATIC_FALLTHROUGH=true        # Continue to backend if file not found

# Advanced (TOML Mode)
WARPDRIVE_CONFIG=/path/to/config.toml    # TOML routing config

# Process Supervision
WARPDRIVE_UPSTREAM_COMMAND=bundle exec puma        # Command to spawn
WARPDRIVE_UPSTREAM_ARGS=-p 3000                    # Command arguments
```

### Prometheus Metrics

WarpDrive exposes Prometheus metrics at `/metrics` on the configured port (default 9090).

**HTTP Metrics:**
- `http_requests_total{method, status}` — Total HTTP requests (counter)
- `http_request_duration_seconds{method, status}` — Request duration histogram (0.001s to 60s buckets)
- `http_requests_active` — Currently active requests (gauge)

**Cache Metrics:**
- `cache_hits_total{backend}` — Cache hits by backend (memory/redis)
- `cache_misses_total{backend}` — Cache misses by backend
- `cache_invalidations_total` — PostgreSQL NOTIFY invalidations received
- `cache_errors_total{backend, operation}` — Cache operation errors

**Circuit Breaker Metrics:**
- `circuit_breaker_state{state}` — Current state (closed/open/half_open) (gauge)
- `circuit_breaker_failures_total` — Total failures detected
- `circuit_breaker_state_changes_total{from, to}` — State transitions

**Rate Limiting Metrics:**
- `rate_limit_requests_allowed_total` — Requests allowed through
- `rate_limit_requests_denied_total` — Requests rate-limited (429 responses)

**Example Prometheus Queries:**
```promql
# Request rate by status code
rate(http_requests_total[5m])

# 95th percentile response time
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# Cache hit ratio
sum(rate(cache_hits_total[5m])) / (sum(rate(cache_hits_total[5m])) + sum(rate(cache_misses_total[5m])))

# Circuit breaker state (1=open, 0=closed)
circuit_breaker_state{state="open"}

# Rate limit rejection rate
rate(rate_limit_requests_denied_total[5m])
```

**Grafana Dashboard:**
```json
{
  "dashboard": {
    "title": "WarpDrive Proxy",
    "panels": [
      {
        "title": "Request Rate",
        "targets": [{"expr": "rate(http_requests_total[5m])"}]
      },
      {
        "title": "Cache Hit Ratio",
        "targets": [{"expr": "sum(rate(cache_hits_total[5m])) / (sum(rate(cache_hits_total[5m])) + sum(rate(cache_misses_total[5m])))"}]
      },
      {
        "title": "Circuit Breaker State",
        "targets": [{"expr": "circuit_breaker_state"}]
      }
    ]
  }
}
```

## Architecture

- **Proxy Handler** (`src/proxy/handler.rs`): Pingora ProxyHttp implementation
- **Router** (`src/router/`): Multi-upstream routing with LoadBalancer
- **Middleware** (`src/middleware/`): Request/response filtering chain
- **Cache** (`src/cache/`): L1 (Memory) + L2 (Redis) coordinator with PG invalidation
- **Metrics** (`src/metrics/`): Prometheus instrumentation
- **Config** (`src/config/`): Env vars and TOML parsing
- **Process** (`src/process/`): Upstream supervisor

**Documentation:**
- `docs/ARCHITECTURE.md` — System architecture, request lifecycle, deployment modes
- `ROUTING.md` — Multi-upstream routing details
- `MASTER_PLAN.md` — Development roadmap and current status

## License

Licensed under the [MIT License](LICENSE).