Skip to content
semih-aydinPublic

About

High-performance, zero-dependency reverse proxy server in Go with built-in Token Bucket rate limiting and low-latency request routing.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

🛡️ ProxyGate

A zero-dependency, ultra-high-performance rate-limited reverse proxy written in pure Go.

GitHub Stars License Language


📋 Table of Contents


ℹ️ About

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.


✨ Key Features

  • ⚡ 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 RemoteAddr verification 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 Gateway responses.
  • 🛑 Graceful Shutdown — Handles SIGINT / SIGTERM signals safely by completing ongoing request streams before shutting down.
  • 📊 Standardized HTTP Headers — Automatically sets X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After on HTTP responses.

🏗️ Architecture

[ 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 ]

💻 Tech Stack

Go JSON


🚀 Getting Started

Prerequisites

  • Go: Version 1.20 or higher.

Installation

Clone the repository to your local machine:

git clone https://github.com/semjhaydin/ProxyGate.git
cd ProxyGate

Running the Proxy

You 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.json

Or compile it into a standalone binary:

# Build executable
go build -o proxygate main.go

# Execute binary
./proxygate

Running Tests

Execute all unit and integration tests across packages:

go test ./... -v

To run concurrency tests with Go's built-in data race detector:

go test ./... -v -race

⚙️ Configuration

ProxyGate 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"
    ]
  }
}

Options Reference

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.

📩 Response Examples

1. Successful Request (200 OK)

HTTP/1.1 200 OK
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 19
X-RateLimit-Reset: 1724275000
Via: 1.1 rate-limited-proxy

2. Rate Limit Exceeded (429 Too Many Requests)

HTTP/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."
}

3. Upstream Unavailable (502 Bad Gateway)

HTTP/1.1 502 Bad Gateway
Content-Type: application/json

{
  "error": "Bad Gateway",
  "message": "Upstream service unavailable"
}

📁 Project Structure

.
├── 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

🤝 Contributing

Contributions are welcome! Follow these steps to contribute:

  1. Fork the repository.
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'feat: add amazing feature'
  4. Push to your branch: git push origin feature/amazing-feature
  5. Open a Pull Request.

For bugs and feature requests, please check the Issues page.


📜 License

This project is open-source software licensed under the MIT License.

About

High-performance, zero-dependency reverse proxy server in Go with built-in Token Bucket rate limiting and low-latency request routing.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages