Skip to content

quangh33/hexgate

Repository files navigation

HexGate

HexGate is a lightweight, high-performance API Gateway built from scratch in Go.

This project is a high-availability, stateless API gateway that runs in a complete Docker-based environment. It features an Nginx load balancer (Tier 1) routing traffic to a scalable pool of stateless HexGate instances (Tier 2) , which in turn use Consul for service discovery and Redis for distributed quotas.

✨Features

  • High Availability (HA): Deployed with an Nginx load balancer in front of multiple, scalable hexgate instances
  • Dynamic Service Discovery: Integrates directly with HashiCorp Consul. Backends are no longer static; hexgate automatically discovers, adds, and removes them in real-time as they register or fail health checks.
  • Path-Based Routing: Intelligently routes requests to different backend service pools based on the URL path (e.g., /users/* -> user-service, /products/* -> product-service).
  • JWT Authentication (RS256): Secures routes with a secure, asymmetric (RS256) JWT validation middleware.
  • Distributed Quotas: Uses Redis with a Sliding Window algorithm to enforce shared quotas (e.g., 1000 requests/day) across all gateway instances.
  • Built-in Observability: Exposes a /metrics endpoint for Prometheus, tracking request rates, latencies, and response codes
  • TLS/SSL Termination: Centralized SSL termination at the Nginx load balancer.
  • Dynamic Configuration (Hot Reload): Uses Consul KV as a centralized, dynamic source of truth for all configuration.

Design

🚀 Getting Started

  1. Prerequisites
  • Go 1.19 or later
  • Docker & Docker Compose (for monitoring stack)
  1. Generate SSL Certificates (for TLS) The gateway is configured to run in HTTPS mode by default. You must generate a self-signed certificate and private key for it to find.
cd config
# Run the openssl command
# You can press Enter to accept the defaults for all questions.
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365
# Navigate back to the root directory
cd ..

This will create key.pem and cert.pem inside the config folder.

  • cert.pem (Public Certificate): This file is sent to every client (like a browser) to prove the server's identity and allow the client to encrypt data. It's safe to share.
  • key.pem (Private Key): This is your server's secret. It must never be shared. It's the only thing that can decrypt data sent by clients.
  1. Load Configuration into Consul The gateway no longer reads from config.yaml. You must load this configuration into the Consul Key/Value store before starting the stack.
  • Start Consul
docker-compose up -d consul
  • Add the configuration
    • Open the Consul UI: http://localhost:8500
    • Click on Key/Value in the top menu.
    • Click the Create button.
    • For the Key, enter: hexgate/config
    • For the Value, copy the entire contents of your local config/config.yaml file and paste it into the text box.
    • Save
  1. Run the full stack

Start all services in High-Availability mode (with 2 hexgate instances).

docker-compose up -d --build --scale hexgate=2

The service is now running:

  1. Run the Test Backends

Open 3 new terminals and run the following commands, one in each:

# Terminal 1: A user service
go run test/backend.go -port 8081 -service "user-service" -advertise-addr "host.docker.internal"

# Terminal 2: Another user service
go run test/backend.go -port 8082 -service "user-service" -advertise-addr "host.docker.internal"

# Terminal 3: A product service
go run test/backend.go -port 8083 -service "product-service" -advertise-addr "host.docker.internal"

Go to your Consul UI (http://localhost:8500) and you will see these services marked as "healthy." Your hexgate logs (via docker-compose logs -f hexgate) will show them being discovered.

📊 Monitoring Dashboard

HexGate is pre-configured to work with the included Prometheus and Grafana stack.

Grafana Setup

  1. Navigate to http://localhost:3000 (login: admin / admin).
  2. On the left menu, go to Connections (plug icon) -> Add new connection.
  3. Select Prometheus.
  4. For "Prometheus server URL", enter: http://prometheus:9090
  5. Click "Save & Test". You should see a green success message.
  6. On the left menu, click the Dashboard icon (four squares) -> New -> New Dashboard to start building.

🧪 Testing the Gateway

Test 1: Service Discovery & Routing

Now that your backends are running, send requests to the gateway:

# This will be routed to the "product-service" pool
curl -k https://localhost:8443/products/abc
# Hello from Backend (Port 8083)

# This will be routed to the "user-service" pool
curl -k https://localhost:8443/users/1
# Hello from Backend (Port 8081)

# Send again to see the load balancing
curl -k https://localhost:8443/users/2
# Hello from Backend (Port 8082)

Now, go to Terminal 3 (port 8081) and stop the server (Ctrl+C). Wait a few seconds for Consul to detect the failure.

Now, all traffic for /users/ will go only to the remaining healthy backend:

curl -k https://localhost:8443/users/3
# Hello from Backend (Port 8082)

Test 2: Authentication (JWT)

  • Authentication is enabled by default in config.yaml to support quotas.
curl -k https://localhost:8443/users/1
# 401 Unauthorized: Missing Authorization header

Generate a token (by running go run test/gentoken.go) and attach it:

TOKEN=...[token]...

curl -H "Authorization: Bearer $TOKEN" https://localhost:8443/users/1

Test 3: Rate Limiting

Our config is set to 1 request/sec with a burst of 3. Send 4 rapid requests:

# (Assumes you are sending the valid JWT token)
curl -H "Authorization: Bearer $TOKEN" https://localhost:8443/users/1 # OK
curl -H "Authorization: Bearer $TOKEN" https://localhost:8443/users/2 # OK
curl -H "Authorization: Bearer $TOKEN" https://localhost:8443/users/3 # OK
curl -H "Authorization: Bearer $TOKEN" https://localhost:8443/users/4
# 429 Too Many Requests

About

A lightweight, high-performance API Gateway built from scratch in Go.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published