Reverse proxy with route policies, GeoIP network controls, challenges, rate limiting, TLS...
10K+
BurrowGate is a self-hosted reverse proxy and access gateway built with Bun. It protects websites and APIs from bots and automated scrapers with route policies, rate limits, network rules, browser challenges, TLS termination, and traffic monitoring.
Requirements:
Clone and start BurrowGate:
git clone https://github.com/Rabbit-Company/BurrowGate.git
cd BurrowGate
docker compose up -d --build
docker compose logs burrowgate
BurrowGate generates a dashboard password, encryption key, and temporary self-signed certificate on the first startup. Read the generated dashboard password with:
docker compose exec burrowgate cat /app/data/bootstrap-admin-password.txt
Open the dashboard:
https://SERVER_IP/_burrowgate/admin
The browser will warn about the temporary certificate until a trusted certificate is uploaded or issued.
Create a site from the Sites tab:
Name: Sonarr
Public host: sonarr.example.com
Origin URL: http://10.0.0.20:8989
Point sonarr.example.com to the VPS, open the site's TLS settings, and request a Let's Encrypt certificate.
The default Compose configuration is production ready:
burrowgate-data volumebun userNET_BIND_SERVICE is added for low-port bindingAn .env file is optional. Copy the example file only when overriding defaults:
cp .env.example .env
nano .env
docker compose up -d --build --force-recreate
| Variable | Default | Description |
|---|---|---|
BG_ENV | production | Runtime environment |
BG_HOST | 0.0.0.0 | Listener address |
BG_HTTP_ENABLED | true | Enable the HTTP listener |
BG_HTTP_PORT | 80 | Internal HTTP port |
BG_HTTP_PUBLIC_PORT | 80 | Public HTTP port used in redirects and ACME validation |
BG_HTTPS_ENABLED | true | Enable the HTTPS listener |
BG_HTTPS_PORT | 443 | Internal HTTPS port |
BG_HTTPS_PUBLIC_PORT | 443 | Public HTTPS port used in redirects |
BG_TLS_LISTENER_DRAIN_TIMEOUT_MS | 5000 | Grace period before the previous HTTPS listener is force-closed after a certificate reload |
DATABASE_URL | sqlite://./data/burrowgate.db | Bun.SQL database URL |
BG_ADMIN_USERNAME | admin | Dashboard username |
BG_ADMIN_PASSWORD | generated | Dashboard password |
BG_COOKIE_SECURE | auto | Use secure cookies on HTTPS and ordinary cookies on HTTP |
BG_MASTER_KEY | generated | Encrypts certificate and ACME private keys |
BG_EVENT_RETENTION_DAYS | 7 | Default retention assigned to new sites |
BG_GEOIP_ENABLED | true | Enable country-level GeoIP enrichment |
BG_GEOIP_DATABASE_PATH | ./data/geoip/GeoLite2-Country.mmdb | Local MaxMind database path |
BG_GEOIP_CACHE_ENTRIES | 4096 | Maximum GeoIP reader cache entries |
BG_GEOIP_RETRY_SECONDS | 30 | Retry interval when the MMDB file is not available yet |
BG_DEFAULT_POW_DIFFICULTY | 18 | Default SHA-256 challenge difficulty |
BG_WEBSOCKET_ENABLED | true | Enable WebSocket proxying |
BG_WEBSOCKET_IDLE_TIMEOUT_SECONDS | 120 | WebSocket idle timeout from 10 to 960 seconds |
BG_ACME_DIRECTORY_URL | Let's Encrypt production | ACME directory URL |
BG_ACME_EMAIL | empty | Default ACME contact email |
See .env.example for every available setting.
DATABASE_URL=sqlite://./data/burrowgate.db
DATABASE_URL=postgres://user:password@postgres:5432/burrowgate
DATABASE_URL=mysql://user:password@mysql:3306/burrowgate
Bun.SQL selects the database adapter from the URL.
Each site contains:
The selected site is stored in the dashboard URL. Traffic, sessions, network rules, route policies, and actions are scoped to that site.
Environment-based site seeding is disabled by default. It can be enabled for automated deployments:
BG_SEED_DEFAULT_SITE=true
BG_DEFAULT_SITE_NAME=Sonarr
BG_DEFAULT_PUBLIC_HOST=sonarr.example.com
BG_DEFAULT_ORIGIN=http://10.0.0.20:8989
Environment settings only seed an empty database. Existing sites are managed from the dashboard.
BurrowGate can store an ISO country code with each request event and visitor session. The dashboard renders an interactive SVG world map for request volume and newly created sessions.
Lookups use a local GeoLite2-Country.mmdb file. BurrowGate reuses one database reader, keeps a bounded LRU cache, and stores only the two-letter country code. It does not call an external GeoIP API for each request.
The included optional Compose profile runs MaxMind's official database updater:
MAXMIND_ACCOUNT_ID=123456
MAXMIND_LICENSE_KEY=replace-with-license-key
docker compose --profile geoip up -d --build
See docs/GEOIP.md.
Third-party map and data attribution is documented in THIRD_PARTY_NOTICES.md.
Each site can define a default IP action, a default country action, explicit IP or CIDR rules, and explicit country rules. This supports blocklists, deny-by-default allowlists, and trusted clients that bypass browser verification.
Policy precedence is:
Country policy fails open when the GeoIP database is unavailable. IP rules and the default IP action continue to apply.
See docs/NETWORK_POLICIES.md.
Route policies can override a site's default behavior by path and HTTP method.
Available access modes:
inherit: use the site defaultchallenge: require the site or route challenge chainbypass: proxy without browser verificationblock: return HTTP 403 without contacting the originExample JSON API policy:
Name: JSON API
Path: /api/**
Access mode: Bypass browser verification
Rate limiter: Sliding window
Maximum: 120
Window: 60000 ms
Identity: IP address
This allows non-browser API clients to work normally while BurrowGate applies request limits at the edge.
Rate limits can use the client IP, a verified BurrowGate session, or a selected application header. Counters can be shared across the policy or separated by path and method.
Each site can choose HTML or JSON for errors generated by BurrowGate. HTML mode provides an editable template with escaped placeholders and a reset-to-default action. JSON mode allows the administrator to select exactly which response fields are exposed.
Custom responses cover network blocks, route blocks, rate limits, verification-required API requests, origin failures, and WebSocket handshake failures. Responses from the protected origin are not changed.
A site or route stores an ordered challenge policy:
[
{
"provider": "pow-sha256",
"config": {
"difficulty": 18
}
}
]
The challenge registry is designed to support additional providers such as CAPTCHA services without changing the proxy or session flow.
See docs/ADDING_CHALLENGES.md.
Each site supports:
BurrowGate serves ACME HTTP-01 challenges directly from port 80 before redirects, route policies, IP rules, sessions, or browser challenges.
Private keys are encrypted with AES-256-GCM before they are stored in SQL. The encryption key is read from BG_MASTER_KEY, BG_MASTER_KEY_FILE, or the generated data/master.key file.
Back up the database and master key together. Losing the master key makes stored private keys unusable.
See docs/TLS.md.
WebSocket upgrades pass through the same site, route, IP, rate-limit, and session checks as normal HTTP requests.
Protocol mapping is automatic:
http://origin.example.com -> ws://origin.example.com
https://origin.example.com -> wss://origin.example.com
BurrowGate forwards application cookies, authentication headers, binary messages, text messages, and negotiated subprotocols. BurrowGate credentials are removed before the upstream handshake.
After a successful challenge, BurrowGate creates a random opaque token and stores only its SHA-256 hash. Browsers receive an HTTP-only cookie.
API clients can use:
Authorization: Burrow <token>
or:
X-Burrow-Token: <token>
Sessions can be monitored and revoked from the dashboard.
BurrowGate signs origin headers with the site's signing secret:
X-BurrowGate-Verified: true
X-BurrowGate-Access-Mode: verified
X-BurrowGate-Session-Id: sess_...
X-BurrowGate-Client-Ip: 203.0.113.10
X-BurrowGate-Timestamp: 1785681000
X-BurrowGate-Signature: <HMAC-SHA256>
Origins should reject direct public traffic. Use a private network, firewall allowlist, WireGuard, or mutual TLS so requests cannot bypass BurrowGate.
The dashboard includes:
BurrowGate automatically selects a suitable graph bucket size for the chosen interval and limits the result to roughly 120 points. Missing intervals are returned as zero values so graphs remain stable during quiet periods. Dragging across a time-series graph applies the highlighted interval to the full dashboard.
Traffic retention is configured per site from 1 to 365 days. Maintenance removes expired events automatically.
Install dependencies:
bun install
Start BurrowGate in watch mode:
bun run dev
Start the example origin server:
bun run origin
Run tests and TypeScript checks:
bun test
bun run typecheck
Regenerate the compressed world map assets after changing public/world.svg:
bun run build:map
The project uses .editorconfig and .prettierrc.json with tabs and a width of 2. YAML files use two spaces.
BurrowGate is licensed under the GNU General Public License v3.0. See LICENSE.
Content type
Image
Digest
sha256:b1e6ddd60…
Size
158 MB
Last updated
2 days ago
docker pull rabbitcompany/burrowgate