Skip to content

About

Reverse proxy and edge gateway with runtime config, health checks, rate limiting, Prometheus metrics, and Grafana dashboard.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Edge Proxy

CI License: MIT Project status: pre-alpha

Edge Proxy is a runtime-configurable reverse proxy and edge gateway written in Go. It routes HTTP traffic by host and path, tracks backend health, applies per-virtual-host rate limiting, exposes Prometheus metrics, and accepts authenticated runtime configuration updates. It is developed as an open-source learning project for exploring HTTP proxy internals and edge infrastructure.

What Edge Proxy Does Today

At runtime, Edge Proxy:

  • accepts HTTP requests on the public proxy port;
  • selects a virtual host by the request Host header;
  • selects optional path routes using longest-match precedence;
  • can strip a matched path prefix before forwarding upstream;
  • forwards only to enabled backends that are currently marked active;
  • supports least-connections and experimental adaptive load balancing;
  • retries retryable requests once on an alternate backend;
  • runs active backend health checks and exposes backend status;
  • resolves client IPs using forwarding headers only from trusted proxy CIDRs;
  • applies per-virtual-host rate limiting through reusable security policies;
  • publishes validated configuration snapshots atomically;
  • persists runtime configuration changes to the configured JSON file;
  • exposes a token-protected admin HTTP API backed by token-protected gRPC;
  • exports operational metrics for Prometheus;
  • includes a Docker Compose stack with two mock backends, Prometheus, and Grafana.

Requests always use one complete runtime snapshot. During a configuration update, a request either sees the previous valid snapshot or the next valid snapshot; it does not observe a partially applied update.

Architecture

flowchart LR
    Client["Client"] --> Proxy["Reverse proxy"]
    Admin["Admin HTTP API"] --> GRPC["Authenticated gRPC control plane"]
    GRPC --> Runtime["Atomic runtime state"]
    Runtime --> Proxy
    Proxy --> LB["Load balancer"]
    LB --> A["Backend A"]
    LB --> B["Backend B"]
    Health["Health checker"] --> A
    Health --> B
    Proxy --> Metrics["Prometheus metrics"]
    Metrics --> Grafana["Grafana"]
Loading
cmd/
  admin-api/        HTTP API for runtime configuration
  mock-backend/     Demo backend used by Docker Compose
  reverse-proxy/    Main proxy process

internal/
  admin/            HTTP handlers and gRPC control plane
  api/              Protocol Buffers definition and generated Go code
  config/           Loading, validation, persistence, and snapshots
  health/           Backend health checking
  lb/               Load-balancing strategies
  metrics/          Runtime and Prometheus metrics
  middleware/       Request middleware and client IP resolution
  proxy/            Proxy runtime, orchestration, and handlers

Quick Start

Requirements:

  • Go 1.25.2 or newer, matching go.mod;
  • Docker and Docker Compose for the complete local stack.

Create a local environment file:

cp .env.example .env

Replace the example secrets in .env, then start the stack:

docker compose up --build

The stack exposes:

Service Address
Reverse proxy http://localhost:8080
Admin API http://localhost:8081
Prometheus http://localhost:9090
Grafana http://localhost:3000

Send a request through the configured virtual host:

curl -H "Host: app.example.local" http://localhost:8080/

Health checks start immediately. A backend becomes available after it reaches the configured healthy threshold.

Configuration

The default configuration is stored in configs/config.json. Additional examples are available in configs/examples/.

Proxy configuration uses concrete, non-secret values. In Docker Compose, backend URLs can use service names from the shared Docker network:

{
  "id": "backend-1",
  "url": "http://backend-a:3000",
  "weight": 1,
  "enabled": true
}

Use a separate configuration file for each environment when backend addresses or routing rules differ. When running the binary directly, CONFIG_PATH selects the file loaded by the proxy. In a container, mount the selected file and set CONFIG_PATH to its path. Runtime changes made through the Admin API are persisted as concrete values to that file.

Environment variables remain available for secrets and process-level startup settings. They are not expanded inside the JSON configuration. The local .env file is used by Docker Compose for values such as admin tokens and the Grafana password, .env.example documents settings intended to be customized for the local stack.

Important fields:

Field Purpose
server.proxy_port Public proxy HTTP port
server.admin_grpc_port Persisted admin gRPC port setting; the listener currently uses ADMIN_GRPC_ADDR
load_balancing.strategy Load-balancing strategy: least-connections or experimental adaptive
backends Upstream backend definitions with stable id values
virtual_hosts Host-based routing policies using backend_ids
path_routes Optional path-specific backend selection
health_check Active and passive checks, scheduling, thresholds, concurrency, recovery backoff, and transport limits
timeouts Outbound HTTP transport timeouts
logging Log level and asynchronous logging settings
security.policies Reusable security policies referenced by security_policy_id

Backend health

When active health checking is enabled, every configured backend is checked immediately at startup and then according to schedule.interval_ms with optional schedule.jitter_ms. Checks run in a bounded worker pool. Duplicate checks for the same backend are coalesced, and work that does not fit in the queue is retried during the next scheduling cycle.

thresholds.healthy and thresholds.unhealthy define how many consecutive results are required to change backend state. Recovery backoff reduces probe frequency for unhealthy backends and is capped by recovery.backoff.max_ms.

When passive checking is enabled, upstream connection errors and HTTP 5xx responses count as failures, while responses below 500 count as successes. Passive observations use the same thresholds as active probes. If health checking is disabled, enabled backends are considered available immediately.

Runtime changes made through the admin API are persisted to the configured JSON file. Mount that file as a volume when configuration must survive container replacement.

Path routes are matched as exact paths or slash-delimited subtrees. For example, /api matches /api and /api/users, but not /apix. When multiple routes match, the longest route wins. strip_prefix is applied only after a route has matched.

Admin API

Authentication is enabled by default. Configure separate HTTP and gRPC tokens:

ADMIN_AUTH_ENABLED=true
ADMIN_API_TOKEN=replace-with-a-random-value
ADMIN_GRPC_TOKEN=replace-with-another-random-value

Set ADMIN_AUTH_ENABLED=false only in an isolated local environment. The gRPC token is always required, and the unencrypted gRPC transport must remain on a trusted private network.

Main routes:

GET|POST             /api/backend
GET|PUT|DELETE       /api/backend/{id}
GET|POST             /api/vhost
GET|PUT|DELETE       /api/vhost/{domain}
GET|PUT              /api/vhost/{domain}/security
GET                  /api/security/policies
PUT                  /api/security/policies/{id}
GET|PUT              /api/config/server
GET|PUT              /api/config/lb

API documentation:

The browsable reference is generated from the checked-in specification and published through this repository's GitHub Pages workflow.

Example:

curl http://localhost:8081/api/backend \
  -H "Authorization: Bearer $ADMIN_API_TOKEN"

Observability

Prometheus scrapes the internal operational endpoint:

http://reverse-proxy:9091/metrics/prometheus

The public proxy port exposes only a minimal /health response. Detailed operational endpoints are kept on the internal OPS_ADDR.

When another proxy is placed in front of Edge Proxy, configure TRUSTED_PROXY_CIDRS with only its network ranges. Forwarded client IP headers from other peers are ignored.

Development

Run the complete quality suite:

gofmt -l .
go vet ./...
go test ./...
go test -race ./...

Run the proxy outside Docker with a configuration whose backend URLs are reachable from the host:

ADMIN_GRPC_TOKEN=development-only \
  CONFIG_PATH=/path/to/config.json \
  go run ./cmd/reverse-proxy

Project Status

Edge Proxy is pre-alpha and under active development. Configuration formats and APIs may change before the first stable release.

The project originated from an engineering thesis. The current repository is a substantial refactor with a consolidated Go module, immutable configuration snapshots, atomic runtime publication, a backend state registry, and an authenticated control plane.

Current Limitations

  • Admin gRPC authentication uses bearer tokens, but the transport is plaintext. Keep it on a trusted private network.
  • The public proxy listener serves plain HTTP; TLS termination is not implemented yet.
  • Updating server.proxy_port persists the new value, but does not restart the listener. server.admin_grpc_port does not currently configure the live listener, which is controlled by ADMIN_GRPC_ADDR.
  • Newly added or freshly started backends may return 503 until health checks mark them active.
  • The adaptive load balancer is implemented but still experimental.
  • HTTP upgrades, trailers, and complete hop-by-hop header filtering are not yet supported.
  • Request size, URL length, and header limits are not yet configurable per virtual host.

Contributing and Security

License

Edge Proxy is available under the MIT License.

About

Reverse proxy and edge gateway with runtime config, health checks, rate limiting, Prometheus metrics, and Grafana dashboard.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages