A high-performance, feature-rich Layer 7 (L7) load balancer with a robust and user-friendly admin API.
- 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
- âś… Round Robin
- âś… Weighted Round Robin
- âś… Least Connections
- âś… Weighted Least Connections
- âś… Response Time Based
- âś… IP Hash
- âś… Consistent Hashing
- âś… Adaptive Load Balancing
- ⏳ WebSocket Support (WIP)
- âś… SSL/TLS Support
- ⏳ Automatic Certificate Management (WIP)
- âś… Connection Pooling
- âś… Circuit Breaker
- âś… Rate Limiting
- âś… Compression
- ❌ Custom Request Headers - WIP
- âś… Dynamic Middleware Plug-in
- âś… Configurable Request Logging
- âś… Health Checking
- âś… Dynamic Configuration via Admin API
- âś… Graceful Shutdown
go build -o terraster cmd/terraster
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
- Create a config file anywhere and use the
-
Default Config
- Place
config.yaml
in the root directory - Terraster will load it automatically at startup
- Place
-
Multiple Services
- Create a directory containing multiple service configs
- Use the
-services
flag to point to the directory - Example:
./terraster -services /path/to/services/
The minimal configuration requires only three fields:
port: 8080
host: "lb.domain.com"
backends:
- url: http://localhost:8081
- url: http://localhost:8082
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"
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
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
}
}
}
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
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
}
}
}
# 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
- 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
- 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"
curl http://localhost:8081/api/backends \
-H "Authorization: Bearer ${JWT_TOKEN}" \
-H "Content-Type: application/json"
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
}'
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"]
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
A benchmarking script 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")