Skip to content

Configuration Reference

This document describes all configuration fields supported by Pleiades GSLB. The canonical struct is internal/config/config.go.

Quick start - Default path: /etc/gslb/config.yaml (override with -config flag). - YAML example with common fields:

cluster:
  id: "prod-eu-glb"
node:
  id: "edge-lon-01"

dns:
  listenAddr: "0.0.0.0"
  port: 5353
  domain: "example.gslb.local"

loadbalancer:
  algorithm: "round-robin"
  endpoints:
    - "203.0.113.10"
    - "2001:db8::10"

database:
  path: "/var/lib/gslbd/gslbd.db"

api:
  enabled: true
  listenAddr: "127.0.0.1"
  port: 8080
  webuiPath: "/opt/gslb/webui"

health:
  type: http
  port: 80
  checkinterval: 10s
  timeout: 2s
  http:
    path: "/healthz"
    expectedstatus: 200
    tls: false
    insecureSkipVerify: false

state:
  healthPolicy: "prefer-local"
  quorumMinPercent: 51
  heartbeatInterval: "10s"
  heartbeatTTL: "30s"
  nats:
    servers: ["nats://n1.example.com:4222"]

metrics:
  enablePrometheus: true
  listenAddr: "0.0.0.0"
  port: 9090

license:
  secret: "dev-secret-change-me"
  licenseKey: ""

Sections

cluster - id (string): cluster identifier, used in NATS subjects and metric labels. Default: dev-cluster.

node - id (string): node identifier. If empty, hostname is used.

dns - listenAddr (string): bind address (UDP). Default 0.0.0.0. - port (int): UDP port. Default 5353 (use 53 in production). - domain (string): zone served. Example gslb.local.

database - path (string): path to the SQLite database file. Default /var/lib/gslbd/gslbd.db. - Use :memory: for ephemeral/testing. - The parent directory must be writable; schema is created automatically on first run.

api - enabled (bool): start the REST API server. Default false. - listenAddr (string): bind address. Default 127.0.0.1 (loopback-only; change to 0.0.0.0 for network access).

API Security

The API is unauthenticated by default. If you enable it, bind to a restricted interface and consider network-level access controls.

  • port (int): TCP port. Default 8080.
  • webuiPath (string): path to the Next.js WebUI build output directory. When set, the WebUI is served from /ui/. Optional.

loadbalancer - algorithm (string): one of: - round-robin (default) - weighted-round-robin (aliases: wrr, weighted_rr) - geo-ip (aliases: geoip) — requires geoip.dbPath - map-file (aliases: mapfile) — requires mapFile.rules - failover — always serves the highest-priority healthy member; members are ranked by their priority field (1 = primary, 2 = secondary, …; 0 = last-resort) - endpoints ([]string): list of IPv4/IPv6 addresses (used by round-robin and weighted algorithms). - weights (map[string]int, optional): per-endpoint weights. Missing entries default to 1. Weight 0 disables.

Example (weighted round-robin)

loadbalancer:
  algorithm: "weighted-round-robin"
  endpoints:
    - 203.0.113.10
    - 203.0.113.11
    - 2001:db8::10
  weights:
    "203.0.113.10": 5
    "203.0.113.11": 1
    "2001:db8::10": 3

loadbalancer.geoip — Geo IP algorithm - dbPath (string): path to a MaxMind GeoLite2 or GeoIP2 City .mmdb file. - endpointLocations (map[string]EndpointLocation, optional): manual lat/lon overrides for endpoints that are not in the MaxMind DB (private IPs, datacenter addresses). - lat (float64): latitude in degrees. - lon (float64): longitude in degrees.

Example (geo-ip)

loadbalancer:
  algorithm: "geo-ip"
  endpoints:
    - 203.0.113.10
    - 203.0.113.11
    - 10.0.1.1
  geoip:
    dbPath: "/etc/gslbd/GeoLite2-City.mmdb"
    endpointLocations:
      "10.0.1.1":
        lat: 51.5074
        lon: -0.1278

Notes: - Endpoints with unknown locations (not in DB and no manual override) sort to the end of the candidate list. - The DNS client's IP is used for the distance calculation; unknown client IPs fall back to round-robin order. - Close the balancer (balancer.Close()) to release the .mmdb file handle.

Hot reload

The GeoIP database is reloaded automatically. When geoipupdate (or any tool) replaces the .mmdb file — including via atomic rename — the new database is opened and the endpoint location cache is rebuilt within milliseconds, with no DNS queries dropped and no restart required. Any reload failure is logged as an error; the previous database remains active.

loadbalancer.mapFile — Map file (CIDR routing) algorithm - rules ([]MapRule): ordered list of CIDR→endpoint mappings. - cidr (string): source CIDR block (e.g., 10.0.0.0/8). - endpoint (string): preferred endpoint IP for this CIDR.

Example (map-file)

loadbalancer:
  algorithm: "map-file"
  endpoints:
    - 203.0.113.10
    - 203.0.113.11
  mapFile:
    rules:
      - cidr: "10.0.0.0/8"
        endpoint: "203.0.113.10"
      - cidr: "192.168.0.0/16"
        endpoint: "203.0.113.11"

Notes: - First matching rule wins; the matched endpoint is returned first, followed by all other endpoints. - If no CIDR matches (or client IP is unknown), all endpoints are returned in their registered order. - Rules can be hot-reloaded at runtime via UpdateRules.

loadbalancer.failover — Priority failover algorithm

The failover algorithm always serves the highest-priority healthy member. It is configured per-service (not in the static config file) via the algorithm field on the service and the priority field on each member.

Member priorities: - priority: 1 — primary (first choice) - priority: 2 — secondary (used if priority-1 members are all unhealthy) - priority: N — Nth failover tier - priority: 0 — unset; treated as last-resort (after all explicitly numbered members)

Behaviour: - At query time, all unhealthy and disabled members are excluded from the candidate list. - The remaining candidates are sorted by priority ascending; the first (lowest-numbered) candidate is returned. - Automatic failback: when a higher-priority member passes health checks again it re-enters the candidate list and is immediately preferred over lower-priority members. - Within a priority tier, if scoreWindow is configured on the health check, the higher-scored member wins; otherwise the first member in DB order is used. - The failover algorithm is a per-service setting (services.algorithm). The static loadbalancer.algorithm field in gslbd.yaml applies only to the static load balancer (endpoints defined in the config file), not to DB-managed services.

Example (configure via API or TUI):

# Create pool and members
POST /api/v1/pools           → {"name": "web-prod"}
POST /api/v1/pools/{id}/members → {"ipAddress": "10.0.0.1", "port": 80, "priority": 1}
POST /api/v1/pools/{id}/members → {"ipAddress": "10.0.0.2", "port": 80, "priority": 2}
POST /api/v1/pools/{id}/members → {"ipAddress": "10.0.0.3", "port": 80, "priority": 3}

# Create service with failover algorithm
POST /api/v1/services → {"name": "www", "domain": "example.com.", "algorithm": "failover", "poolId": "..."}

# Configure health checks so failed members are detected and excluded
PUT /api/v1/pools/{id}/healthcheck → {"type": "http", "port": 80, "intervalMs": 5000, "timeoutMs": 2000}

health - enabled (bool): must be true to activate health checks. Default false. When false, all endpoints are treated as healthy and no probes are sent. Omitting the health: block entirely is equivalent to enabled: false. - type: tcp or http. - port: target port. - checkinterval: Go duration (e.g., 10s). - timeout: Go duration. - http.path, http.host, http.expectedstatus, http.contains. - http.tls: enable HTTPS. - http.insecureSkipVerify: skip TLS verification (default false).

gitops - repoURL: Git repository URL (SSH or HTTPS). - branch: branch/ref to track (default main). - pathPrefix: directory containing gslbd.yaml. - pollInterval: duration between checks (default 30s). - requireSignature: require GPG-signed commits (default true). - allowedSigners: optional list of allowed GPG fingerprints. - auth.sshKeyPath: private key for SSH. - auth.tokenEnv: reserved for future HTTPS token support.

state - healthPolicy: prefer-local (default), local-only, global-any-healthy, global-quorum. - quorumMinPercent: minimum percent healthy for global-quorum (0–100, default 51). - heartbeatInterval, heartbeatTTL: membership heartbeat cadence and TTL. - nats.servers: list of NATS URLs. If empty, state sync is disabled. - nats.tls.caFile, certFile, keyFile: mTLS settings. - nats.auth: user/password, NKey seed path, or creds file (NATS JWT). - nats.jetStream.domain: optional JetStream domain name.

Configuration sync (JetStream) - enableConfigSync (bool): enable JetStream-based configuration sync. Default false. - config.mode (string): jetstream (only supported mode). - config.stream (string): JetStream stream name. Default PLEIADES.cfg. - config.subjectPrefix (string): base subject. Messages publish to <subjectPrefix>.<cluster>. Default pleiades.cfg. - config.kvBucket (string): KV bucket for latest desired config per cluster. Default PLEIADES_CFG. - config.applyTimeout (duration): max time to apply a received config. Default 5s.

Example (enable configuration sync)

state:
  enableConfigSync: true
  nats:
    servers: ["nats://n1.example.com:4222"]
    jetStream:
      domain: "gslb"
  config:
    mode: "jetstream"
    stream: "PLEIADES.cfg"
    subjectPrefix: "pleiades.cfg"
    kvBucket: "PLEIADES_CFG"
    applyTimeout: "5s"

backup - enabled (bool): enable periodic database backups. Default false. - dir (string): directory in which backup files are written. Default /var/lib/gslbd/backups. Created automatically if absent. - interval (Go duration): how often to take a backup. Default 1h. - keep (int): number of backup files to retain; oldest are deleted first. 0 retains all files. Default 24 (one day of hourly backups).

Backup files are named gslbd-<YYYYMMDDTHHMMSS>.db (UTC timestamp). Each file is a self-contained, independently openable SQLite database. The backup is taken with VACUUM INTO, which produces a clean consistent snapshot without blocking DNS queries or API requests.

Example

backup:
  enabled: true
  dir: /var/lib/gslbd/backups
  interval: 1h
  keep: 24

Retention note: with interval: 1h and keep: 24 you retain 24 hours of hourly backups (~24 × ~500 KB depending on pool size).

logging - format (string): json (default) or text. Use json for log aggregation pipelines (Loki, Datadog, Splunk); text for human-readable console output. - level (string): debug, info (default), warn, error. Set debug to enable DNS query logging (see dns.queryLog) and other verbose output.

Example

logging:
  format: json
  level: info

dns (additional fields) - queryLog (bool): emit one structured log line per DNS response. Default false. Each line includes name, type, src (client IP), rcode, answers (selected IPs), and duration_us. Useful during incident investigation; disable in high-traffic environments to avoid log volume.

Example

dns:
  listenAddr: "0.0.0.0"
  port: 53
  domain: "gslb.example.com"
  queryLog: true

api (additional fields) - Authentication: set the GSLB_API_KEY environment variable to require Authorization: Bearer <key> on all API requests. The GET /api/v1/health endpoint is always exempt. When the variable is unset, the API is unauthenticated (restrict access via firewall in this case). - Audit log: set GSLB_AUDIT_LOG to an absolute file path to write a dedicated JSON audit log of all mutating API calls (POST, PUT, DELETE). Each entry includes: method, path, actor (last 4 chars of the bearer token, or anon), remote, status, duration_ms. When unset, audit entries are written to the main structured log (distinguishable by "audit":true). GET requests and /api/v1/health are never audited.

Example (systemd)

Environment=GSLB_API_KEY=changeme-use-a-long-random-value
Environment=GSLB_AUDIT_LOG=/var/log/gslbd/audit.log

alerts - webhooks ([]WebhookConfig): list of HTTP endpoints to notify on health state transitions. - url (string, required): full http:// or https:// URL to POST events to. - secret (string, optional): when set, each request includes an X-Pleiades-Signature: sha256=<hex> header — an HMAC-SHA256 of the request body signed with this secret. Use it to verify the sender.

Webhook events are fired only on state transitions (healthy → unhealthy or unhealthy → healthy), not on every probe. Delivery is asynchronous and non-blocking: events are queued and retried up to 3 times with exponential backoff (2 s, 4 s). If the queue fills (> 256 pending events), new events are dropped with a warning log.

Event payload (JSON):

{"poolId": "abc123", "ipAddress": "10.0.0.1", "healthy": false, "timestamp": 1714000000}

Example

alerts:
  webhooks:
    - url: "https://hooks.example.com/pleiades"
      secret: "my-signing-secret"
    - url: "https://slack.example.com/incoming"

Signature verification (Go example):

mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
ok := hmac.Equal([]byte(r.Header.Get("X-Pleiades-Signature")), []byte(expected))

metrics - enablePrometheus: expose /metrics endpoint (default false). - listenAddr, port: server binding.

license - secret: HMAC-SHA256 signing secret. Override with GSLB_LICENSE_SECRET env var. - licenseKey: signed license token. Override with GSLB_LICENSE_KEY env var. - Env vars take precedence over config file values. - See docs/Licensing.md for license generation details. Use PLEIADES_LICENSE_SECRET when running licensegen.

Validation internal/config/validator/validate.go is called at startup and rejects invalid configuration with a descriptive error. Checks performed:

Section Validated fields
dns listenAddr valid IP; port 1–65535; domain valid DNS label format (no adjacent dots, no leading/trailing hyphens)
api (when enabled) listenAddr valid IP; port 1–65535
metrics (when enablePrometheus) listenAddr valid IP; port 1–65535
loadbalancer endpoints all valid IPs; algorithm one of the recognised values; weights keys valid IPs and values ≥ 0; geoip.dbPath required when algorithm is geo-ip; geoip.endpointLocations lat ∈ [−90, 90] and lon ∈ [−180, 180]; mapFile.rules each CIDR valid and endpoint a valid IP
health (when enabled) type must be tcp or http; port 1–65535; checkinterval and timeout parseable Go durations
state healthPolicy one of the four recognised values; quorumMinPercent 0–100; heartbeatInterval and heartbeatTTL parseable durations; config-sync fields validated when enableConfigSync is true
backup (when enabled) interval parseable duration; keep ≥ 0
logging format must be json or text; level must be debug, info, warn, or error
alerts each webhooks[].url must be a valid http:// or https:// URL