baker

package module
v0.0.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 15, 2025 License: MIT Imports: 22 Imported by: 0

README

██████╗░░█████╗░██╗░░██╗███████╗██████╗░
██╔══██╗██╔══██╗██║░██╔╝██╔════╝██╔══██╗
██████╦╝███████║█████═╝░█████╗░░██████╔╝
██╔══██╗██╔══██║██╔═██╗░██╔══╝░░██╔══██╗
██████╦╝██║░░██║██║░╚██╗███████╗██║░░██║
╚═════╝░╚═╝░░╚═╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝

Go Reference Go Report Card

Introduction

Baker is a dynamic HTTP reverse proxy with a focus on extensibility and flexibility. It is designed to adapt to a variety of orchestration engines and provides dynamic configuration capabilities, eliminating the need to restart the reverse proxy when changing configurations.

Features

Feature Description
🐳 Docker Integration Native Docker driver for real-time container event listening
🔌 Pluggable Drivers Exposed driver interface for easy integration with other orchestration engines
Dynamic Config Hot-reload configuration without restarts
🌳 Fast Routing Custom trie data structure for high-performance path pattern matching
📚 Library Mode Use as a library—implements the standard http.Handler interface
🔧 Extensible Exposed interfaces for most components
🔀 Middleware Modify incoming and outgoing traffic with built-in or custom middleware
⚖️ Load Balancing Built-in load balancing across service instances
🔒 Auto SSL Automatic certificate creation and renewal via Let's Encrypt
🚦 Rate Limiting Configurable rate limiter per domain and path
📊 Metrics Prometheus metrics available at /metrics endpoint
📋 Static Config Support for services without dynamic configuration endpoints
🔄 WebSocket Full WebSocket proxy support

Quick Start

1. Deploy Baker

Create a docker-compose.yml for Baker:

services:
  baker:
    image: ellato/baker:latest
    environment:
      - BAKER_ACME=NO              # Enable/disable ACME (Let's Encrypt)
      - BAKER_ACME_PATH=/acme/cert # Certificate storage path
      - BAKER_LOG_LEVEL=DEBUG      # Log level: DEBUG, INFO, WARN, ERROR
      - BAKER_BUFFER_SIZE=100      # Event buffer size
      - BAKER_PING_DURATION=2s     # Health check interval
      - BAKER_METRICS_ADDR=:8089   # Metrics endpoint address
    ports:
      - "80:80"
      - "443:443"
    networks:
      - baker
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./acme/cert:/acme/cert

networks:
  baker:
    name: baker
    driver: bridge

2. Configure Your Service

Add Baker labels to your service's docker-compose.yml:

services:
  my-service:
    image: my-service:latest
    labels:
      - "baker.enable=true"
      - "baker.network=baker"
      - "baker.service.port=8000"
      - "baker.service.ping=/config"
      # Optional: Static configuration (for non-dynamic services)
      - "baker.service.static.domain=api.example.com"
      - "baker.service.static.path=/*"
      - "baker.service.static.headers.host=api.example.com"
    networks:
      - baker

networks:
  baker:
    name: baker
    external: true

Note: Ensure both Baker and your service share the same Docker network.

Configuration

Environment Variables

Variable Default Description
BAKER_ACME NO Enable Let's Encrypt automatic SSL
BAKER_ACME_PATH /acme/cert Directory for SSL certificates
BAKER_LOG_LEVEL INFO Logging level
BAKER_BUFFER_SIZE 100 Docker event buffer size
BAKER_PING_DURATION 2s Service health check interval
BAKER_METRICS_ADDR :8089 Prometheus metrics endpoint

Service Labels

Label Required Description
baker.enable Yes Enable Baker for this container
baker.network Yes Docker network name
baker.service.port Yes Service port to proxy to
baker.service.ping Yes Health check / config endpoint
baker.service.static.domain No Static domain (bypasses dynamic config)
baker.service.static.path No Static path pattern
baker.service.static.headers.* No Custom headers to add

Dynamic Configuration Endpoint

Your service should expose a REST endpoint (specified by baker.service.ping) that returns routing configuration:

[
  {
    "domain": "example.com",
    "path": "/api/v1",
    "ready": true
  },
  {
    "domain": "example.com",
    "path": "/api/v2",
    "ready": false
  },
  {
    "domain": "app.example.com",
    "path": "/app/*",
    "ready": true,
    "rules": [
      {
        "type": "ReplacePath",
        "args": {
          "search": "/app",
          "replace": "",
          "times": 1
        }
      }
    ]
  }
]
Field Type Description
domain string Domain to match
path string Path pattern (supports * wildcard)
ready boolean Whether the route is active
rules array Optional middleware rules

Middleware

Baker includes several built-in middleware for request/response modification:

ReplacePath

Replaces or removes parts of the request path before forwarding to the backend service.

{
  "type": "ReplacePath",
  "args": {
    "search": "/api/v1",
    "replace": "",
    "times": 1
  }
}
Argument Type Description
search string Pattern to search for
replace string Replacement string
times integer Number of replacements (-1 for all)

Example: Request to /api/v1/users → Backend receives /users


AppendPath

Adds prefixes and/or suffixes to the request path.

{
  "type": "AppendPath",
  "args": {
    "begin": "/v2",
    "end": ".json"
  }
}
Argument Type Description
begin string Prefix to add
end string Suffix to add

Example: Request to /users → Backend receives /v2/users.json


RateLimiter

Applies rate limiting per client IP address.

{
  "type": "RateLimiter",
  "args": {
    "request_limit": 100,
    "window_duration": "60s"
  }
}
Argument Type Description
request_limit integer Maximum requests per window
window_duration string Time window (e.g., 60s, 1m, 1h)

When the limit is exceeded, clients receive a 429 Too Many Requests response.

License

Baker is licensed under the MIT LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewEntryList added in v0.0.4

func NewEntryList() *entryList

func WithAddCallback

func WithAddCallback(callback func(*Container)) func(*ActionRunner)

func WithBufferSize

func WithBufferSize(size int) serverOptFunc

func WithGetCallback

func WithGetCallback(callback func(string, string) (*Container, *Endpoint)) func(*ActionRunner)

func WithHasDomainCallback added in v0.0.15

func WithHasDomainCallback(callback func(string) bool) func(*ActionRunner)

func WithPingDuration

func WithPingDuration(d time.Duration) serverOptFunc

func WithPingerCallback

func WithPingerCallback(callback func()) func(*ActionRunner)

func WithRemoveCallback

func WithRemoveCallback(callback func(*Container)) func(*ActionRunner)

func WithRules

func WithRules(rules ...rule.RegisterFunc) serverOptFunc

func WithUpdateCallback

func WithUpdateCallback(callback func(*Container, *Endpoint)) func(*ActionRunner)

Types

type ActionCallback

type ActionCallback func(*ActionRunner)

type ActionRunner

type ActionRunner struct {
	// contains filtered or unexported fields
}

func NewActionRunner

func NewActionRunner(bufferSize int, cbs ...ActionCallback) *ActionRunner

func (*ActionRunner) Add

func (ar *ActionRunner) Add(container *Container)

func (*ActionRunner) Close

func (ar *ActionRunner) Close()

func (*ActionRunner) Get

func (ar *ActionRunner) Get(ctx context.Context, endpoint *Endpoint) (*Container, *Endpoint)

func (*ActionRunner) HasDomain added in v0.0.15

func (ar *ActionRunner) HasDomain(ctx context.Context, domain string) bool

func (*ActionRunner) Pinger

func (ar *ActionRunner) Pinger()

func (*ActionRunner) Remove

func (ar *ActionRunner) Remove(container *Container)

func (*ActionRunner) Update

func (ar *ActionRunner) Update(container *Container, endpoint *Endpoint)

type Config

type Config struct {
	Endpoints []Endpoint `json:"endpoints"`
}

type Container

type Container struct {
	Id         string
	ConfigPath string
	Addr       netip.AddrPort
	Meta       Meta
}

type Driver

type Driver interface {
	Add(*Container)
	Remove(*Container)
}

type Endpoint

type Endpoint struct {
	Domain string `json:"domain"`
	Path   string `json:"path"`
	Rules  []Rule `json:"rules"`
}

type Event

type Event struct {
	Type      EventType
	Container *Container
	Endpoint  *Endpoint
	Result    chan struct {
		Container *Container
		Endpoint  *Endpoint
	}
}

type EventType

type EventType int

type Meta added in v0.0.7

type Meta struct {
	Static struct {
		Domain  string
		Path    string
		Headers map[string]string
	}
}

type Rule

type Rule struct {
	Type string          `json:"type"`
	Args json.RawMessage `json:"args"`
}

type Server

type Server struct {
	// contains filtered or unexported fields
}

func NewServer

func NewServer(opts ...serverOpt) *Server

func (*Server) Close

func (s *Server) Close()

func (*Server) HasDomain added in v0.0.15

func (s *Server) HasDomain(ctx context.Context, domain string) bool

HasDomain checks if a domain is registered with the server. This can be used by ACME to validate domains before requesting certificates.

func (*Server) RegisterDriver

func (s *Server) RegisterDriver(fn func(Driver))

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Service

type Service struct {
	Containers []*Container
	Endpoint   *Endpoint
}

Directories

Path Synopsis
cmd
baker command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL