warpdrive-proxy 0.1.0-x86_64-freebsd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +513 -0
- data/bin/warpdrive +31 -0
- data/exe/warpdrive-x86_64-unknown-freebsd +0 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ac00b16867eb512c5744cff2258b6d5df753775036b28610cb170793bebca27d
|
4
|
+
data.tar.gz: fceb16ec68b5fd2a6ea64dce58847da96f91935293865b22cd36247a1299d92e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d7c2cb72e8fabde140053eda7ce5528fd1789ba89e284829a9c453c52f170eac21730387074347c7676a33281b68869306ba5c6867c79a7b0d67e535bd8c66c8
|
7
|
+
data.tar.gz: 410bceb64ffee5b340e5640e35ccf455b50b681a51dafa46b277821ef927b039c5850fb5293e922ef898bdc415efcecce89d3fce383050b1234e44358210b4e1
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 Abdelkader Boudih
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,513 @@
|
|
1
|
+
# WarpDrive
|
2
|
+
|
3
|
+
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.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
**Routing & Load Balancing:**
|
8
|
+
- Multi-upstream routing with path, host, method, and header matching
|
9
|
+
- Built-in load balancing (always uses Pingora's LoadBalancer, even for single backends)
|
10
|
+
- Path transformation (strip_prefix, rewrite)
|
11
|
+
- Protocol support: HTTP, HTTPS, WebSocket (ws/wss), gRPC
|
12
|
+
- Unix domain socket support (~30% faster than TCP)
|
13
|
+
|
14
|
+
**Middleware Chain:**
|
15
|
+
- **Direct static file serving** (bypasses backend, 600+ req/s)
|
16
|
+
- X-Forwarded-* header management
|
17
|
+
- Request/response logging with Prometheus metrics
|
18
|
+
- X-Sendfile support (backend-controlled file serving)
|
19
|
+
- Gzip compression (including pre-compressed .gz files)
|
20
|
+
- Per-IP rate limiting (GCRA token bucket)
|
21
|
+
- Circuit breaker (automatic failure detection)
|
22
|
+
- Concurrency limiting (max concurrent requests)
|
23
|
+
- Custom middleware extensibility
|
24
|
+
|
25
|
+
**Caching & Coordination:**
|
26
|
+
- **L1 Cache**: In-memory LRU (64MB default, probabilistic eviction, won't kill your Raspberry Pi)
|
27
|
+
- **L2 Cache**: Redis distributed cache (optional, auto-fallback to L1 on errors)
|
28
|
+
- **Invalidation**: PostgreSQL LISTEN/NOTIFY for cross-instance coordination
|
29
|
+
- **Graceful Degradation**: Works without Redis/PostgreSQL (memory-only mode)
|
30
|
+
|
31
|
+
**Observability:**
|
32
|
+
- **Prometheus Metrics**: HTTP requests, cache hits/misses, circuit breaker state
|
33
|
+
- **Structured Logging**: tracing-based logs with request context
|
34
|
+
- **Metrics Endpoint**: `/metrics` on configurable port (default 9090)
|
35
|
+
|
36
|
+
**Operations:**
|
37
|
+
- Two modes: Simple (env vars) or Advanced (TOML routing config)
|
38
|
+
- Process supervisor for Ruby/Node/Python upstreams
|
39
|
+
- Docker support with Ruby 3.4 Alpine base
|
40
|
+
- Environment-based configuration with sensible defaults
|
41
|
+
- Graceful shutdown with configurable timeout
|
42
|
+
|
43
|
+
## Getting Started
|
44
|
+
|
45
|
+
### Prerequisites
|
46
|
+
|
47
|
+
- **Unix-based OS** (Linux/macOS/FreeBSD/etc) — Windows not supported (at Wrap speed, Windows will break and cause hull breach)
|
48
|
+
- Rust 1.90+
|
49
|
+
- Optional: Redis, PostgreSQL (for caching/coordination)
|
50
|
+
|
51
|
+
### Quick Start
|
52
|
+
|
53
|
+
**Simple Mode** (single upstream):
|
54
|
+
```bash
|
55
|
+
cargo build --release
|
56
|
+
WARPDRIVE_TARGET_PORT=3001 WARPDRIVE_HTTP_PORT=8080 ./target/release/warpdrive
|
57
|
+
```
|
58
|
+
|
59
|
+
**Advanced Mode** (multi-upstream routing):
|
60
|
+
```bash
|
61
|
+
# Create config.toml
|
62
|
+
cat > config.toml << 'EOF'
|
63
|
+
[upstreams.rails]
|
64
|
+
protocol = "http"
|
65
|
+
host = "127.0.0.1"
|
66
|
+
port = 3000
|
67
|
+
|
68
|
+
[upstreams.cable]
|
69
|
+
protocol = "ws"
|
70
|
+
socket = "/tmp/cable.sock"
|
71
|
+
|
72
|
+
[[routes]]
|
73
|
+
path_prefix = "/cable"
|
74
|
+
upstream = "cable"
|
75
|
+
|
76
|
+
[[routes]]
|
77
|
+
path_prefix = "/"
|
78
|
+
upstream = "rails"
|
79
|
+
EOF
|
80
|
+
|
81
|
+
# Run with TOML config
|
82
|
+
WARPDRIVE_CONFIG=config.toml ./target/release/warpdrive
|
83
|
+
```
|
84
|
+
|
85
|
+
### Configuration
|
86
|
+
|
87
|
+
**Simple Mode** (env vars only):
|
88
|
+
|
89
|
+
*Basic Proxy:*
|
90
|
+
- `WARPDRIVE_TARGET_HOST=127.0.0.1` — upstream host
|
91
|
+
- `WARPDRIVE_TARGET_PORT=3000` — upstream port
|
92
|
+
- `WARPDRIVE_HTTP_PORT=80` — HTTP listener port
|
93
|
+
- `WARPDRIVE_HTTPS_PORT=443` — HTTPS listener port
|
94
|
+
|
95
|
+
*Static File Serving:*
|
96
|
+
- `WARPDRIVE_STATIC_ENABLED=true` — enable direct static file serving (default: true)
|
97
|
+
- `WARPDRIVE_STATIC_ROOT=./public` — static files directory (default: ./public)
|
98
|
+
- `WARPDRIVE_STATIC_PATHS=/assets,/packs` — URL paths to serve statically
|
99
|
+
- `WARPDRIVE_STATIC_CACHE_CONTROL="..."` — cache header for static files
|
100
|
+
|
101
|
+
*Caching (Optional):*
|
102
|
+
- `WARPDRIVE_CACHE_SIZE=67108864` — memory cache size in bytes (default 64MB)
|
103
|
+
- `WARPDRIVE_MAX_CACHE_ITEM_SIZE=1048576` — max item size in bytes (default 1MB)
|
104
|
+
- `WARPDRIVE_REDIS_URL=redis://localhost:6379` — Redis L2 cache (optional)
|
105
|
+
- `WARPDRIVE_DATABASE_URL=postgresql://localhost/warpdrive` — PostgreSQL for invalidation (optional)
|
106
|
+
|
107
|
+
*Observability:*
|
108
|
+
- `WARPDRIVE_METRICS_ENABLED=true` — enable Prometheus metrics endpoint
|
109
|
+
- `WARPDRIVE_METRICS_PORT=9090` — metrics HTTP server port
|
110
|
+
- `WARPDRIVE_LOG_LEVEL=info` — log level (error, warn, info, debug)
|
111
|
+
|
112
|
+
*Resilience:*
|
113
|
+
- `WARPDRIVE_RATE_LIMIT_ENABLED=true` — enable per-IP rate limiting
|
114
|
+
- `WARPDRIVE_RATE_LIMIT_RPS=100` — requests per second per IP
|
115
|
+
- `WARPDRIVE_RATE_LIMIT_BURST=200` — burst size (tokens)
|
116
|
+
- `WARPDRIVE_CIRCUIT_BREAKER_ENABLED=true` — enable circuit breaker
|
117
|
+
- `WARPDRIVE_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5` — failures before opening
|
118
|
+
- `WARPDRIVE_CIRCUIT_BREAKER_TIMEOUT_SECS=60` — seconds before trying half-open
|
119
|
+
- `WARPDRIVE_MAX_CONCURRENT_REQUESTS=0` — max concurrent requests (0 = unlimited)
|
120
|
+
|
121
|
+
*Process Supervision:*
|
122
|
+
- `WARPDRIVE_UPSTREAM_COMMAND=bundle exec puma` — command to spawn upstream
|
123
|
+
- `WARPDRIVE_UPSTREAM_ARGS=-p 3000` — arguments for upstream command
|
124
|
+
|
125
|
+
**Advanced Mode** (TOML config):
|
126
|
+
- `WARPDRIVE_CONFIG=/path/to/config.toml` — routing configuration
|
127
|
+
|
128
|
+
See `config.example.toml` for full TOML examples with:
|
129
|
+
- Path transformation (strip_prefix, rewrite)
|
130
|
+
- Load-balanced pools
|
131
|
+
- WebSocket/gRPC routing
|
132
|
+
- Unix domain sockets
|
133
|
+
|
134
|
+
**Deployment Modes:**
|
135
|
+
|
136
|
+
```bash
|
137
|
+
# Mode 1: Memory-only (dev)
|
138
|
+
WARPDRIVE_TARGET_PORT=3000 ./warpdrive
|
139
|
+
|
140
|
+
# Mode 2: + Redis cache (staging)
|
141
|
+
WARPDRIVE_REDIS_URL=redis://localhost:6379 \
|
142
|
+
WARPDRIVE_TARGET_PORT=3000 ./warpdrive
|
143
|
+
|
144
|
+
# Mode 3: Full distributed (production)
|
145
|
+
WARPDRIVE_REDIS_URL=redis://localhost:6379 \
|
146
|
+
WARPDRIVE_DATABASE_URL=postgresql://localhost/warpdrive \
|
147
|
+
WARPDRIVE_METRICS_ENABLED=true \
|
148
|
+
WARPDRIVE_RATE_LIMIT_ENABLED=true \
|
149
|
+
WARPDRIVE_CIRCUIT_BREAKER_ENABLED=true \
|
150
|
+
WARPDRIVE_TARGET_PORT=3000 ./warpdrive
|
151
|
+
```
|
152
|
+
|
153
|
+
### Static File Serving
|
154
|
+
|
155
|
+
WarpDrive can serve static files directly from disk, bypassing your application backend entirely. This is significantly faster than X-Sendfile.
|
156
|
+
|
157
|
+
**Key Differences:**
|
158
|
+
- **Direct Static Serving**: WarpDrive serves files from configured paths (e.g., `/assets/*`) without touching the backend
|
159
|
+
- **X-Sendfile**: Backend returns `X-Sendfile` header, then WarpDrive serves the file
|
160
|
+
- **Performance**: Static serving is 10-100x faster than backend serving, ideal for assets/images/fonts
|
161
|
+
|
162
|
+
**Basic Setup:**
|
163
|
+
```bash
|
164
|
+
# Serve files from ./public directory
|
165
|
+
WARPDRIVE_STATIC_ENABLED=true \
|
166
|
+
WARPDRIVE_STATIC_ROOT=./public \
|
167
|
+
WARPDRIVE_STATIC_PATHS=/assets,/packs,/images,/favicon.ico \
|
168
|
+
./warpdrive
|
169
|
+
```
|
170
|
+
|
171
|
+
**Directory Structure:**
|
172
|
+
```
|
173
|
+
./public/
|
174
|
+
├── assets/
|
175
|
+
│ ├── application.css
|
176
|
+
│ └── application.js
|
177
|
+
├── images/
|
178
|
+
│ ├── logo.png
|
179
|
+
│ └── hero.jpg
|
180
|
+
└── favicon.ico
|
181
|
+
```
|
182
|
+
|
183
|
+
**URL Mapping:**
|
184
|
+
- `GET /assets/application.js` → `./public/assets/application.js`
|
185
|
+
- `GET /images/logo.png` → `./public/images/logo.png`
|
186
|
+
- `GET /favicon.ico` → `./public/favicon.ico`
|
187
|
+
|
188
|
+
**Features:**
|
189
|
+
- **Content-Type Detection**: 28 MIME types (js, css, html, png, svg, woff2, etc.)
|
190
|
+
- **ETag Generation**: `"{size}-{mtime_nanos}"` format for cache validation
|
191
|
+
- **304 Not Modified**: Automatic `If-None-Match` handling
|
192
|
+
- **Gzip Support**: Serves `.gz` files when `Accept-Encoding: gzip` present
|
193
|
+
- **Directory Indexes**: Serves `index.html` for directory requests
|
194
|
+
- **Security**: Directory traversal prevention, hidden file blocking
|
195
|
+
- **Fallthrough**: Continues to backend if file not found (configurable)
|
196
|
+
|
197
|
+
**Environment Variables:**
|
198
|
+
```bash
|
199
|
+
WARPDRIVE_STATIC_ENABLED=true # Enable/disable (default: true)
|
200
|
+
WARPDRIVE_STATIC_ROOT=./public # Root directory (default: ./public)
|
201
|
+
WARPDRIVE_STATIC_PATHS=/assets,/packs # URL prefixes (default: /assets,/packs,/images,/favicon.ico)
|
202
|
+
WARPDRIVE_STATIC_CACHE_CONTROL="public, max-age=31536000, immutable" # Cache header
|
203
|
+
WARPDRIVE_STATIC_GZIP=true # Serve .gz files (default: true)
|
204
|
+
WARPDRIVE_STATIC_INDEX_FILES=index.html # Directory indexes (default: index.html)
|
205
|
+
WARPDRIVE_STATIC_FALLTHROUGH=true # Pass to backend if not found (default: true)
|
206
|
+
```
|
207
|
+
|
208
|
+
**Example Responses:**
|
209
|
+
```bash
|
210
|
+
# JavaScript with ETag and caching
|
211
|
+
$ curl -I http://localhost/assets/app.js
|
212
|
+
HTTP/1.1 200 OK
|
213
|
+
Content-Type: application/javascript
|
214
|
+
Content-Length: 1024
|
215
|
+
Cache-Control: public, max-age=31536000, immutable
|
216
|
+
ETag: "1024-1759606090065974032"
|
217
|
+
|
218
|
+
# 304 Not Modified on subsequent request
|
219
|
+
$ curl -I -H 'If-None-Match: "1024-1759606090065974032"' http://localhost/assets/app.js
|
220
|
+
HTTP/1.1 304 Not Modified
|
221
|
+
ETag: "1024-1759606090065974032"
|
222
|
+
Cache-Control: public, max-age=31536000, immutable
|
223
|
+
```
|
224
|
+
|
225
|
+
**Performance:**
|
226
|
+
- **Sequential**: ~100 req/s (single curl loop)
|
227
|
+
- **Concurrent**: 600+ req/s (500 parallel requests)
|
228
|
+
- **Latency**: Sub-millisecond for cached files
|
229
|
+
- **No backend overhead**: Rails/app server never touched
|
230
|
+
|
231
|
+
**Production Tips:**
|
232
|
+
- Use CDN for hot assets (CloudFlare, Fastly) for global distribution
|
233
|
+
- Enable gzip pre-compression: `gzip -k public/assets/*.{js,css}`
|
234
|
+
- Set long cache TTL: files are immutable with content hashing
|
235
|
+
- Monitor with Prometheus: `static_files_served_total` metric (future)
|
236
|
+
|
237
|
+
### TLS & ACME Configuration
|
238
|
+
|
239
|
+
WarpDrive supports TLS/HTTPS in three ways:
|
240
|
+
|
241
|
+
**1. Manual Certificates** (self-signed or custom):
|
242
|
+
```bash
|
243
|
+
# Self-signed certificate (development)
|
244
|
+
openssl req -x509 -newkey rsa:4096 -nodes \
|
245
|
+
-keyout server.key -out server.crt -days 365 \
|
246
|
+
-subj "/CN=localhost"
|
247
|
+
|
248
|
+
WARPDRIVE_TLS_CERT_PATH=server.crt \
|
249
|
+
WARPDRIVE_TLS_KEY_PATH=server.key \
|
250
|
+
WARPDRIVE_HTTPS_PORT=443 \
|
251
|
+
./warpdrive
|
252
|
+
```
|
253
|
+
|
254
|
+
**2. ACME/Let's Encrypt** (automatic certificates):
|
255
|
+
```bash
|
256
|
+
# Production with automatic Let's Encrypt certificates
|
257
|
+
WARPDRIVE_TLS_DOMAINS=example.com,www.example.com \
|
258
|
+
WARPDRIVE_STORAGE_PATH=/var/lib/warpdrive \
|
259
|
+
WARPDRIVE_HTTP_PORT=80 \
|
260
|
+
WARPDRIVE_HTTPS_PORT=443 \
|
261
|
+
./warpdrive
|
262
|
+
```
|
263
|
+
|
264
|
+
**Environment Variables:**
|
265
|
+
- `WARPDRIVE_TLS_DOMAINS=domain1.com,domain2.com` — domains for ACME certificates
|
266
|
+
- `WARPDRIVE_STORAGE_PATH=/var/lib/warpdrive` — certificate storage directory
|
267
|
+
- `WARPDRIVE_ACME_DIRECTORY=https://acme-v02.api.letsencrypt.org/directory` — ACME server URL
|
268
|
+
- `WARPDRIVE_EAB_KID=...` — External Account Binding key ID (optional, for some CAs)
|
269
|
+
- `WARPDRIVE_EAB_HMAC_KEY=...` — EAB HMAC key (optional)
|
270
|
+
|
271
|
+
**ACME Workflow:**
|
272
|
+
1. WarpDrive provisions certificates on startup for all `TLS_DOMAINS`
|
273
|
+
2. HTTP-01 challenges handled at `/.well-known/acme-challenge/*`
|
274
|
+
3. Certificates stored in `{STORAGE_PATH}/certs/{domain}.pem`
|
275
|
+
4. Private keys stored with 0600 permissions
|
276
|
+
5. HTTPS listener starts with provisioned certificates
|
277
|
+
|
278
|
+
**Certificate Storage Layout:**
|
279
|
+
```
|
280
|
+
/var/lib/warpdrive/
|
281
|
+
├── account.json # ACME account credentials
|
282
|
+
└── certs/
|
283
|
+
├── example.com.pem # Certificate chain
|
284
|
+
├── example.com.key.pem # Private key
|
285
|
+
├── www.example.com.pem
|
286
|
+
└── www.example.com.key.pem
|
287
|
+
```
|
288
|
+
|
289
|
+
**3. Docker with TLS** (self-signed generation):
|
290
|
+
```bash
|
291
|
+
# Docker automatically generates self-signed cert at build time
|
292
|
+
docker run -p 80:80 -p 443:443 \
|
293
|
+
-e WARPDRIVE_TARGET_PORT=3000 \
|
294
|
+
warpdrive
|
295
|
+
```
|
296
|
+
|
297
|
+
**Let's Encrypt Staging** (testing):
|
298
|
+
```bash
|
299
|
+
# Use staging server for testing (avoids rate limits)
|
300
|
+
WARPDRIVE_TLS_DOMAINS=test.example.com \
|
301
|
+
WARPDRIVE_ACME_DIRECTORY=https://acme-staging-v02.api.letsencrypt.org/directory \
|
302
|
+
WARPDRIVE_STORAGE_PATH=/tmp/warpdrive \
|
303
|
+
./warpdrive
|
304
|
+
```
|
305
|
+
|
306
|
+
**Protocol Support:**
|
307
|
+
- HTTP/1.1 and HTTP/2 (automatic via ALPN)
|
308
|
+
- WebSocket over TLS (wss://)
|
309
|
+
- HTTP/3/QUIC (tracked, blocked on Pingora support)
|
310
|
+
|
311
|
+
### Docker
|
312
|
+
|
313
|
+
Run WarpDrive with Puma and Falcon backends:
|
314
|
+
|
315
|
+
```bash
|
316
|
+
docker-compose up warpdrive
|
317
|
+
```
|
318
|
+
|
319
|
+
Test routing:
|
320
|
+
```bash
|
321
|
+
curl http://localhost:8080/ # → Puma
|
322
|
+
curl http://localhost:8080/puma/test # → Puma (/test)
|
323
|
+
curl http://localhost:8080/falcon/test # → Falcon (/test)
|
324
|
+
```
|
325
|
+
|
326
|
+
See `DOCKER.md` for details.
|
327
|
+
|
328
|
+
### Tests
|
329
|
+
|
330
|
+
**Quick Start** (Docker Compose with PostgreSQL and Redis):
|
331
|
+
```bash
|
332
|
+
# Run all tests in isolated environment
|
333
|
+
docker-compose up --build test
|
334
|
+
```
|
335
|
+
|
336
|
+
**Local Development:**
|
337
|
+
```bash
|
338
|
+
# Start services
|
339
|
+
docker-compose up -d postgres redis
|
340
|
+
|
341
|
+
# Run tests
|
342
|
+
export WARPDRIVE_DATABASE_URL=postgresql://warpdrive:warpdrive_test@localhost:5432/warpdrive_test
|
343
|
+
export WARPDRIVE_REDIS_URL=redis://localhost:6379
|
344
|
+
cargo test --workspace --all-features
|
345
|
+
```
|
346
|
+
|
347
|
+
**Test Categories:**
|
348
|
+
```bash
|
349
|
+
# Unit tests only
|
350
|
+
cargo test --lib
|
351
|
+
|
352
|
+
# Integration tests
|
353
|
+
cargo test --test '*'
|
354
|
+
|
355
|
+
# Specific test suites
|
356
|
+
cargo test --lib cache
|
357
|
+
cargo test --test redis_test
|
358
|
+
cargo test --test postgres_test
|
359
|
+
```
|
360
|
+
|
361
|
+
See [`TESTING.md`](TESTING.md) for comprehensive testing guide including:
|
362
|
+
- Docker Compose test setup
|
363
|
+
- CI/CD configuration examples
|
364
|
+
- Coverage reports
|
365
|
+
- Troubleshooting guide
|
366
|
+
|
367
|
+
### Environment Variables Reference
|
368
|
+
|
369
|
+
**Complete list of all configuration options:**
|
370
|
+
|
371
|
+
```bash
|
372
|
+
# Core Proxy
|
373
|
+
WARPDRIVE_TARGET_HOST=127.0.0.1 # Upstream host (simple mode)
|
374
|
+
WARPDRIVE_TARGET_PORT=3000 # Upstream port (simple mode)
|
375
|
+
WARPDRIVE_HTTP_PORT=80 # HTTP listener port
|
376
|
+
WARPDRIVE_HTTPS_PORT=443 # HTTPS listener port
|
377
|
+
|
378
|
+
# TLS & ACME
|
379
|
+
WARPDRIVE_TLS_DOMAINS=example.com,www.example.com # ACME domains (comma-separated)
|
380
|
+
WARPDRIVE_TLS_CERT_PATH=/path/to/cert.pem # Manual certificate path
|
381
|
+
WARPDRIVE_TLS_KEY_PATH=/path/to/key.pem # Manual key path
|
382
|
+
WARPDRIVE_STORAGE_PATH=/var/lib/warpdrive # Certificate storage directory
|
383
|
+
WARPDRIVE_ACME_DIRECTORY=https://... # ACME server URL
|
384
|
+
WARPDRIVE_EAB_KID=... # External Account Binding key ID
|
385
|
+
WARPDRIVE_EAB_HMAC_KEY=... # External Account Binding HMAC key
|
386
|
+
|
387
|
+
# Caching
|
388
|
+
WARPDRIVE_CACHE_SIZE=67108864 # Memory cache size in bytes (64MB)
|
389
|
+
WARPDRIVE_MAX_CACHE_ITEM_SIZE=1048576 # Max item size in bytes (1MB)
|
390
|
+
WARPDRIVE_REDIS_URL=redis://localhost:6379 # Redis L2 cache (optional)
|
391
|
+
WARPDRIVE_DATABASE_URL=postgresql://... # PostgreSQL for invalidation (optional)
|
392
|
+
|
393
|
+
# Observability
|
394
|
+
WARPDRIVE_METRICS_ENABLED=true # Enable Prometheus metrics
|
395
|
+
WARPDRIVE_METRICS_PORT=9090 # Metrics server port
|
396
|
+
WARPDRIVE_LOG_LEVEL=info # Log level (error/warn/info/debug/trace)
|
397
|
+
WARPDRIVE_LOG_REQUESTS=true # Log all HTTP requests
|
398
|
+
|
399
|
+
# Resilience
|
400
|
+
WARPDRIVE_RATE_LIMIT_ENABLED=true # Enable per-IP rate limiting
|
401
|
+
WARPDRIVE_RATE_LIMIT_RPS=100 # Requests per second per IP
|
402
|
+
WARPDRIVE_RATE_LIMIT_BURST=200 # Burst size (tokens)
|
403
|
+
WARPDRIVE_CIRCUIT_BREAKER_ENABLED=true # Enable circuit breaker
|
404
|
+
WARPDRIVE_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5 # Failures before opening
|
405
|
+
WARPDRIVE_CIRCUIT_BREAKER_TIMEOUT_SECS=60 # Seconds before retry
|
406
|
+
WARPDRIVE_MAX_CONCURRENT_REQUESTS=0 # Max concurrent requests (0 = unlimited)
|
407
|
+
WARPDRIVE_UPSTREAM_TIMEOUT=30 # Upstream request timeout in seconds
|
408
|
+
|
409
|
+
# Headers & Middleware
|
410
|
+
WARPDRIVE_FORWARD_HEADERS=true # Add X-Forwarded-* headers
|
411
|
+
WARPDRIVE_X_SENDFILE_ENABLED=true # Enable X-Sendfile support
|
412
|
+
WARPDRIVE_GZIP_COMPRESSION_ENABLED=true # Enable gzip compression
|
413
|
+
|
414
|
+
# Static File Serving
|
415
|
+
WARPDRIVE_STATIC_ENABLED=true # Enable direct static file serving
|
416
|
+
WARPDRIVE_STATIC_ROOT=./public # Static files directory
|
417
|
+
WARPDRIVE_STATIC_PATHS=/assets,/packs,/images,/favicon.ico # URL paths to serve
|
418
|
+
WARPDRIVE_STATIC_CACHE_CONTROL="public, max-age=31536000, immutable" # Cache header
|
419
|
+
WARPDRIVE_STATIC_GZIP=true # Serve .gz files when available
|
420
|
+
WARPDRIVE_STATIC_INDEX_FILES=index.html # Directory index files
|
421
|
+
WARPDRIVE_STATIC_FALLTHROUGH=true # Continue to backend if file not found
|
422
|
+
|
423
|
+
# Advanced (TOML Mode)
|
424
|
+
WARPDRIVE_CONFIG=/path/to/config.toml # TOML routing config
|
425
|
+
|
426
|
+
# Process Supervision
|
427
|
+
WARPDRIVE_UPSTREAM_COMMAND=bundle exec puma # Command to spawn
|
428
|
+
WARPDRIVE_UPSTREAM_ARGS=-p 3000 # Command arguments
|
429
|
+
```
|
430
|
+
|
431
|
+
### Prometheus Metrics
|
432
|
+
|
433
|
+
WarpDrive exposes Prometheus metrics at `/metrics` on the configured port (default 9090).
|
434
|
+
|
435
|
+
**HTTP Metrics:**
|
436
|
+
- `http_requests_total{method, status}` — Total HTTP requests (counter)
|
437
|
+
- `http_request_duration_seconds{method, status}` — Request duration histogram (0.001s to 60s buckets)
|
438
|
+
- `http_requests_active` — Currently active requests (gauge)
|
439
|
+
|
440
|
+
**Cache Metrics:**
|
441
|
+
- `cache_hits_total{backend}` — Cache hits by backend (memory/redis)
|
442
|
+
- `cache_misses_total{backend}` — Cache misses by backend
|
443
|
+
- `cache_invalidations_total` — PostgreSQL NOTIFY invalidations received
|
444
|
+
- `cache_errors_total{backend, operation}` — Cache operation errors
|
445
|
+
|
446
|
+
**Circuit Breaker Metrics:**
|
447
|
+
- `circuit_breaker_state{state}` — Current state (closed/open/half_open) (gauge)
|
448
|
+
- `circuit_breaker_failures_total` — Total failures detected
|
449
|
+
- `circuit_breaker_state_changes_total{from, to}` — State transitions
|
450
|
+
|
451
|
+
**Rate Limiting Metrics:**
|
452
|
+
- `rate_limit_requests_allowed_total` — Requests allowed through
|
453
|
+
- `rate_limit_requests_denied_total` — Requests rate-limited (429 responses)
|
454
|
+
|
455
|
+
**Example Prometheus Queries:**
|
456
|
+
```promql
|
457
|
+
# Request rate by status code
|
458
|
+
rate(http_requests_total[5m])
|
459
|
+
|
460
|
+
# 95th percentile response time
|
461
|
+
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
|
462
|
+
|
463
|
+
# Cache hit ratio
|
464
|
+
sum(rate(cache_hits_total[5m])) / (sum(rate(cache_hits_total[5m])) + sum(rate(cache_misses_total[5m])))
|
465
|
+
|
466
|
+
# Circuit breaker state (1=open, 0=closed)
|
467
|
+
circuit_breaker_state{state="open"}
|
468
|
+
|
469
|
+
# Rate limit rejection rate
|
470
|
+
rate(rate_limit_requests_denied_total[5m])
|
471
|
+
```
|
472
|
+
|
473
|
+
**Grafana Dashboard:**
|
474
|
+
```json
|
475
|
+
{
|
476
|
+
"dashboard": {
|
477
|
+
"title": "WarpDrive Proxy",
|
478
|
+
"panels": [
|
479
|
+
{
|
480
|
+
"title": "Request Rate",
|
481
|
+
"targets": [{"expr": "rate(http_requests_total[5m])"}]
|
482
|
+
},
|
483
|
+
{
|
484
|
+
"title": "Cache Hit Ratio",
|
485
|
+
"targets": [{"expr": "sum(rate(cache_hits_total[5m])) / (sum(rate(cache_hits_total[5m])) + sum(rate(cache_misses_total[5m])))"}]
|
486
|
+
},
|
487
|
+
{
|
488
|
+
"title": "Circuit Breaker State",
|
489
|
+
"targets": [{"expr": "circuit_breaker_state"}]
|
490
|
+
}
|
491
|
+
]
|
492
|
+
}
|
493
|
+
}
|
494
|
+
```
|
495
|
+
|
496
|
+
## Architecture
|
497
|
+
|
498
|
+
- **Proxy Handler** (`src/proxy/handler.rs`): Pingora ProxyHttp implementation
|
499
|
+
- **Router** (`src/router/`): Multi-upstream routing with LoadBalancer
|
500
|
+
- **Middleware** (`src/middleware/`): Request/response filtering chain
|
501
|
+
- **Cache** (`src/cache/`): L1 (Memory) + L2 (Redis) coordinator with PG invalidation
|
502
|
+
- **Metrics** (`src/metrics/`): Prometheus instrumentation
|
503
|
+
- **Config** (`src/config/`): Env vars and TOML parsing
|
504
|
+
- **Process** (`src/process/`): Upstream supervisor
|
505
|
+
|
506
|
+
**Documentation:**
|
507
|
+
- `docs/ARCHITECTURE.md` — System architecture, request lifecycle, deployment modes
|
508
|
+
- `ROUTING.md` — Multi-upstream routing details
|
509
|
+
- `MASTER_PLAN.md` — Development roadmap and current status
|
510
|
+
|
511
|
+
## License
|
512
|
+
|
513
|
+
Licensed under the [MIT License](LICENSE).
|
data/bin/warpdrive
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Find the platform-specific binary
|
5
|
+
gem_root = File.expand_path("..", __dir__)
|
6
|
+
platform = Gem::Platform.local.to_s
|
7
|
+
|
8
|
+
# Map gem platform to binary suffix
|
9
|
+
binary_suffix = case platform
|
10
|
+
when /arm64-darwin/
|
11
|
+
"aarch64-apple-darwin"
|
12
|
+
when /x86_64-darwin/
|
13
|
+
"x86_64-apple-darwin"
|
14
|
+
when /x86_64-linux/
|
15
|
+
"x86_64-unknown-linux-gnu"
|
16
|
+
when /aarch64-linux/
|
17
|
+
"aarch64-unknown-linux-gnu"
|
18
|
+
when /x86_64-freebsd/
|
19
|
+
"x86_64-unknown-freebsd"
|
20
|
+
else
|
21
|
+
abort "Unsupported platform: #{platform}"
|
22
|
+
end
|
23
|
+
|
24
|
+
binary = File.join(gem_root, "exe", "warpdrive-#{binary_suffix}")
|
25
|
+
|
26
|
+
unless File.executable?(binary)
|
27
|
+
abort "Binary not found: #{binary}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Execute the binary
|
31
|
+
exec(binary, *ARGV)
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: warpdrive-proxy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: x86_64-freebsd
|
6
|
+
authors:
|
7
|
+
- Seuros
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
description: |
|
13
|
+
WarpDrive is a high-performance reverse proxy built on Pingora
|
14
|
+
(Cloudflare's Rust proxy framework). This gem provides pre-compiled
|
15
|
+
binaries for FreeBSD x86_64.
|
16
|
+
email:
|
17
|
+
- seuros@users.noreply.github.com
|
18
|
+
executables:
|
19
|
+
- warpdrive
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- bin/warpdrive
|
26
|
+
- exe/warpdrive-x86_64-unknown-freebsd
|
27
|
+
homepage: https://github.com/seuros/warpdrive
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata:
|
31
|
+
homepage_uri: https://github.com/seuros/warpdrive
|
32
|
+
source_code_uri: https://github.com/seuros/warpdrive
|
33
|
+
changelog_uri: https://github.com/seuros/warpdrive/blob/main/CHANGELOG.md
|
34
|
+
bug_tracker_uri: https://github.com/seuros/warpdrive/issues
|
35
|
+
documentation_uri: https://github.com/seuros/warpdrive/blob/main/README.md
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.6.0
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubygems_version: 3.6.9
|
51
|
+
specification_version: 4
|
52
|
+
summary: High-performance reverse proxy built on Cloudflare's Pingora
|
53
|
+
test_files: []
|