A lightweight, open-source API proxy gateway built with Next.js. Route client-side requests through a hosted middleman — with domain allowlisting, per-IP rate limiting, structured logging, and a live stats dashboard.
No database required. Stateless by design. Deploy on Vercel, Render, Railway, Fly.io, any VPS, or Docker.
- Domain allowlisting — only proxy to explicitly permitted hostnames
- All HTTP methods — GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
- Streaming responses — body piped directly, no buffering
- Per-IP rate limiting — configurable max requests per sliding window
- CORS headers — automatically added to all responses
- Stats dashboard — live in-memory counters at
/stats, token-protected - Structured logging — optional JSON logs per request
- Edge runtime — runs at the CDN edge on Vercel for low latency
- Docker ready — multi-stage Dockerfile + docker-compose included
proxi-gate/
├── src/
│ ├── app/ # Next.js App Router (pages + API routes)
│ │ ├── api/
│ │ │ ├── proxy/ # GET/POST/… /api/proxy?url=…
│ │ │ └── stats/ # GET /api/stats
│ │ ├── stats/ # /stats dashboard page
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── globals.css
│ ├── components/ # React components (Header, Footer, ScrollReveal…)
│ ├── lib/ # Core logic (allowlist, headers, stats, rate limit)
│ └── middleware.ts # Per-IP rate limiting middleware
├── public/ # Static assets
├── Dockerfile # Multi-stage production image
├── docker-compose.yml # One-command local Docker deployment
├── .env.docker.example # Docker env template
├── next.config.ts
├── package.json
└── tsconfig.json
git clone https://github.com/Tanendra77/proxi-gate.git
cd proxi-gate
npm install
cp .env.local.example .env.local # fill in your values
npm run devOpen http://localhost:3000. Test the proxy:
GET http://localhost:3000/api/proxy?url=https://jsonplaceholder.typicode.com/posts/1
For detailed step-by-step deployment guides for every platform, see DEPLOYMENT.md.
Quick options:
| Platform | Guide |
|---|---|
| Docker (local) | DEPLOYMENT.md#docker |
| Vercel | DEPLOYMENT.md#vercel |
| Render | DEPLOYMENT.md#render |
| Railway | DEPLOYMENT.md#railway |
| Fly.io | DEPLOYMENT.md#flyio |
| VPS / VM | DEPLOYMENT.md#vps--vm-ubuntudebian |
GET /api/proxy?url=<target-url>
All query parameters, headers, and body are forwarded to the target. The response is streamed back as-is.
# GET request
curl "https://your-instance.vercel.app/api/proxy?url=https://api.themoviedb.org/3/movie/popular?api_key=YOUR_KEY"
# POST with JSON body
curl -X POST "https://your-instance.vercel.app/api/proxy?url=https://api.example.com/data" \
-H "Content-Type: application/json" \
-d '{"key":"value"}'
# With auth header forwarded
curl "https://your-instance.vercel.app/api/proxy?url=https://api.example.com/me" \
-H "Authorization: Bearer YOUR_TOKEN"| Method | Supported |
|---|---|
| GET | Yes |
| POST | Yes |
| PUT | Yes |
| DELETE | Yes |
| PATCH | Yes |
| HEAD | Yes |
| OPTIONS | Yes (CORS preflight) |
| Status | Reason |
|---|---|
| 400 | Missing or invalid ?url= parameter, or non-http(s) protocol |
| 403 | Target domain is not in the allowlist |
| 429 | Rate limit exceeded — includes Retry-After header |
| 502 | Failed to reach the target API |
| Variable | Required | Default | Description |
|---|---|---|---|
ALLOWED_DOMAINS |
Yes | — | Comma-separated hostnames the proxy may forward to. Example: api.themoviedb.org,api.openweathermap.org |
RATE_LIMIT_MAX |
No | 100 |
Max requests per IP per window |
RATE_LIMIT_WINDOW_MS |
No | 60000 |
Rate limit window in milliseconds |
NEXT_PUBLIC_SITE_URL |
No | http://localhost:3000 |
Public URL of your deployment |
ENABLE_REQUEST_LOGGING |
No | false |
true to emit JSON logs per request (host, method, status, timestamp — no API keys) |
STATS_ENABLED |
No | true |
false to disable /stats entirely (returns 404) |
STATS_TOKEN |
No | (unset) | If set, /stats requires Authorization: Bearer <token> |
For local dev copy .env.local.example → .env.local.
For Docker copy .env.docker.example → .env.docker.
ALLOWED_DOMAINS is a comma-separated list of hostnames (no protocol, no path):
ALLOWED_DOMAINS=api.themoviedb.org,api.openweathermap.org,my-api.example.com- Subdomains must be listed explicitly (
api.supabase.co≠db.supabase.co) - Wildcards are not supported — intentional for security
- Changes on Vercel/Render require a redeploy
Visit /stats on your deployed instance:
- Total Requests — all proxied requests since last restart
- Rate Limit Hits — number of 429 responses issued
- Error Rate — percentage of 4xx + 5xx responses
- Uptime — time since process start
- Error Breakdown — 4xx vs 5xx with progress bars
- Top Proxied Domains — top 5 targets by volume
- Rate Limiting — 429 count, configured limit and window
Stats auto-refresh every 10 seconds. All counters are in-memory and reset on process restart.
To protect the stats page, set STATS_TOKEN=your-secret — the page will prompt for it.
Applied per IP at the middleware layer, before the proxy handler.
| Setting | Default |
|---|---|
| Max requests | 100 per window |
| Window | 60 seconds (sliding) |
429 response includes Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining headers.
- Full request URLs (including API keys) are never logged
- API keys and tokens in headers are never stored
- When
ENABLE_REQUEST_LOGGING=true, onlytarget_host,method,status,timestampare logged - No cookies, sessions, or user data are stored
- Stats are in-memory only — no database, no external service
- Owner info — edit
src/components/Footer.tsxandsrc/components/Header.tsx(name + GitHub URL are hard-coded) - Allowed domains — set
ALLOWED_DOMAINSin your environment - Branding — site name "PROXY GATE" is in
src/components/Header.tsxandsrc/components/LogoText.tsx
- Next.js 16 — App Router, Edge Runtime
- React 19 — client components for stats dashboard and animations
- TypeScript — fully typed
- Tailwind CSS v4 — utility-first styling
- shadcn/ui — Card, Badge, Progress components (stats page only)
- IBM Plex Mono — monospace typography
Apache License 2.0 — see LICENSE.
You are free to use, modify, and distribute this project, including for commercial purposes, provided you include the license and attribution notice.