Terraster

A high-performance, feature-rich Layer 7 (L7) load balancer with a robust and user-friendly admin API.
[!WARNING]
This project is currently in its early development stages. While the core functionality is in place and working as intended, further improvements and features are actively being developed. Expect updates as the project evolves.
π Key Features
- Multiple load balancing methods including Round Robin, Weighted Round Robin, and IP Hash
- TLS termination with certificate management
- Path rewriting and service-to-service redirection
- Dynamic configuration via comprehensive Admin API
- Multiple host support on the same port
- HTTP compression
- Certificate expiration notifications via email
π― Feature Status
Load Balancing Algorithms
- β
Round Robin
- β
Weighted Round Robin
- β
Least Connections
- β
Weighted Least Connections
- β
Response Time Based
- β
IP Hash
- β
Consistent Hashing
- β
Adaptive Load Balancing
Advanced Features
- β³ WebSocket Support (WIP)
- β
SSL/TLS Support
- β³ Automatic Certificate Management (WIP)
- β
Connection Pooling
- β
Circuit Breaker
- β
Rate Limiting
- β
Compression
- β Custom Request Headers
- β
Dynamic Middleware Plug-in
- β
Configurable Request Logging
Core Features
- β
Health Checking
- β
Dynamic Configuration via Admin API
- β
Graceful Shutdown
π¦ Quick Start
Building from Source
go build -o terraster cmd/main.go
βοΈ Configuration Guide
Configuration Methods
Terraster offers three ways to manage your configuration:
-
Single Config File
- Create a config file anywhere and use the
-config flag
- Example:
./terraster -config /path/to/config.yaml
-
Default Config
- Place
config.yaml in the root directory
- Terraster will load it automatically at startup
-
Multiple Services
- Create a directory containing multiple service configs
- Use the
-services flag to point to the directory
- Example:
./terraster -services /path/to/services/
Basic Configuration
The minimal configuration requires only three fields:
port: 8080
host: "lb.domain.com"
backends:
- url: http://localhost:8081
- url: http://localhost:8082
Basic Configuration with Middleware and TLS
This configuration demonstrates TLS termination and basic middleware setup:
port: 8080
algorithm: round-robin
host: "lb.domain.com"
backends:
- url: http://localhost:8081
- url: http://localhost:8082
# Middleware Configuration
middleware:
- rate_limit:
requests_per_second: 100
burst: 30
- security:
hsts: true
frame_options: DENY
xss_protection: true
# TLS Configuration (optional)
tls:
enabled: true
cert_file: "./certificates/my_cert.pem"
key_file: "./certificates/my_cert_privatekey.key"
Advanced Configuration
This example demonstrates a comprehensive setup with multiple services, health checks, and advanced features:
### GLOBAL CONFIG ###
port: 443
# Global Health Check Configuration
health_check:
interval: 10s
timeout: 2s
path: /health
# Global Middleware Configuration
middleware:
- rate_limit:
requests_per_second: 100
burst: 150
- security:
hsts: true
hsts_max_age: 31536000
frame_options: DENY
content_type_options: true
xss_protection: true
- circuit_breaker:
threshold: 5
timeout: 60s
# Global Connection Pool Settings
connection_pool:
max_idle: 100
max_open: 1000
idle_timeout: 90s
### SERVICES CONFIGURATION ###
services:
# Backend API Service
- name: backend-api
host: internal-api1.local.com
port: 8455
log_name: backend-api # Maps to logger configuration
# Service-specific TLS
tls:
cert_file: "/path/to/api-cert.pem"
key_file: "/path/to/api-key.pem"
# Service-specific middleware (overrides global)
middleware:
- rate_limit:
requests_per_second: 2500
burst: 500
# Service-specific health check
health_check:
type: "http"
path: "/"
interval: "5s"
timeout: "3s"
thresholds:
healthy: 2
unhealthy: 3
# Path-based routing
locations:
- path: "/api/"
lb_policy: round-robin
redirect: "/"
backends:
- url: http://internal-api1.local.com:8455
weight: 5
max_connections: 1000
# Backend-specific health check
health_check:
type: "http"
path: "/api_health"
interval: "4s"
timeout: "3s"
thresholds:
healthy: 1
unhealthy: 2
- url: http://internal-api2.local.com:8455
weight: 3
max_connections: 800
# Frontend Service
- name: frontend
host: frontend.local.com
port: 443
locations:
- path: "/"
lb_policy: least_connections
rewrite: "/frontend/"
backends:
- url: http://frontend-1.local.com:3000
weight: 5
max_connections: 1000
- url: http://frontend-2.local.com:3000
weight: 3
max_connections: 800
# HTTP to HTTPS Redirect Service
- name: frontend_redirect
host: frontend.local.com
port: 80
http_redirect: true
redirect_port: 443
# Custom Port Redirect Service
- name: backend_api_redirect
host: internal-api1.local.com
port: 80
http_redirect: true
redirect_port: 8455
π Logging Configuration
Terraster provides a flexible logging system with three main approaches:
1. Default Logger
If no custom logging configuration is provided, Terraster will use the default logger configuration from log.config.json. Your services will use the service_default logger automatically.
{
"loggers": {
"terraster": {
"level": "debug",
"outputPaths": ["terraster.log"],
"errorOutputPaths": ["stderr"],
"development": false,
"logToConsole": true
},
"service_default": {
"level": "info",
"outputPaths": ["service_default.log"],
"errorOutputPaths": ["service_default_error.log"],
"development": false,
"logToConsole": false
}
}
}
2. Single Custom Logger Configuration
Create one custom logging configuration file for all services. Each service can reference a specific logger by name in its configuration.
{
"loggers": {
"api-services": {
"level": "info",
"outputPaths": ["api-services.log"],
"errorOutputPaths": ["api-errors.log"],
"development": false,
"logToConsole": false,
"logRotation": {
"enabled": true,
"maxSizeMB": 50,
"maxBackups": 10,
"maxAgeDays": 30,
"compress": true
}
},
"frontend-services": {
"level": "debug",
"outputPaths": ["frontend.log"],
"errorOutputPaths": ["frontend-errors.log"],
"development": true,
"logToConsole": true
}
}
}
Use in service configuration:
services:
- name: backend-api
log_name: api-services # References logger name from config
# ... rest of service config
- name: frontend
log_name: frontend-services # References logger name from config
# ... rest of service config
3. Separate Logger Configuration Per Service
Create individual log configuration files for each service. Each file must start with the loggers key.
backend-api.log.json:
{
"loggers": {
"backend-api": {
"level": "info",
"outputPaths": ["backend-api.log"],
"errorOutputPaths": ["backend-api-error.log"],
"development": false,
"logToConsole": false
}
}
}
frontend.log.json:
{
"loggers": {
"frontend": {
"level": "debug",
"outputPaths": ["frontend.log"],
"errorOutputPaths": ["frontend-error.log"],
"development": true,
"logToConsole": true
}
}
}
Running Terraster with Different Logging Configurations
# Using default logger
./terraster --config config.yaml
# Using single custom log config
./terraster --config config.yaml --log_configs custom.log.json
# Using separate log configs for each service
./terraster --config config.yaml --log_configs backend-api.log.json,frontend.log.json
# Using default logger and appending additional loggers
./terraster --config config.yaml --log_configs additional.log.json
Important Notes:
- All log config files must start with the
loggers key
- When using multiple config files, make sure logger names are unique
- If no log_name is specified in service configuration, the service will use the
service_default logger
- You can append additional loggers to the default configuration by providing them via --log_configs
π οΈ Admin API Setup
Database Configuration
- Create or use the provided API configuration file:
api:
enabled: true
host: lb-api.domain.com
port: 8081
tls:
cert_file: "./certs/admin.pem"
key_file: "./certs/admin_key.key"
database:
path: "./api.db"
auth:
jwt_secret: "YourSecretKey"
token_cleanup_interval: "7h"
password_expiry_days: 3
- Create an admin user:
go run scripts/database/api_util.go --config ./api.config.yaml \
-username "lb_admin" \
-password "SecurePassword123" \
-role "admin"
API Examples
Get Backend Status
curl http://localhost:8081/api/backends \
-H "Authorization: Bearer ${JWT_TOKEN}" \
-H "Content-Type: application/json"
Add Backend
curl -X POST http://localhost:8081/api/backends?service_name=backend-api \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${JWT_TOKEN}" \
-d '{
"url": "http://newbackend:8080",
"weight": 5
}'
π³ Docker Deployment
Dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN go build -o terraster cmd/main.go
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/terraster .
COPY config.yaml .
EXPOSE 8080 8081 9090
CMD ["./terraster", "--config", "config.yaml"]
Docker Compose
version: '3.8'
services:
terraster:
build: .
ports:
- "8080:8080"
- "8081:8081"
- "9090:9090"
volumes:
- ./config.yaml:/root/config.yaml
- ./certs:/etc/certs
restart: unless-stopped
π Benchmarking
A benchmarking tool is included in the tools/benchmark directory. Run it with:
go run tools/benchmark/main.go -url http://localhost:8080 -c 10 -n 1000
Available flags:
-url: Target URL (default: "http://localhost:8080")
-c: Number of concurrent requests (default: 10)
-n: Total number of requests (default: 1000)
-d: Duration of the test (e.g., "30s", "5m")
π License
This project is licensed under the MIT License - see the LICENSE file for details.