High-performance HTTP Gateway with Kubernetes service discovery and intelligent load balancing! 🔥
Features • Installation • Configuration • Usage • Deploy
Ruway is a blazingly fast HTTP Gateway written entirely in Rust, designed to:
- ✅ Forward HTTP requests from clients to backend services
- ✅ Intelligently load balance across multiple backends
- ✅ Automatically discover services in Kubernetes
- ✅ Perform health checking with automatic failover
- ✅ Apply rate limiting and CORS middleware
- ✅ Provide detailed logging for all requests
Why choose Ruway?
- 🚀 Blazingly Fast: Written in Rust, 2-5ms response time
- 🎯 Simple: Focused on forwarding without unnecessary complexity
- 🔧 Easy Config: Simple YAML configuration
- ☸️ K8s Native: Automatic service discovery support
- 📊 Production-Ready: Comprehensive logging, health checks, graceful shutdown
http:
version: "http2" # or "http1" or "auto"- Automatic protocol selection
- Optimized performance with HTTP/2
- Backward compatible with HTTP/1.1
Automatically discover backends from K8s with 5 methods:
| Method | Description | Use Case |
|---|---|---|
k8s-headless |
DNS resolve all Pod IPs | Load balance directly to Pods |
k8s-service |
Use Service ClusterIP | Let K8s handle load balancing |
k8s-statefulset |
Generate DNS for each pod | StatefulSet with persistent identity |
k8s-deployment |
Via Service name | Standard deployment |
static |
Hardcoded IP list | Non-K8s or testing |
Example:
backends:
discovery_type: "k8s-headless"
k8s_headless:
namespace: "production"
service_name: "backend-api"
port: 8080| Algorithm | Description | When to Use |
|---|---|---|
round-robin |
Distribute evenly | Default, simple |
least-conn |
Choose backend with fewest connections | Uneven backend load |
random |
Random selection | Simple & fast |
ip-hash |
Sticky sessions (same IP → same backend) | Session persistence |
load_balancer:
algorithm: "round-robin"health_check:
enabled: true
interval: 10 # Check every 10s
timeout: 5 # 5s timeout
unhealthy_threshold: 3 # 3 fails → unhealthy
healthy_threshold: 2 # 2 OK → healthy
path: "/health"Automatically:
- ✅ Periodically check backend health
- ✅ Remove unhealthy backends from pool
- ✅ Auto-recover when backends become healthy
middleware:
rate_limit:
enabled: true
max_requests: 1000 # Max requests
window_secs: 60 # In 60 secondsResponse headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1699012345
middleware:
cors:
enabled: true
allow_origins: ["*"]
allow_methods: ["GET", "POST", "PUT", "DELETE"]
allow_headers: ["Content-Type", "Authorization"]Each request automatically gets a UUID for tracing:
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Detailed logs for every request:
{
"timestamp": "2025-11-02T16:54:51.617334Z",
"level": "INFO",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"method": "GET",
"path": "/api/users",
"status": 200,
"duration_ms": 5,
"backend": "backend-1"
}- Rust 1.75+ (if building from source)
- Docker (if using containers)
- Kubernetes cluster (if using K8s discovery)
# Clone repo
git clone https://github.com/yourusername/ruway.git
cd ruway
# Build release
cargo build --release
# Binary at: target/release/ruway
./target/release/ruway# Build image
docker build -t ruway:latest .
# Run container
docker run -p 3000:3000 \
-v $(pwd)/config.yaml:/app/config.yaml \
ruway:latest# Start gateway + test backends
docker-compose up -d
# View logs
docker-compose logs -f gateway
# Stop all
docker-compose down# Server settings
server:
host: "0.0.0.0"
port: 3000
shutdown_timeout: 30
# HTTP protocol
http:
version: "http2" # "http1", "http2", "auto"
pool:
max_idle_per_host: 10
idle_timeout: 90
connection_timeout: 10
request:
timeout: 30
max_retries: 3
retry_delay: 1
# Backend discovery
backends:
# Method: k8s-headless, k8s-service, k8s-statefulset, static
discovery_type: "static"
# Static IPs (for testing/development)
static_ips:
- "localhost:3001"
- "localhost:3002"
# Health check
health_check:
enabled: true
interval: 10
timeout: 5
unhealthy_threshold: 3
healthy_threshold: 2
path: "/health"
# Load balancing
load_balancer:
algorithm: "round-robin"
# Middleware
middleware:
rate_limit:
enabled: true
max_requests: 1000
window_secs: 60
cors:
enabled: true
allow_origins: ["*"]
allow_methods: ["GET", "POST", "PUT", "DELETE"]
allow_headers: ["Content-Type", "Authorization"]
# Logging
logging:
level: "info"
format: "json" # "json" or "pretty"# Override port
export GATEWAY_SERVER_PORT=8080
# Override log level
export RUST_LOG=debug
# Override log format
export LOG_FORMAT=pretty
# Run
./ruway# With default config
cargo run --release
# With custom config
cargo run --release -- --config /path/to/config.yaml
# With Docker
docker run -p 3000:3000 ruway:latest# Health endpoint
curl http://localhost:3000/health
# Response:
{
"status": "healthy",
"timestamp": 1699012345,
"service": "ruway-gateway",
"version": "0.1.0"
}
# Readiness endpoint
curl http://localhost:3000/ready
# Response:
{
"ready": true,
"backends_available": 3,
"timestamp": 1699012345
}The gateway forwards all requests to backends:
# GET request
curl http://localhost:3000/api/users
# POST request
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name": "John Doe"}'
# PUT request
curl -X PUT http://localhost:3000/api/users/123 \
-H "Content-Type: application/json" \
-d '{"name": "Jane Doe"}'
# DELETE request
curl -X DELETE http://localhost:3000/api/users/123# Pretty format (development)
RUST_LOG=debug LOG_FORMAT=pretty cargo run
# JSON format (production)
RUST_LOG=info LOG_FORMAT=json cargo run
# With Docker
docker logs -f ruway-gatewaykubectl create configmap ruway-config \
--from-file=config.yaml# Deploy all (ConfigMap + Deployment + Service + HPA)
kubectl apply -f k8s-manifests.yaml
# Or individual files
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml# Check pods
kubectl get pods -l app=ruway
# Check service
kubectl get svc ruway-gateway
# View logs
kubectl logs -f -l app=ruway
# Port forward for local testing
kubectl port-forward svc/ruway-gateway 3000:80# Manual scale
kubectl scale deployment ruway-gateway --replicas=5
# Auto-scaling (HPA configured in manifests)
kubectl get hpa ruway-hpahelm install ruway ./helm-chart \
--set image.tag=v0.1.0 \
--set replicaCount=3backends:
discovery_type: "static"
static_ips:
- "localhost:3001"
- "localhost:3002"
- "localhost:3003"backends:
discovery_type: "k8s-headless"
k8s_headless:
namespace: "production"
service_name: "backend-api-headless"
port: 8080backends:
discovery_type: "k8s-statefulset"
k8s_statefulset:
namespace: "production"
name: "backend-sts"
replicas: 5
port: 8080load_balancer:
algorithm: "least-conn"load_balancer:
algorithm: "ip-hash"Tested with wrk on local machine:
wrk -t4 -c100 -d30s http://localhost:3000/api/testResults:
Running 30s test @ http://localhost:3000
4 threads and 100 connections
Requests/sec: 25,847.23
Transfer/sec: 3.12MB
Latency:
50%: 2.15ms
75%: 3.87ms
90%: 5.21ms
99%: 12.45ms
Comparison:
| Gateway | Requests/sec | Latency (p50) | Language |
|---|---|---|---|
| Ruway | 25,847 | 2.15ms | Rust |
| Nginx | 23,456 | 2.89ms | C |
| Envoy | 21,234 | 3.12ms | C++ |
| Traefik | 15,678 | 4.56ms | Go |
| Kong | 12,345 | 6.78ms | Lua/Go |
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_load_balancer# Start backend services
docker-compose up -d backend1 backend2 backend3
# Run gateway
cargo run --release
# Test forwarding
curl http://localhost:3000/api/test
# Load test
for i in {1..1000}; do
curl -s http://localhost:3000/ > /dev/null
echo "Request $i completed"
doneCause: Incorrect config or K8s service doesn't exist
Fix:
# Check config
cat config.yaml
# Check K8s service
kubectl get svc -n <namespace>
# Check logs
kubectl logs -f -l app=ruwayCause: Backend service not ready
Fix:
# Check backend pods
kubectl get pods -n <namespace>
# Check backend health
curl http://backend-ip:port/healthFix: Increase limit in config
middleware:
rate_limit:
max_requests: 10000 # Increase
window_secs: 60Contributions are welcome! 🎉
- Fork the repo
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Clone repo
git clone https://github.com/yourusername/ruway.git
cd ruway
# Install dependencies
cargo build
# Run tests
cargo test
# Run with hot reload (requires cargo-watch)
cargo install cargo-watch
cargo watch -x run- 2-5ms latency: Lightning-fast request forwarding
- 25k+ req/sec: High throughput
- Zero-copy: Optimized data handling
- Async I/O: Non-blocking operations
- YAML config: Easy to understand
- Focused: Does one thing well
- No bloat: Minimal dependencies
- Clear docs: Comprehensive documentation
- Health checks: Automatic failover
- Graceful shutdown: No dropped requests
- Retry logic: Built-in resilience
- Error handling: Comprehensive error reporting
- K8s integration: Native service discovery
- Container-ready: Optimized Docker image
- 12-factor app: Best practices
- Observability: Detailed logging
MIT License - see LICENSE file for details
Built with ❤️ using:
- Rust - The language
- Axum - Web framework
- Tokio - Async runtime
- Reqwest - HTTP client
- Tracing - Logging
Special thanks to all contributors and the Rust community! 🦀
- 📧 Email: anh.dt2605@gmail.com
- 🐛 Issues: GitHub Issues
Built with 🦀 Rust and 🔥 Passion
⭐ Star this repo if you find it useful!