High-performance HTTP proxy & API gateway built on Bun
Midleman is a self-hosted middleware layer that sits between your services and the outside world. It handles credential injection, multi-target routing, webhook fan-out with retries, and real-time traffic inspection — all managed through a built-in web dashboard.
- Proxy Profiles — Inject API credentials server-side so they are never exposed to clients. Share protected upstream APIs via public or key-gated links.
- Named Targets — Reverse-proxy to multiple upstreams, each on its own auto-assigned port, with optional per-target auth.
- Webhook Fan-out — Receive a single inbound webhook and dispatch it asynchronously to N destinations with body templating, custom headers, and retry logic.
- Retry Engine — Configurable per-distributor and per-destination retry with exponential or fixed backoff. Includes a retry until 2xx mode for critical notifications.
- Dead Letter Queue — Failed deliveries are captured in-memory with full replay capability from the dashboard.
- Web Dashboard — Built-in admin UI for full CRUD, request log inspection, charts, and fanout detail.
- Traffic Logging — SQLite-backed request/response capture with configurable retention and body size limits.
- TOTP 2FA — First-run setup wizard generates a QR code for any authenticator app. All admin routes are session-protected.
- Meta Webhook Support — Native
hub.challengeverification for Facebook / WhatsApp / Instagram integrations. - OpenTelemetry — Optional traces and metrics export via OTLP. Compatible with Jaeger, Grafana, Prometheus.
- Low overhead — Sub-5ms processing using Bun's native HTTP server.
- Bun >= 1.0
git clone https://github.com/Biscatos/Midleman.git
cd Midleman
bun install
cp .env.example .env
bun run devOpen http://localhost:3000/dashboard to complete the initial TOTP setup.
docker-compose up -dThe admin dashboard is available at http://localhost:3000/dashboard.
Proxy targets and webhook ports are auto-assigned starting at 4000.
Make sure the
./datavolume is mapped so configuration, logs, and auth state survive container restarts.
All options are set via environment variables. Copy .env.example to get started.
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Admin dashboard port (fixed) |
DATA_DIR |
./data |
Persistent storage directory |
PORT_RANGE_START |
4000 |
Starting port for auto-assigned targets |
Define one or more upstream targets using the TARGET_ prefix:
TARGET_API_URL=https://api.example.com
TARGET_API_PORT=4001 # omit or set to 0 for auto-assign
TARGET_API_AUTH=secret_token # optional per-target auth
TARGET_API_FWDPATH=true # append incoming path to target URLPROXY_INFOBIP_URL=https://api.infobip.com
PROXY_INFOBIP_KEY=your_api_key
PROXY_INFOBIP_HEADER=Authorization
PROXY_INFOBIP_PREFIX=App
PROXY_INFOBIP_ACCESS=public_link_key # optional: protect the public link
PROXY_INFOBIP_BLOCKED=.exe,.bat # optional: block file extensions| Variable | Default | Description |
|---|---|---|
REQUEST_LOG_ENABLED |
true |
Enable SQLite request logging |
REQUEST_LOG_RETENTION_DAYS |
7 |
Auto-purge after N days |
REQUEST_LOG_MAX_BODY_SIZE |
65536 |
Max bytes captured per request body |
| Variable | Default | Description |
|---|---|---|
OTEL_ENABLED |
false |
Enable telemetry |
OTEL_ENDPOINT |
— | OTLP HTTP endpoint (e.g. http://otel-collector:4318) |
OTEL_SERVICE_NAME |
midleman |
Service name in spans/metrics |
OTEL_METRICS_INTERVAL |
15000 |
Metrics export interval (ms) |
Webhooks are configured from the dashboard. Each distributor listens on its own port and dispatches to multiple destinations in parallel.
{
"name": "payments",
"port": 4010,
"retry": {
"maxRetries": 5,
"retryDelayMs": 1000,
"backoff": "exponential",
"retryUntilSuccess": true
},
"targets": [
"https://service-a.internal/hook",
{
"url": "https://service-b.internal/notify",
"method": "POST",
"bodyTemplate": "{\"id\": \"{{order.id}}\", \"amount\": {{order.total}}}",
"retry": {
"maxRetries": 10,
"retryDelayMs": 500,
"retryUntilSuccess": true
}
}
]
}| Field | Description |
|---|---|
maxRetries |
Attempts after the first failure |
retryDelayMs |
Base delay between retries (ms) |
backoff |
exponential (default) or fixed |
retryOn |
HTTP status codes that trigger retry (default: [429, 502, 503, 504]) |
retryUntilSuccess |
Retry on any non-2xx response |
Failed deliveries that exhaust all retries are captured in the Dead Letter Queue and can be replayed individually or in bulk from the dashboard.
- Set the Callback URL in Meta's App Dashboard to your Midleman endpoint, e.g.
https://midleman.example.com/webhook?token=your_token - Set the Verify Token in Meta to match the Auth Token configured in Midleman
- Midleman handles the
hub.challengehandshake automatically
All resources are available via REST under /admin:
| Method | Path | Description |
|---|---|---|
GET |
/admin/webhooks |
List webhook distributors |
POST |
/admin/webhooks |
Create / update a distributor |
DELETE |
/admin/webhooks/:name |
Delete a distributor |
POST |
/admin/webhooks/:name/restart |
Restart a distributor |
GET |
/admin/webhooks/dlq |
List failed deliveries |
POST |
/admin/webhooks/dlq/retry-all |
Retry all failed deliveries |
POST |
/admin/webhooks/dlq/:id/retry |
Retry one delivery |
DELETE |
/admin/webhooks/dlq/:id |
Dismiss a failed delivery |
GET |
/admin/targets |
List named targets |
POST |
/admin/targets |
Create / update a target |
GET |
/admin/profiles |
List proxy profiles |
POST |
/admin/profiles |
Create / update a profile |
GET |
/admin/requests |
Query request logs |
GET |
/health |
Health check |
All admin routes require a valid session cookie (obtained via dashboard login).
src/
├── index.ts # Entry point — HTTP server & routing
├── core/
│ ├── config.ts # Environment config loader
│ ├── store.ts # JSON persistence layer
│ └── types.ts # TypeScript interfaces
├── servers/
│ ├── webhook-server.ts # Webhook fan-out + DLQ + retry engine
│ ├── target-server.ts # Named target servers
│ ├── proxy-server.ts # Proxy profile servers
│ └── port-manager.ts # Dynamic port allocation
├── proxy/
│ └── proxy.ts # Request forwarding logic
├── auth/
│ └── auth.ts # TOTP, sessions, rate limiting
├── telemetry/
│ ├── telemetry.ts # OpenTelemetry setup
│ └── request-log.ts # SQLite logging
└── views/ # Dashboard HTML/CSS/JS
Contributions are welcome! Please read CONTRIBUTING.md before opening a pull request.