A zero-dependency, ultra-high-performance rate-limited reverse proxy written in pure Go.
- About
- Key Features
- Architecture
- Tech Stack
- Getting Started
- Configuration
- Response Examples
- Project Structure
- Contributing
- License
ProxyGate is an enterprise-grade, lightweight HTTP Reverse Proxy with an integrated per-IP Rate Limiter designed to protect web applications, microservices, and APIs from traffic spikes and malicious abuse.
Built exclusively with the Go Standard Library, ProxyGate provides exceptional throughput and minimal latency without introducing bloat or third-party dependency vulnerabilities. It seamlessly intercepts incoming HTTP traffic, enforces dynamic rate limits based on client IP addresses, attaches standardized RFC-compliant rate limiting headers, and forwards legitimate requests to target upstream servers.
Whether deployed as a sidecar proxy, API gateway fronting internal services, or standalone rate limiting buffer behind load balancers like Cloudflare or NGINX, ProxyGate provides robust protection and precise control over incoming server traffic.
- ⚡ Token Bucket Algorithm — Highly accurate, nanosecond-precision dynamic token refills using lazy evaluation logic.
- 📦 Zero External Dependencies — Engineered using 100% Go standard library (
net/http,net/http/httputil,sync,time) for maximum stability and speed. - 🔒 IP Security & Proxy Whitelisting — Prevents IP spoofing using
RemoteAddrverification while offering optional trusted headers parsing (X-Forwarded-For/X-Real-IP). - 🧹 Automatic Bucket Eviction — Built-in background Garbage Collector goroutine that automatically cleans up stale, inactive client buckets to optimize memory usage.
- 🚨 Upstream Fault Tolerance — Captures upstream server failures gracefully and returns formatted JSON
502 Bad Gatewayresponses. - 🛑 Graceful Shutdown — Handles
SIGINT/SIGTERMsignals safely by completing ongoing request streams before shutting down. - 📊 Standardized HTTP Headers — Automatically sets
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset, andRetry-Afteron HTTP responses.
[ Client Request ]
│
▼
[ ProxyGate Server ]
│
├───> 1. Extract Client IP (RemoteAddr / X-Forwarded-For)
│
├───> 2. Query Rate Limiter (Token Bucket Algorithm)
│ │
│ ├───> [ Refill Tokens based on elapsed time ]
│ │
│ ├─── [ Tokens available? ]
│ │ │
│ │ ├── NO ───> [ Return 429 Too Many Requests ]
│ │ │ (Set Headers: Retry-After, X-RateLimit-*)
│ │ │
│ │ └── YES ───> [ Consume 1 Token & Continue ]
│
└───> 3. Forward Request to Target Upstream Server
│
└───> [ Relay Response Back to Client ]
- Go: Version 1.20 or higher.
Clone the repository to your local machine:
git clone https://github.com/semjhaydin/ProxyGate.git
cd ProxyGateYou can run ProxyGate directly from source:
# Run with default configuration
go run main.go
# Run with a custom configuration file
go run main.go -config config.jsonOr compile it into a standalone binary:
# Build executable
go build -o proxygate main.go
# Execute binary
./proxygateExecute all unit and integration tests across packages:
go test ./... -vTo run concurrency tests with Go's built-in data race detector:
go test ./... -v -raceProxyGate is configured via config.json at the root directory:
{
"server": {
"port": 8000,
"target_upstream": "http://127.0.0.1:5000",
"trust_proxy_headers": false
},
"rate_limiter": {
"capacity": 20,
"refill_rate_per_sec": 2.0,
"cleanup_interval_sec": 300,
"bucket_ttl_sec": 600,
"ip_whitelist": [
"127.0.0.1",
"192.168.1.100"
]
}
}| Parameter | Type | Description |
|---|---|---|
server.port |
int |
Port number on which the proxy server listens (e.g., 8000). |
server.target_upstream |
string |
Target upstream URL where valid requests are forwarded (e.g., http://127.0.0.1:5000). |
server.trust_proxy_headers |
bool |
Set to true to extract real client IPs from X-Forwarded-For when behind load balancers or Cloudflare. |
rate_limiter.capacity |
float64 |
Maximum token capacity per bucket (burst size). |
rate_limiter.refill_rate_per_sec |
float64 |
Token refill rate per second (e.g., 2.0 = 2 tokens refill per second). |
rate_limiter.cleanup_interval_sec |
float64 |
Interval in seconds for running the background bucket memory garbage collector. |
rate_limiter.bucket_ttl_sec |
int |
Time-to-live in seconds for inactive client buckets before eviction. |
rate_limiter.ip_whitelist |
[]string |
List of IP addresses exempt from rate limiting restrictions. |
HTTP/1.1 200 OK
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 19
X-RateLimit-Reset: 1724275000
Via: 1.1 rate-limited-proxyHTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 1
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1724275010
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Try again in 1 seconds."
}HTTP/1.1 502 Bad Gateway
Content-Type: application/json
{
"error": "Bad Gateway",
"message": "Upstream service unavailable"
}.
├── config.json # Configuration parameters for server and rate limiter
├── main.go # Core application entrypoint and signal handling
├── config/
│ └── config.go # Config parser and validation logic
├── limiter/
│ ├── bucket.go # Token Bucket core data structure and lazy refill logic
│ ├── store.go # Thread-safe in-memory bucket store
│ ├── cleaner.go # Background memory eviction worker
│ ├── bucket_test.go # Bucket unit tests
│ └── store_test.go # Store unit tests
├── middleware/
│ ├── limiter_mw.go # HTTP middleware interceptor
│ └── limiter_mw_test.go # Middleware integration tests
└── proxy/
├── reverse_proxy.go # HTTP Reverse Proxy core and error handling
└── reverse_proxy_test.go # Proxy unit tests
Contributions are welcome! Follow these steps to contribute:
- Fork the repository.
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'feat: add amazing feature' - Push to your branch:
git push origin feature/amazing-feature - Open a Pull Request.
For bugs and feature requests, please check the Issues page.
This project is open-source software licensed under the MIT License.