Home
Softono

Terraster

Open source MIT Go
37
Stars
2
Forks
0
Issues
4
Watchers
11 months
Last Commit

 About Terraster

Uncomplicated L7 Load Balancer/Reverse Proxy with BYO plugins support

Platforms

Web Self-hosted

Languages

Go

Links

Need Help Installing Terraster?

We provide expert installation service for this software. Our team will install, configure, and secure Terraster on your server. plans start at just $30.

Terraster

MIT License

A high-performance, feature-rich Layer 7 (L7) load balancer with a robust and user-friendly admin API.

Overview

  • Multiple load balancing methods including Round Robin, Weighted Round Robin, and IP Hash
  • Support for external plugins (third-party modules) for middleware (request, response)
  • 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
  • HTTP/1.1 & HTTP/2 support

Features

Load Balancing Algorithms

  • Round Robin
  • Weighted Round Robin
  • Least Connections
  • Weighted Least Connections
  • Response Time Based
  • IP Hash
  • Consistent Hashing
  • Adaptive Load Balancing
  • Sticky session
  • SSL/TLS Support
  • Dynamic Middleware Plug-in
  • Server Name Indication (SNI)
  • Connection Pooling
  • Circuit Breaker
  • Rate Limiting
  • Compression
  • Configurable Request Logging
  • Restrict access to API via IPs whitelist
  • Custom Request/Response Headers
  • Health Checking
  • Dynamic Configuration via Admin API

WIP

  • WebSocket Support (WIP)

Quick Start

Building from Source

go build -o terraster cmd/terraster

Configuration Guide

Configuration Methods

Terraster offers three ways to manage your configuration:

  1. Single Config File

    • Create a config file anywhere and use the -config flag
    • Example: ./terraster -config /path/to/config.yaml
  2. Default Config

    • Place config.yaml in the root directory
    • Terraster will load it automatically at startup
  3. 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
    headers:               # Custom headers
      request_headers:
        X-Custom-Header: "custom-value"
      response_headers:
        Cache-Control: "no-cache"
      remove_request_headers:
        - User-Agent
        - Accept-Encoding
      remove_response_headers:
        - Server
        - X-Powered-By

    # 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"
      skip_tls_verify: true # only if you don't want to health checker to verify SSL
      thresholds:
        healthy: 2
        unhealthy: 3

    # Path-based routing
    locations:
      - path: "/api/"
        lb_policy: sticky-session # cookie based
        redirect: "/"
        backends:
          - url: http://internal-api1.local.com:8455
            weight: 5
            max_connections: 1000
            http2: false # use http1/1
            sni: "api.domain.com"
            # 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
            http2: false
            sni: "api.domain.com"

  # 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

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

  1. 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"
  insecure: false # set it ONLY to true if you want to run your API via HTTP (unsecure, NOT RECOMMENDED)
  allowed_ips:    # allow access to API only from those IP addresses (if not defined - no restrictions)
    - 10.10.10.10

database:
  path: "./api.db"

auth:
  jwt_secret: "YourSecretKey"
  token_cleanup_interval: "7h"
  password_expiry_days: 3
  1. 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 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")