A lightweight, configurable reverse proxy server built with Node.js and Express. It routes incoming HTTP requests to multiple local backend services, exposes them via Ngrok tunnels, and provides beautiful request/response logging with full body capture.
- Dynamic Routing — Route traffic to multiple backend services using path prefixes (e.g.,
/ledger,/kms,/app). - Ngrok Integration — Automatically creates a secure public tunnel for local development.
- Request/Response Logging — Colorful, detailed logs with captured request and response bodies (skips in production).
- Raw Body Support — Handles any content type, including large payloads up to 50 MB.
- Error Handling — Graceful handling of unreachable backends (502 Bad Gateway) and timeouts (504 Gateway Timeout).
- Default Fallback Port — Requests to unknown app names are automatically proxied to a configurable default port instead of returning 404.
- Health Check — Root endpoint (
/) returns proxy status, available routes, and the configured default port.
# Clone the repository
git clone <repo-url>
cd reverse-proxy-server
# Install dependencies
pnpm installCreate a .env file in the project root (see .env.example):
# Server port (default: 8888)
PORT=8888
# Ngrok authentication token (required for public tunnels)
NGROK_AUTHTOKEN=your_ngrok_authtoken_here
# Custom Ngrok domain (optional)
NGROK_DOMAIN=your-domain.ngrok-free.app
# Node environment (set to 'production' to disable verbose logging)
NODE_ENV=developmentBackend routes are defined in config.js (not committed to Git).
-
Copy the example file:
cp config.example.js config.js
-
Edit
config.jsto match your local services:export const ROUTES = { kms: 3600, ledger: 3500, app: 8000, ledger2: 3501, kms2: 3601, }; export const DEFAULT_PORT = 8000;
Any request to /{appName}/* will be proxied to http://127.0.0.1:{port}/*.
If appName is not found in ROUTES, the request is forwarded to the DEFAULT_PORT instead of returning a 404 error.
pnpm startThis will:
- Start the Express server on the configured
PORT(default8888). - Attempt to establish an Ngrok tunnel using your
NGROK_AUTHTOKENand optionalNGROK_DOMAIN. - Print available routes and example URLs to the console.
Assuming the proxy is running on http://localhost:8888:
| Request | Proxied To | Note |
|---|---|---|
GET /ledger/accounts |
http://127.0.0.1:3500/accounts |
Known app (ledger) |
POST /kms/encrypt |
http://127.0.0.1:3600/encrypt |
Known app (kms) |
GET /app/users?id=1 |
http://127.0.0.1:8000/users?id=1 |
Known app (app) |
POST /unknown/webhook |
http://127.0.0.1:8000/webhook |
Unknown app → default port |
curl http://localhost:8888/Response:
{
"message": "Webhook Proxy Active",
"uptime": 123.45,
"applications": { "kms": 3600, "ledger": 3500, "app": 8000, "ledger2": 3501, "kms2": 3601 },
"defaultPort": 8000,
"timestamp": "2026-04-23T12:00:00.000Z"
}| Script | Command | Description |
|---|---|---|
start |
nodemon server.js |
Run the proxy server with auto-reload |
test |
echo "Error: no test specified" && exit 1 |
Placeholder for tests |
reverse-proxy-server/
├── .env # Environment variables (not committed)
├── .env.example # Example environment file
├── .gitignore # Git ignore rules
├── config.js # Local app routing configuration (not committed)
├── config.example.js # Example routing configuration
├── index.js # Legacy CommonJS proxy (http-proxy-middleware)
├── requestLogger.js # Express middleware for request/response logging
├── server.js # Main ESM proxy server with Ngrok support
├── package.json # Project metadata and dependencies
└── README.md # This file
server.js— Main entry point. Uses nativehttp/httpsmodules for proxying and integrates Ngrok.config.js— Local routing map. Defines which app names map to which local ports. Ignored by Git.config.example.js— Committed example of the routing configuration.index.js— Older implementation usinghttp-proxy-middleware(CommonJS). Kept for reference.requestLogger.js— Middleware that captures and pretty-prints request/response bodies withchalkcoloring.
| Package | Purpose |
|---|---|
express |
Web framework |
http-proxy / http-proxy-middleware |
Proxying utilities |
@ngrok/ngrok |
Ngrok tunnel integration |
chalk |
Terminal string styling |
morgan |
HTTP request logger (available, used via custom middleware) |
dotenv |
Environment variable loading |
nodemon |
Development auto-reload |
on-finished |
Executes callback when response is finished |
raw-body |
Raw body parsing helper |
ISC