Skip to content

Repository files navigation

Aegis

A high-performance L4 network proxy, with Go control plane and Rust data plane

aegis



License: MIT GitHub Stars CI

Go Rust gRPC Protobuf Tokio Chi Zap Docker Kubernetes Prometheus Grafana

Aegis is a high-performance network proxy that combines Go's control plane with Rust's data plane for optimal performance and maintainability.

The control plane handles configuration, health checks, and load balancing logic in Go, while the data plane processes packets in Rust for minimal latency overhead. The two communicate via gRPC, allowing independent development and deployment of each component.

Aegis is designed for production use in microservice architectures and backend infrastructure, and also serves as a reference implementation for building high-performance networked systems.

Grafana Dashboard Screenshots

Aegis Proxy Dashboard:

image image image

Prometheus Dashboard Screenshots

Prometheus Target Health:

image

Table of Contents

Quick Start

Docker (Recommended)

Runs the full stack (proxy, test backends, Prometheus, Grafana) in one command. No local Go/Rust install needed.

git clone https://github.com/lazzerex/aegis.git
cd aegis
cp .env.example .env          # configure credentials (defaults work out of the box)
docker-compose up --build -d

# Test the proxy
curl http://localhost:8080/api/test

# Admin API
curl http://localhost:9090/health

# Grafana: http://localhost:3030  (admin / admin by default)
# Prometheus: http://localhost:9092

Local Development

Requires Go 1.25+, Rust 1.88+, and protoc.

git clone https://github.com/lazzerex/aegis.git
cd aegis
make all                          # builds proto + control plane + data plane

# Terminal 1: data plane
make run-data

# Terminal 2: control plane
make run-control

# Terminal 3: test
./scripts/test-proxy.sh start     # start test backends
./scripts/test-proxy.sh test-proxy
./scripts/test-proxy.sh stop

For the complete Docker Compose service list and port reference, see the Docker Compose section below.

Features

Proxy Capabilities

  • TCP Proxy: High-performance TCP forwarding with async I/O (Tokio)
  • UDP Proxy: Session-based UDP forwarding with bidirectional NAT mapping and connection tracking

Load Balancing

  • Round-robin: Equal distribution across backends
  • Weighted round-robin: Proportional distribution based on backend capacity
  • Least connections: Routes to backend with fewest active connections
  • Consistent hashing: Session affinity using client IP

Reliability & Performance

  • Circuit Breaking: Automatic failure detection and backend recovery with configurable thresholds
  • Rate Limiting: Token bucket algorithm with global and per-connection limits
  • Health Checking: Periodic backend health monitoring with automatic failover
  • Connection Pooling: Pre-warmed idle backend connections skip the TCP handshake on the hot path — protocol-safe (not request-level reuse; each connection still serves exactly one client's session)
  • Config Validation: Bad config is rejected at load/reload time, never partially applied
  • Graceful Shutdown: Connection draining and cleanup

Observability

  • Dual Prometheus Endpoints: Control plane (:9091/metrics) and data plane (:9100/metrics) scraped independently — data plane metrics stay up even if the control plane is down
  • Structured Access Logs: One JSON line per connection (client IP, backend, bytes, latency, error) for both TCP and UDP
  • Read-only Dashboard: GET /dashboard on the Admin API — backend health, weight, and live circuit breaker state, no auth, no build step
  • Structured Logging: Detailed tracing with configurable log levels
  • gRPC Communication: Clean separation between control and data planes

Management

  • aegis-tui: Live read-only terminal dashboard — backend health, circuit breaker transitions, and load-balancing distribution as they happen, polling the Admin API and the data plane's own metrics endpoint independently so it keeps showing traffic even if the control plane goes down
  • aegis-ctl CLI: Built-in operator tool for live backend management
  • Admin API authentication: Bearer token via AEGIS_API_TOKEN env var
  • Dynamic backend API: Add/remove backends at runtime without config reload
  • Helm Chart: charts/aegis/ for Kubernetes deployment (see Helm Chart)
  • TLS on gRPC: Optional TLS between control and data planes via AEGIS_TLS_CERT_FILE/AEGIS_TLS_KEY_FILE

Coming Soon

  • Distributed tracing with OpenTelemetry
  • HTTP/2 support and WebSocket proxying
  • Zero-downtime config reload (preserve existing connections)
  • Kubernetes service discovery (auto-register backends from a Service's endpoints)
  • Redis-backed multi-instance state coordination (circuit breaker state only — see TASK.md for why rate limiting is intentionally excluded)

Architecture

System Overview

End-to-end data flow from clients through Aegis proxy to backend services:

image

Data Plane Request Pipeline

How each request flows through the proxy with rate limiting and circuit breaking:

image

Control Plane Architecture

Configuration management and health monitoring system:

image

Data Plane Internal

Async I/O processing with Tokio runtime

image

Monitoring & Observability

Real-time metrics collection and visualization:

image

Docker Compose Deployment

Complete containerized stack with all services:

image

Load Balancing Algorithms

Four strategies for distributing traffic across backends

image

Circuit Breaker State Machine

Automatic failure detection and recovery:

image

Basic Overview

┌─────────────────────────────────────────────────────────────┐
│                     Go Control Plane                         │
│  ┌────────────┐  ┌──────────┐  ┌─────────────┐             │
│  │ Config Mgmt│  │ Health   │  │ Admin API   │             │
│  │ (YAML)     │  │ Checker  │  │ (Chi Router)│             │
│  └────────────┘  └──────────┘  └─────────────┘             │
│         │              │               │                     │
│         └──────────────┴───────────────┘                     │
│                       │                                      │
│                  gRPC Client                                 │
└───────────────────────┼──────────────────────────────────────┘
                        │
                  gRPC (50051)
                        │
┌───────────────────────┼──────────────────────────────────────┐
│                  gRPC Server                                 │
│                       │                                      │
│                Rust Data Plane                               │
│  ┌────────────┐  ┌──────────┐  ┌─────────────┐             │
│  │ TCP Proxy  │  │ UDP Proxy│  │ Load        │             │
│  │ (Tokio)    │  │ (Tokio)  │  │ Balancer    │             │
│  └────────────┘  └──────────┘  └─────────────┘             │
│         │              │               │                     │
│         └──────────────┴───────────────┘                     │
│                       │                                      │
└───────────────────────┼──────────────────────────────────────┘
                        │
                   Backends
              (NestJS/Any HTTP Service)

Design Decisions

Why Go + Rust instead of one language, why gRPC instead of shared memory, why this concurrency model, why these load balancing algorithms, why v1 doesn't horizontally scale yet — each with alternatives considered and the trade-offs actually accepted, not just what shipped: docs/decisions/.

Installation

Prerequisites

  • Go 1.25+
  • Rust 1.88+
  • Protocol Buffers compiler (protoc)
  • Make
  • Docker (optional, for containerized deployment)

Install Dependencies

Ubuntu/Debian

# Install protobuf compiler
sudo apt update
sudo apt install -y protobuf-compiler

# Install Go (if not installed)
cd /tmp
wget https://go.dev/dl/go1.25.0.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.25.0.linux-amd64.tar.gz
rm go1.25.0.linux-amd64.tar.gz

# Add to PATH
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.bashrc
source ~/.bashrc

macOS

# Install protobuf compiler
brew install protobuf

# Install Go
brew install go

Install Go Protobuf Plugins

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

# Verify installation
protoc --version
go version

Configure Go PATH

The Protocol Buffer plugins must be in your PATH for protoc to find them. If you get errors like protoc-gen-go: program not found or is not executable, follow these steps:

1. Check if plugins are installed:

ls $(go env GOPATH)/bin

You should see protoc-gen-go and protoc-gen-go-grpc.

2. Add Go bin directory to PATH:

For bash users:

echo 'export GOPATH="$HOME/go"' >> ~/.bashrc
echo 'export PATH="$PATH:$GOPATH/bin"' >> ~/.bashrc
source ~/.bashrc

For zsh users:

echo 'export GOPATH="$HOME/go"' >> ~/.zshrc
echo 'export PATH="$PATH:$GOPATH/bin"' >> ~/.zshrc
source ~/.zshrc

3. Verify PATH is correct:

which protoc-gen-go
which protoc-gen-go-grpc
protoc-gen-go --version

Expected output should show paths like /home/yourusername/go/bin/protoc-gen-go.

Build Aegis

# Clone the repository
git clone https://github.com/lazzerex/aegis.git
cd aegis

# Generate protobuf code
make proto

# Build both control and data planes
make all

# Or build individually
make build-go      # Build Go control plane
make build-rust    # Build Rust data plane

The binaries will be created at:

  • control-plane/aegis-control - Go control plane
  • data-plane/target/release/aegis-data - Rust data plane

Production Usage

How Users Deploy Aegis

Aegis is a CLI-based infrastructure tool (like nginx or HAProxy), designed for deployment in production environments.

Common Use Cases:

  1. Reverse Proxy - Place Aegis in front of your application servers

    Internet → Aegis (port 80/443) → Your Backend Servers
    
  2. Load Balancer - Distribute traffic across multiple instances

    Clients → Aegis → [Server 1, Server 2, Server 3, ...]
    
  3. API Gateway - Route requests with rate limiting and circuit breaking

    Mobile/Web Apps → Aegis → Microservices
    

Deployment Methods:

# Option 1: Systemd Service (Linux)
sudo systemctl start aegis
sudo systemctl enable aegis

# Option 2: Docker Compose (Containers)
docker-compose up -d

# Option 3: Kubernetes (Cloud-native)
kubectl apply -f aegis-deployment.yaml

# Option 4: Direct Binary (Development)
# Use make commands (recommended)
make run-data
make run-control

# Or run binaries directly
./data-plane/target/release/aegis-data --config config.yaml
./control-plane/aegis-control --config config.yaml

Management:

  • Configure via YAML files (config.yaml)
  • Monitor via Prometheus metrics (:9091/metrics)
  • Control via Admin API (:9090) or aegis-ctl CLI
  • View dashboards with Grafana (connects to Prometheus)

No GUI Required - Aegis is infrastructure software managed through:

  • Configuration files (YAML)
  • Command-line interface
  • HTTP Admin API
  • Monitoring dashboards (Grafana/Prometheus)

Configuration

Edit config.yaml to configure the proxy:

proxy:
  listen:
    tcp: "0.0.0.0:8080"
    udp: "0.0.0.0:8081"
  
  backends:
    - address: "localhost:3000"
      weight: 100
      health_check:
        interval: 5s
        timeout: 2s
        path: "/health"
    - address: "localhost:3001"
      weight: 100
      health_check:
        interval: 5s
        timeout: 2s
        path: "/health"

  load_balancing:
    algorithm: "round_robin"  # round_robin, weighted, least_connections
    session_affinity: false

  traffic:
    rate_limit:
      requests_per_second: 1000
      burst: 100
    timeout:
      connect: 5s
      idle: 60s
      read: 30s

  circuit_breaker:
    error_threshold: 5
    timeout: 30s

admin:
  api_address: "127.0.0.1:9090"
  metrics_address: "0.0.0.0:9091"

grpc:
  control_plane_address: "127.0.0.1:50051"

Running Aegis

Local Development with Make

This is the recommended method for development and testing.

Prerequisites:

  • Built binaries (run make all)
  • Config file: config.yaml (uses localhost for backends)

Start Aegis:

# Terminal 1: Start Rust data plane
make run-data

# Terminal 2: Start Go control plane
make run-control

The binaries are located at:

  • Data plane: data-plane/target/release/aegis-data
  • Control plane: control-plane/aegis-control

Test it:

# Terminal 3: Test the proxy
curl http://localhost:8080

# Check health status
curl http://localhost:9090/health

# Check metrics
curl http://localhost:9091/metrics

# Check proxy status
curl http://localhost:9090/status

Docker Compose

This method runs the complete stack including monitoring tools.

Prerequisites:

  • Docker and Docker Compose installed
  • Config file: config.docker.yaml (uses Docker service names for backends)

Start the stack:

# Option 1: Using Make commands (wrapper around docker-compose)
make docker-build        # Build images
make docker-up           # Start all services
make docker-logs         # View logs
make docker-down         # Stop all services

# Option 2: Using docker-compose directly (recommended)
docker-compose up --build -d     # Build and start in detached mode
docker-compose ps                # Check status
docker-compose logs -f           # Follow logs
docker-compose logs -f grafana   # Follow specific service
docker-compose down              # Stop all services
docker-compose down -v           # Stop and remove volumes

Services started:

  • Aegis data plane - TCP/UDP proxy (ports 8080/8081)
  • Aegis control plane - Admin API (9090), Metrics (9091)
  • Test backends - HTTP servers (ports 3000-3002)
  • UDP backends - UDP echo servers (ports 5001-5003/udp)
  • Prometheus - Metrics collection (port 9092)
  • Grafana - Visualization (port 3030, login: admin/admin)

Access services:

Helm Chart (Kubernetes)

charts/aegis/ deploys both components as one release — see charts/aegis/README.md for full details.

helm install aegis charts/aegis \
  --set controlPlane.config.proxy.backends[0].address=db1.internal:5432 \
  --set dataPlane.image.repository=<your-registry>/aegis-data \
  --set controlPlane.image.repository=<your-registry>/aegis-control

Notes:

  • No public images are published yet — build Dockerfile.data/Dockerfile.control and push to a registry your cluster can pull from.
  • replicaCount defaults to 1 for both components and the bundled HPA ships disabled — circuit breaker/rate limiter state is per-instance, not yet safe to run >1 replica (see TASK.md Phase 3).
  • Not yet run through helm lint/a live cluster in this environment — review rendered output with helm template before deploying.

Quick Reference

Essential Commands:

# Build
make all              # Build everything
make build-go         # Build control plane only
make build-rust       # Build data plane only
make build-tui        # Build the live terminal dashboard


# Run (development)
make run-data         # Start data plane
make run-control      # Start control plane
make run-tui          # Start the live terminal dashboard

# Testing
./scripts/test-proxy.sh start       # Start test backends
./scripts/test-proxy.sh test-proxy  # Test load balancing
./scripts/test-proxy.sh status      # Check services
./scripts/test-proxy.sh stop        # Stop backends

# Docker
make docker-build     # Build images
make docker-up        # Start stack
make docker-down      # Stop stack
make docker-logs      # View logs

# Or use docker-compose directly
docker-compose up --build -d    # Build and start
docker-compose ps               # Check status
docker-compose logs -f          # View logs
docker-compose down             # Stop stack

# Development
make test             # Run tests
make fmt              # Format code
make lint             # Lint code
make clean            # Clean build artifacts

# aegis-ctl (set AEGIS_URL and AEGIS_API_TOKEN in env)
aegis-ctl status                            # list backends + health
aegis-ctl backends add db4.internal:5432    # add backend
aegis-ctl backends add db4.internal:5432 -w 80  # add with weight
aegis-ctl backends remove db4.internal:5432 # remove backend
aegis-ctl reload                            # reload config from disk
aegis-ctl drain                             # drain connections

Default Ports:

Service Port Purpose
TCP Proxy 8080 Main proxy entry point
UDP Proxy 8081 UDP proxy entry point
Admin API 9090 Control & management (/health, /status, /backends, /dashboard)
Metrics 9091 Prometheus metrics (control plane, aggregated)
Data Plane Metrics 9100 Prometheus metrics (data plane, direct — stays up if control plane is down)
gRPC (Internal) 50051 Control/data plane comms
Prometheus 9092 Metrics scraping
Grafana 3030 Dashboard visualization
Backend 1-3 3000-3002 Test HTTP servers
UDP Backend 1-3 5001-5003 Test UDP servers

Testing

Quick Start Testing

Aegis includes test backend servers and convenient scripts to verify functionality.

Automated Testing (Recommended):

# 1. Start test backend servers
./test-proxy.sh start

# 2. Build and start Aegis (in separate terminals)
# Terminal 1: Data plane
make run-data

# Terminal 2: Control plane
make run-control

# 3. Test the proxy
./test-proxy.sh test-proxy

# 4. Check status of all services
./test-proxy.sh status

# 5. Stop test backends when done
./test-proxy.sh stop

Manual Testing

Step 1: Start Backend Servers

# Terminal 1
python3 examples/simple-http-server.py --port 3000 --name backend1

# Terminal 2
python3 examples/simple-http-server.py --port 3001 --name backend2

# Terminal 3
python3 examples/simple-http-server.py --port 3002 --name backend3

Step 2: Start Aegis

# Terminal 4: Build and start data plane
make build-rust
make run-data

# Terminal 5: Build and start control plane
make build-go
make run-control

Step 3: Test Load Balancing

# Send multiple requests to see round-robin distribution
for i in {1..9}; do
  echo "Request $i:"
  curl -s http://localhost:8080/api/test
  echo ""
done

Expected output: Requests should rotate through backend1 → backend2 → backend3 → backend1...

Step 4: Test Health Checks

# Check overall health
curl http://localhost:9090/health

# Expected: {"status":"ok","backends":{"localhost:3000":true,"localhost:3001":true,"localhost:3002":true}}

Step 5: Test Backend Failover

# Stop one backend (Ctrl+C in its terminal)
# Then test again
curl http://localhost:8080/api/test

# Verify only healthy backends receive traffic
curl http://localhost:9090/health

Step 6: Monitor Metrics

# View Prometheus metrics
curl http://localhost:9091/metrics

# Metrics include:
# - go_goroutines
# - go_memstats_*
# - process_*
# And more...

Testing with netcat (Raw TCP/UDP)

# Test raw TCP connection
printf "GET /health HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" | nc localhost 8080

# Test UDP proxy
echo "test_message" | nc -u -w1 localhost 8081

UDP Proxy Testing

Aegis includes a comprehensive UDP test suite:

# Start UDP backends
make udp-backends-start
# or
./scripts/test-udp-proxy.sh start

# Run comprehensive UDP tests
make test-udp
# or
./scripts/test-udp-proxy.sh test

# Tests include:
# - Basic packet forwarding
# - Load balancing across backends
# - NAT session tracking
# - Rate limiting
# - Circuit breaker
# - Metrics collection
# - Stress testing (1000 packets)

# Stop UDP backends
make udp-backends-stop
# or
./scripts/test-udp-proxy.sh stop

Unit Tests

# Test Go control plane
cd control-plane && go test ./...

# Test Rust data plane
cd data-plane && cargo test

# Run all tests
make test

Advanced Testing Scenarios

Test Advanced Features

# Run comprehensive test suite for advanced features
./scripts/test-advanced-features.sh

# Tests include:
# - Load balancing algorithms (round-robin, least-connections, weighted, consistent-hash)
# - Rate limiting and burst handling
# - Circuit breaker failure detection
# - UDP proxy session management
# - Metrics collection

Test 1: Sustained Load

# Install Apache Bench (if not installed)
# Ubuntu: sudo apt install apache2-utils
# macOS: brew install httpd

# Send 1000 requests with 10 concurrent connections
ab -n 1000 -c 10 http://localhost:8080/api/test

Test 2: Health Check Failover

# 1. Monitor backend health in real-time
watch -n 1 'curl -s http://localhost:9090/health | jq'

# 2. Stop a backend (Ctrl+C in backend terminal)
# 3. Observe automatic traffic redirection to healthy backends
# 4. Restart the backend and watch it rejoin the pool

Test 3: Configuration Validation

# Edit config.yaml to add/modify backends
vim config.yaml

# Restart control plane to apply changes
# New configuration will be pushed to data plane automatically

Test 4: Graceful Shutdown

# Drain connections
curl -X POST http://localhost:9090/drain

# Verify no active connections
curl http://localhost:9090/status

Load Testing

Using wrk

# Install wrk
git clone https://github.com/wg/wrk.git
cd wrk && make

# Run load test
./wrk -t12 -c400 -d30s http://localhost:8080/

Using hey

# Install hey
go install github.com/rakyll/hey@latest

# Run load test
hey -n 10000 -c 100 http://localhost:8080/

Using Apache Bench

ab -n 10000 -c 100 http://localhost:8080/

Performance Benchmarks

bench/run-bench.sh benchmarks Aegis against a raw nginx baseline: the same nginx instance backs both arms, so the only variable is the overhead Aegis itself adds. It builds an isolated stack and runs wrk (via the williamyeh/wrk Docker image — no local install needed) directly against nginx, then again through the Aegis TCP proxy.

./bench/run-bench.sh [duration] [connections] [threads]
# defaults: 15s 100 4

Measured (15s / 100 connections / 4 threads, single-vCPU sandbox — see caveat below):

direct → nginx through Aegis delta
Requests/sec 4513.18 3270.96 -27.5%
Latency p50 19.80ms 23.38ms +18%
Latency p90 33.54ms 60.10ms +79%
Latency p99 61.95ms 73.29ms +18%

This ran on a 1-vCPU sandbox shared across nginx, the load generator, and both Aegis processes — treat the absolute numbers as sandbox-limited and the direct-vs-Aegis ratio as the meaningful, directional signal, not a formal SLA.

Per-function profiling (pprof/flamegraph/criterion, Go + Rust) — what actually costs time inside Aegis, not just the end-to-end number above: docs/profiling/PROFILING.md.

Failure Testing

A live backend crash against the real docker-compose stack — circuit breaker, health checker, and a real cross-component gap the two surfaced together: bench/FAILURE_TESTING.md. Reproduce with ./scripts/failure-demo.sh.

Monitoring

Aegis provides comprehensive observability through Prometheus metrics and Grafana dashboards.

Quick Start Monitoring

When using Docker Compose, monitoring is automatically configured:

# Start the full stack with monitoring
docker-compose up -d

# Access monitoring tools
open http://localhost:3030  # Grafana (admin/admin)
open http://localhost:9092  # Prometheus

Prometheus Metrics

Two independent endpoints:

  • http://localhost:9091/metrics — control plane, aggregated from the data plane over gRPC (also carries Go runtime metrics)
  • http://localhost:9100/metrics — data plane, direct, rebuilt from live counters on every scrape. Keeps working even if the control plane is down, since it doesn't route through it.

Metrics Endpoint: http://localhost:9091/metrics

Key Metrics:

Request Metrics:

  • proxy_requests_total{backend="..."} - Total requests per backend
  • proxy_errors_total{backend="..."} - Total errors per backend
  • proxy_request_duration_seconds - Request latency histogram

Connection Metrics:

  • proxy_active_connections - Current active connections
  • proxy_total_connections - Total connections handled
  • proxy_bytes_sent_total - Total bytes sent
  • proxy_bytes_received_total - Total bytes received

Circuit Breaker Metrics:

  • proxy_circuit_breaker_state{backend="..."} - State (0=closed, 1=half-open, 2=open)
  • proxy_circuit_breaker_trips_total{backend="..."} - Number of trips

Rate Limiter Metrics:

  • proxy_rate_limit_rejected_total - Rejected requests due to rate limiting

Connection Pool Metrics (data plane only, :9100/metrics):

  • proxy_pool_hits_total - Backend connections served from the pre-warmed pool
  • proxy_pool_misses_total - Backend connections that required a fresh dial

Backend Health:

  • proxy_backend_healthy{backend="..."} - Health status (0=unhealthy, 1=healthy)
  • proxy_backend_connections{backend="..."} - Per-backend connection count
  • proxy_backend_requests_total{backend="..."} - Per-backend request count
  • proxy_backend_failures_total{backend="..."} - Per-backend failure count

Example Queries:

# View all metrics
curl http://localhost:9091/metrics

# View only proxy metrics
curl http://localhost:9091/metrics | grep proxy_

# Check request rate
curl -s http://localhost:9091/metrics | grep proxy_requests_total

Access Logs

The data plane emits one structured JSON line per connection (both TCP and UDP) at target=access_log, covering every exit path — rate limited, no healthy backend, circuit breaker open, connect failure/timeout, and normal close:

docker-compose logs data-plane | grep access_log
# {"protocol":"tcp","client_ip":"127.0.0.1","backend":"localhost:3000","bytes_sent":77,"bytes_received":783,"duration_ms":0.8,"error":null}

Grafana Dashboards

Pre-configured Dashboard includes:

  • Request rate and error rate
  • Request latency (p50, p95, p99)
  • Active connections
  • Circuit breaker states per backend
  • Rate limit rejections
  • Backend health status
  • Traffic distribution across backends

Using Grafana:

  1. Navigate to http://localhost:3030
  2. Login with admin / admin (change password on first login)
  3. Go to DashboardsBrowse
  4. Select Aegis Proxy Dashboard
  5. Dashboard auto-refreshes and shows last 15 minutes by default

Customizing Dashboards:

  1. Open the Aegis Proxy Dashboard
  2. Click the gear icon (⚙️) to edit
  3. Add new panels or modify existing ones
  4. Click "Save dashboard" to persist changes

Prometheus Configuration

Prometheus is configured to scrape metrics every 10 seconds. Configuration in prometheus.yml:

global:
  scrape_interval: 10s

scrape_configs:
  - job_name: 'aegis'
    static_configs:
      - targets: ['control-plane:9091']

Alerting Rules:

The following alerts are configured in prometheus-alerts.yml:

Alert Severity Condition Duration
HighProxyErrorRate warning Error rate > 5% 5 minutes
CircuitBreakerOpen warning Circuit breaker open 2 minutes
HighRateLimitRejections info > 10 rejections/sec 5 minutes
BackendUnhealthy critical Backend down 1 minute
HighConnectionCount warning > 1000 connections 10 minutes

Check Alerts:

# View active alerts
open http://localhost:9092/alerts

# View alert rules
open http://localhost:9092/rules

Testing Monitoring

Generate test traffic to see metrics in action:

# Generate TCP traffic
for i in {1..100}; do
  curl -s http://localhost:8080/ > /dev/null
  sleep 0.1
done

# Check metrics update
curl http://localhost:9091/metrics | grep proxy_requests_total

# View in Grafana
open http://localhost:3030

Admin API Endpoints

Monitor and control Aegis via the Admin API (port 9090):

# Health status with backend states (no auth required)
curl http://localhost:9090/health

# Read-only dashboard — backend health, weight, circuit state (no auth required)
open http://localhost:9090/dashboard

# List backends with health state + circuit breaker state (no auth required)
curl http://localhost:9090/backends

# Proxy configuration and status (no auth required)
curl http://localhost:9090/status

# Add a backend at runtime (auth required)
curl -X POST http://localhost:9090/backends \
  -H "Authorization: Bearer $AEGIS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"address":"db4.internal:5432","weight":100}'

# Remove a backend at runtime (auth required)
curl -X DELETE "http://localhost:9090/backends/db4.internal:5432" \
  -H "Authorization: Bearer $AEGIS_API_TOKEN"

# Reload configuration from disk (auth required)
curl -X POST http://localhost:9090/reload \
  -H "Authorization: Bearer $AEGIS_API_TOKEN"

# Drain connections for graceful shutdown (auth required)
curl -X POST http://localhost:9090/drain \
  -H "Authorization: Bearer $AEGIS_API_TOKEN"

Authentication: Set AEGIS_API_TOKEN in your .env file or environment. When empty, auth is disabled (default for local dev). Read-only endpoints (/health, /status, /backends GET) never require auth.

Live TUI

aegis-tui is a live-refreshing terminal dashboard — the same read-only data as GET /dashboard, but with more of it, TCP and UDP, and a set of demo actions to trigger and watch react live. It's meant for demos and at-a-glance operator visibility, not backend management (that's still aegis-ctl — the TUI never mutates Aegis's own config, only external things like a demo backend container).

make build-tui   # or: cd control-plane && go build -o aegis-tui ./cmd/aegis-tui
make run-tui      # or: AEGIS_URL=http://localhost:9090 ./control-plane/aegis-tui

On launch it shows an ASCII splash while the first poll is in flight, then switches to the dashboard. On a wide terminal (roughly 165+ columns) it renders as a two-column layout — backend tables + a stats sidebar on top, event feed + actions list below; narrower terminals fall back to the original single-column stack automatically, no broken layout either way.

What it shows, refreshed every second:

  • Separate TCP and UDP backend panels — health, circuit breaker state, weight, connected count, request count (as a proportional bar, so load-balancing distribution is visible at a glance), failures, and per-backend latency
  • The algorithm currently in effect and whether session affinity is on, read live from the Admin API
  • Global stats with rolling sparklines for request rate and latency, pulled directly from the data plane's own :9100/metrics — plus connection-pool hit rate, rate-limit rejections, circuit breaker trips
  • A live event feed, generated by diffing successive polls (not log tailing) — health flips, circuit breaker transitions, control-plane/data-plane reachability changes, and your own triggered actions all show up as timestamped lines, cause next to effect
  • Two independent reachability indicators for the Admin API and the data plane's metrics endpoint. Killing the control plane doesn't blank the dashboard — the backend table freezes at its last known state while data-plane-sourced stats keep updating, a live demonstration of the control/data-plane split

Actions (same trust level as aegis-ctl's drain/reload — no confirmation prompts, run from repo root so docker compose/docker-compose can find docker-compose.yml):

Key Action
1/2/3 Kill backend1/backend2/backend3 (docker compose kill)
4/5/6 Restart backend1/backend2/backend3 (docker compose start)
7 Fire a concurrent TCP burst — enough to trip rate limiting on a normal multi-core machine (see data-plane/src/rate_limiter.rs config); this project's own 1-vCPU sandbox can't reliably exceed the configured rate no matter the burst size, so don't be surprised if it doesn't trip there
8 Fire a UDP burst at the UDP proxy
p Pause/resume polling — freezes the display for a screenshot without quitting
? Toggle a help screen listing all of this
q Quit

Env vars: AEGIS_URL (Admin API, default http://localhost:9090), AEGIS_DATA_METRICS_URL (data plane metrics, default http://localhost:9100/metrics), AEGIS_PROXY_URL (TCP burst target, default http://localhost:8080/api/test), AEGIS_UDP_ADDR (UDP burst target, default localhost:8081).

A full recordable walkthrough — proving all 4 load-balancing algorithms live, session affinity, dynamic backend management via aegis-ctl, and the resilience beat, not just kill/restart/burst — is in bench/DEMO_SCRIPT.md.

Data Persistence

Both Prometheus and Grafana use Docker volumes for data persistence:

  • prometheus-data - Stores time-series data
  • grafana-storage - Stores dashboards and settings

Reset monitoring data:

docker-compose down -v
docker-compose up -d

Troubleshooting Monitoring

Grafana shows "No data":

# Check Prometheus is running
docker-compose ps prometheus

# Verify Prometheus is scraping
open http://localhost:9092/targets

# Ensure control-plane exposes metrics
curl http://localhost:9091/metrics

Prometheus can't scrape control-plane:

# Check control-plane health
docker-compose ps control-plane

# Test network connectivity
docker-compose exec prometheus wget -O- http://control-plane:9091/metrics

Alerts not firing:

# Generate load to trigger conditions
ab -n 1000 -c 50 http://localhost:8080/

# Check alert status
open http://localhost:9092/alerts

# Verify rules are loaded
open http://localhost:9092/rules

Production Recommendations

For production deployments:

  1. Configure AlertManager for notifications (email, Slack, PagerDuty)
  2. Increase retention in Prometheus (default: 15 days)
  3. Enable authentication on Prometheus
  4. Use HTTPS with proper certificates
  5. Set up Grafana SSO for team access
  6. Configure backups for dashboards and Prometheus data
  7. Tune scrape intervals based on your needs

Project Structure

aegis/
├── proto/                    # Shared protobuf definitions
│   └── proxy.proto          # gRPC service definitions
│
├── control-plane/           # Go control plane
│   ├── cmd/
│   │   ├── main.go         # Control plane entry point
│   │   ├── aegis-ctl/      # Operator CLI tool
│   │   │   └── main.go
│   │   └── aegis-tui/      # Live terminal dashboard
│   ├── internal/
│   │   ├── api/            # REST API handlers + tests
│   │   │   └── dashboard.html # Read-only dashboard (go:embed)
│   │   ├── config/         # Configuration management + validation + tests
│   │   ├── grpc/           # gRPC client to data plane
│   │   ├── health/         # Health checker + tests
│   │   └── metrics/        # Prometheus metrics + circuit state tracking
│   ├── proto/              # Generated protobuf code
│   ├── aegis-control       # Binary (after build)
│   ├── aegis-ctl           # CLI binary (after build)
│   ├── aegis-tui           # TUI binary (after build)
│   └── go.mod
│
├── data-plane/              # Rust data plane
│   ├── src/
│   │   ├── main.rs         # Entry point
│   │   ├── tcp_proxy.rs    # TCP forwarding logic
│   │   ├── udp_proxy.rs    # UDP forwarding logic
│   │   ├── grpc_server.rs  # gRPC service implementation
│   │   ├── load_balancer.rs # Load balancing algorithms
│   │   ├── rate_limiter.rs  # Rate limiting
│   │   ├── circuit_breaker.rs # Circuit breaker
│   │   ├── connection.rs    # Pre-warmed backend connection pool
│   │   ├── access_log.rs    # Structured JSON per-connection logging
│   │   ├── config.rs        # Configuration structures
│   │   ├── metrics.rs       # Metrics collection
│   │   └── metrics_server.rs # Direct Prometheus /metrics endpoint (9100)
│   ├── target/release/
│   │   └── aegis-data      # Binary (after build)
│   ├── Cargo.toml
│   └── build.rs
│
├── examples/                # Test utilities
│   ├── simple-http-server.py # Test HTTP backend server
│   ├── udp-echo-server.py    # Test UDP backend server
│   └── examples.md           # Examples documentation
│
├── scripts/                 # Testing and automation scripts
│   ├── test-proxy.sh            # TCP proxy testing
│   ├── test-udp-proxy.sh        # UDP proxy testing
│   └── test-advanced-features.sh # Advanced features testing
│
├── grafana/                 # Grafana configuration
│   └── provisioning/
│       ├── dashboards/     # Pre-configured dashboards
│       └── datasources/    # Datasource configuration
│
├── charts/aegis/             # Helm chart for Kubernetes deployment
│   ├── values.yaml
│   └── templates/
│
├── .env.example             # Environment variable template (copy to .env)
├── config.yaml              # Local development config (localhost)
├── config.docker.yaml       # Docker config (service names)
├── docker-compose.yml       # Full stack deployment
├── Dockerfile.control       # Control plane image
├── Dockerfile.data          # Data plane image
├── prometheus.yml           # Prometheus configuration
├── prometheus-alerts.yml    # Alert rules
├── Makefile                 # Build automation
├── README.md                # This file
└── TODO.md                  # Project tasks and roadmap

Development

Code Formatting

# Format Go code
cd control-plane && go fmt ./...

# Format Rust code
cd data-plane && cargo fmt

Linting

# Lint Go code
cd control-plane && go vet ./...

# Lint Rust code
cd data-plane && cargo clippy

Development Workflow

# Format, lint, test, and build
make dev

Troubleshooting

Common Issues

1. gRPC Connection Failed

  • Ensure data plane starts before control plane
  • Check port 50051 is not in use: lsof -i :50051

2. Port Already in Use

  • Change ports in config.yaml
  • Check what's using the port: lsof -i :8080

3. Protobuf Generation Fails

  • Verify protoc is installed: protoc --version
  • Install Go plugins: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
  • Important: Ensure Go's bin directory is in your PATH (see Configure Go PATH section)

4. protoc-gen-go: program not found or is not executable

This error means protoc can't find the Go plugins. Fix it by adding Go's bin directory to your PATH:

# Check where Go installs binaries
go env GOPATH

# Add to your shell config (~/.bashrc or ~/.zshrc)
export GOPATH="$HOME/go"
export PATH="$PATH:$GOPATH/bin"

# Reload your shell
source ~/.bashrc  # or source ~/.zshrc

# Verify it works
which protoc-gen-go
protoc-gen-go --version

5. Backend Connection Refused

  • Ensure backend services are running
  • Check backend addresses in config.yaml
  • Verify health check paths are correct

Roadmap

  • Basic TCP proxy
  • Health checking
  • Metrics pipeline
  • Load balancing (round-robin, weighted, least-connections, consistent-hash)
  • UDP proxy with NAT
  • Rate limiting
  • Circuit breaking
  • Configuration hot reload (POST /reload)
  • Session affinity via consistent hashing
  • Read timeout enforcement
  • Admin API authentication (Bearer token via AEGIS_API_TOKEN)
  • Dynamic backend management API (GET/POST/DELETE /backends)
  • aegis-ctl CLI for live backend management
  • SIGTERM handling for container/Kubernetes graceful shutdown
  • TLS on the control-plane ↔ data-plane gRPC channel
  • Helm chart for Kubernetes
  • Pre-warmed backend connection pooling
  • Structured JSON access logging (TCP + UDP, all exit paths)
  • Config validation on load/reload
  • Direct Prometheus scrape on the data plane (independent of control plane)
  • Read-only admin dashboard (GET /dashboard)
  • Circuit breaker state persistence across restarts/reloads
  • Per-function profiling evidence (pprof, criterion, flamegraphs)
  • Live failure-injection demo (backend crash, health checker + circuit breaker)
  • Zero-downtime reload (preserve active connections)
  • HTTP/2 support
  • Distributed tracing
  • Kubernetes service discovery (auto-register backends from Service endpoints)
  • Redis-backed multi-instance coordination (circuit breaker state)
  • Circuit breaker state reset on unrelated backend health-check reloads (see bench/FAILURE_TESTING.md Finding 2, fixed — TASK.md)
  • Live terminal dashboard (aegis-tui) — backend health, circuit breaker transitions, and load-balancing distribution in real time

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE file for details

Acknowledgments

Built with:

  • Go - Control plane and orchestration
  • Rust - High-performance data plane
  • gRPC - Inter-process communication
  • Tokio - Async runtime for Rust
  • Prometheus - Metrics collection

Author: lazzerex
Project: Aegis Network Proxy

About

A high-performance network proxy built with Rust and Golang.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages