Configuration Reference
Configuration Reference
This document describes all configuration fields supported by Nexus
GSLB. The canonical struct is
internal/config/config.go.
Quick start
- Default path:
/etc/gslb/config.yaml(override with-configflag). - 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"
rqlite:
httpAddr: "localhost:4001"
dataDir: "/var/lib/gslbd/rqlite"
connectTimeout: "10s"
database:
cacheTTL: "30s" # DNS query result cache TTL (live-reloadable via SIGHUP)
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). Default0.0.0.0.port(int): UDP port. Default5353(use 53 in production).domain(string): zone served. Examplegslb.local.
rqlite
gslbd stores all configuration and data-plane objects (pools,
members, services, users, …) in rqlite — a
Raft-replicated SQLite cluster — and connects to a co-located
rqlited process over its HTTP API. This block tells gslbd
how to reach the local rqlited; cluster membership is
configured separately in rqlited's own service env (see Datastore).
httpAddr(string): localrqlitedHTTP API address. Defaultlocalhost:4001.connectTimeout(duration): startup connect + leader-wait budget. Default10s.dataDir(string):rqlited's data directory. Default/var/lib/gslbd/rqlite. Owned byrqlited; documented here as the single source of truth for the deploy layer.joinAddrs(list): existing cluster peers for a joining node (empty = standalone).tls(object):enabled,caFile,certFile,keyFile,insecureSkipVerifyfor HTTPS torqlited.auth(object):username,passwordfor therqlitedHTTP basic-auth.
database
cacheTTL(duration): DNS query result cache TTL;"0"disables. Default30s. Live-reloadable viasystemctl reload gslbd(SIGHUP).
api
enabled(bool): start the REST API server. Defaultfalse.listenAddr(string): bind address. Default127.0.0.1(loopback-only; change to0.0.0.0for network access).
!!! warning "API Security" Set GSLB_API_KEY and create
named users before exposing the API on a network interface. When
GSLB_API_KEY is unset the daemon runs in dev mode — all
requests are treated as system admin with no authentication
required.
port(int): TCP port. Default8080.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) — requiresgeoip.dbPathmap-file(aliases:mapfile) — requiresmapFile.rulesasn— routes by client autonomous system number/ISP; requiresasn.dbPathandasn.rulesfailover— always serves the highest-priority healthy member; members are ranked by theirpriorityfield (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 to1. Weight0disables.
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": 3loadbalancer.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.1278Notes:
- 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.
!!! tip "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.asn — ASN/ISP routing algorithm
Routes DNS clients to preferred endpoints based on their autonomous system (AS) number or ISP organisation name. Useful for ISP-level traffic engineering — e.g., send Comcast customers to a specific PoP, or route a known transit provider to a directly-peered endpoint.
dbPath(string): path to a MaxMind GeoLite2-ASN or GeoIP2-ISP .mmdb file.rules([]ASNRule): ordered list of ASN/org→endpoint mappings. First matching rule wins.asn(uint, optional): autonomous system number to match exactly (e.g.,15169for Google).org(string, optional): substring to match against the AS organisation name; case-insensitive (e.g.,"COMCAST"matches"COMCAST-7922").endpoint(string): preferred backend IP when this rule matches.
At least one of asn or org must be set per
rule. When both are set, asn takes precedence (exact match
checked first). Clients whose ASN is not in the database, or whose ASN
does not match any rule, fall through to round-robin across all
endpoints.
Example
loadbalancer:
algorithm: "asn"
endpoints:
- 203.0.113.10 # PoP-A
- 203.0.113.11 # PoP-B
asn:
dbPath: "/etc/gslbd/GeoLite2-ASN.mmdb"
rules:
- asn: 15169
endpoint: "203.0.113.10" # Google → PoP-A
- org: "COMCAST"
endpoint: "203.0.113.11" # Comcast (any ASN) → PoP-B
- org: "COGENT"
endpoint: "203.0.113.10" # Cogent → PoP-ANotes:
- Rules are evaluated in order; first match wins.
orgmatching is a case-insensitive substring match against the full AS organisation name from the MaxMind database."COMCAST"matches"COMCAST-7922","COMCAST CABLE", etc.- Clients from ASNs not in the database, or not matched by any rule, fall back to standard round-robin across all endpoints.
- The preferred endpoint is returned first in the candidate list; remaining endpoints follow in registered order. The DNS server and health manager will skip unhealthy endpoints in the candidate list.
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 tierpriority: 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
scoreWindowis configured on the health check, the higher-scored member wins; otherwise the first member in DB order is used. - The
failoveralgorithm is a per-service setting (services.algorithm). The staticloadbalancer.algorithmfield ingslbd.yamlapplies 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 betrueto activate health checks. Defaultfalse. When false, all endpoints are treated as healthy and no probes are sent. Omitting thehealth:block entirely is equivalent toenabled: false.type:tcp,http,icmp,script, orwebhook. See Health Checks reference for per-type parameters.port: target port (ignored foricmp).checkinterval: Go duration (e.g.,10s).timeout: Go duration.http.path,http.host,http.expectedstatus,http.contains(http type).icmpCount: echo requests per probe interval (icmp type, default 3).scriptPath: path to executable on local filesystem (script type, VM/bare-metal only).scriptContent: script body stored in DB and replicated via NATS — works on VMs, containers, and Kubernetes (script type, takes precedence over scriptPath).webhookURL,webhookMethod: URL and HTTP method for webhook checks (webhook type).http.tls: enable HTTPS.http.insecureSkipVerify: skip TLS verification (default false).
gitops
repoURL: Git repository URL (SSH or HTTPS).branch: branch/ref to track (defaultmain).pathPrefix: directory containinggslbd.yaml.pollInterval: duration between checks (default30s).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
NATS carries ephemeral cluster state only (health transitions, membership heartbeats, RTT samples, sessions). Config and data-plane objects are not synced over NATS — those live in the rqlite datastore (replicated via Raft) and config flows from git via GitOps self-restart.
healthPolicy:local-or-global-fallback(default),prefer-local,local-only,global-any-healthy,global-quorum.quorumMinPercent: minimum percent healthy forglobal-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.
!!! note "Config sync removed" Earlier releases had a JetStream-based
enableConfigSync / state.config.* block. It
has been removed: configuration is now distributed via GitOps self-restart and data-plane
objects are replicated by the rqlite
datastore. NATS carries ephemeral state only.
backup
enabled(bool): enable periodic database backups. Defaultfalse.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. Default1h.keep(int): number of backup files to retain; oldest are deleted first.0retains all files. Default24(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: 24Retention 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) ortext. Usejsonfor log aggregation pipelines (Loki, Datadog, Splunk);textfor human-readable console output.level(string):debug,info(default),warn,error. Setdebugto enable DNS query logging (seedns.queryLog) and other verbose output.
Example
logging:
format: json
level: infodns (additional fields)
queryLog(bool): emit one structured log line per DNS response. Defaultfalse. Each line includesname,type,src(client IP),rcode,answers(selected IPs), andduration_us. Useful during incident investigation; disable in high-traffic environments to avoid log volume.
dns.axfr — Zone Transfers (RFC 5936 / RFC 1995)
enabled(bool): allow AXFR/IXFR zone transfer requests. Defaultfalse. Must be set totrueto enable any transfers.requireTsig(bool): whentrue, unsigned AXFR requests are refused with REFUSED. Defaultfalse. Recommended for public-facing authoritative zones.
IXFR requests (qtype=IXFR) are answered with a full AXFR transfer, satisfying secondary nameservers (BIND 9, Knot DNS, CoreDNS) that request incremental updates.
Zone contents served via AXFR:
- SOA record (opening and closing bookend per RFC 5936)
- NS records from
nsNames - A/AAAA records for every service that has at least one enabled pool member — all enabled members are included regardless of current health state, since secondary servers have no health data
- TXT records managed via the RFC 2136 dynamic DNS API
Example
dns:
listenAddr: "0.0.0.0"
port: 53
domain: "gslb.example.com"
queryLog: true
axfr:
enabled: true
requireTsig: trueTo restrict AXFR to trusted secondaries, use firewall rules on port 53/TCP in addition to (or instead of) TSIG authentication. AXFR is always TCP-only; UDP requests receive REFUSED.
See Zone Transfers reference and the Secondary DNS setup guide for full configuration examples for BIND 9, Knot DNS, CoreDNS, NSD, and Cloudflare Secondary DNS.
api (additional fields)
- Authentication: controlled by
GSLB_API_KEY(see below). When unset, the daemon runs in dev mode — all requests are treated as system admin with no login required. Always set this in production. - Audit log: set
GSLB_AUDIT_LOGto 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, oranon),remote,status,duration_ms. When unset, audit entries are written to the main structured log (distinguishable by"audit":true). GET requests and/api/v1/healthare never audited.
Example (systemd EnvironmentFile)
GSLB_API_KEY=<32-byte hex>
GSLB_SECRET_KEY=<32-byte hex>
GSLB_AUDIT_LOG=/var/log/gslbd/audit.log
auth
sessionTTL(duration): how long a session lives. Default24h.sessionExtend(bool): if true, each authenticated request resets the TTL (sliding window). Defaulttrue.bcryptCost(int): bcrypt work factor for password hashing. Range 10–14; default12. Higher values are slower for attackers but also slower at login.setupEndpoint(bool): when true,POST /api/v1/auth/setupis available while the user table is empty. Defaulttrue. Set tofalseafter initial bootstrapping if desired.
auth.oidc — SSO via OpenID Connect
enabled(bool): activate OIDC/SSO. Defaultfalse.discoveryUrl(string): OIDC issuer base URL (must behttps://). The daemon fetches<discoveryUrl>/.well-known/openid-configurationon startup.clientId(string): OAuth2 client ID registered with the provider.clientSecret(string): OAuth2 client secret.redirectUri(string): full callback URL registered with the provider (https://<host>/api/v1/auth/oidc/callback).scopes([]string): OAuth2 scopes to request. Default:[openid, profile, email].roleClaim(string): claim name to inspect for role mapping (e.g.,groups). If empty, all users receivedefaultRole.roleMapping(map[string]string): maps claim values to Nexus role names. The claim may be a string or a list; the first match wins.defaultRole(string): role assigned when noroleMappingentry matches. Must be one oftenant_admin,operator,viewer. Default:viewer.allowedDomains([]string): when non-empty, only email addresses whose domain matches are permitted; others receive 403.
Example
auth:
sessionTTL: "24h"
sessionExtend: true
bcryptCost: 12
setupEndpoint: true
oidc:
enabled: true
discoveryUrl: "https://accounts.google.com"
clientId: "1234567890-abc.apps.googleusercontent.com"
clientSecret: "GOCSPX-..."
redirectUri: "https://nexus.example.com/api/v1/auth/oidc/callback"
roleClaim: "groups"
roleMapping:
"nexus-admins": "tenant_admin"
"nexus-operators": "operator"
defaultRole: "viewer"
allowedDomains: ["example.com"]Environment variables used by the auth system (set via EnvironmentFile, not in config.yaml):
| Variable | Required | Purpose |
|---|---|---|
GSLB_API_KEY |
Yes (prod) | System-level admin bearer token. When unset, dev mode is active (no auth). |
GSLB_SECRET_KEY |
When TOTP used | 32-byte hex key for AES-256-GCM encryption of TOTP secrets. The daemon refuses to start if TOTP users exist and this is unset. |
Generate both values with openssl rand -hex 32.
bgp — BGP Route Health Injection
enabled(bool): activate the embedded BGP speaker. Defaultfalse.localASN(uint32): required when enabled. Your autonomous system number. Private-use range: 64512–65534.routerID(string): required when enabled. A stable IPv4 address used as the BGP router ID. Must be unique across nodes peering with the same upstream.listenAddr(string): bind address for incoming BGP connections. Default0.0.0.0.listenPort(int): TCP port. Default179.holdTime(duration): BGP hold timer. Default90s. RFC 4271 minimum is 3 seconds.keepAliveTime(duration): keepalive interval. Default30s. Should be one third ofholdTime.peers([]PeerConfig): list of BGP neighbours.remoteASN(uint32, required): neighbour's AS number.remoteAddr(string, required): neighbour's IPv4 address.password(string, optional): MD5 TCP session authentication password.
nodePrefixes([]string): CIDR prefixes announced unconditionally while the daemon runs. Withdrawn on graceful shutdown (SIGTERM/SIGINT). Use for anycast VIPs that represent the GSLB service itself.poolPrefixes([]PoolPrefixConfig): health-driven prefix injection.poolID(string, required): pool UUID from the database.prefixes([]string, required): CIDR prefixes to announce when pool is healthy.withdrawThreshold(float64): fraction of endpoints that must be healthy to keep prefix announced.0.0(default) = any healthy endpoint keeps routes up;0.5= withdraw below 50% healthy.
Example (node VIP + pool-driven prefix):
bgp:
enabled: true
localASN: 65001
routerID: "10.0.0.1"
listenPort: 179
holdTime: "90s"
keepAliveTime: "30s"
peers:
- remoteASN: 65000
remoteAddr: "10.0.0.254"
password: ""
nodePrefixes:
- "203.0.113.0/24" # always announced while daemon runs
poolPrefixes:
- poolID: "a1b2c3d4-..." # UUID from GET /api/v1/pools
prefixes:
- "198.51.100.0/24"
withdrawThreshold: 0.5 # withdraw if <50% of pool endpoints healthySee BGP Route Health Injection for the full reference, peer configuration examples (FRR, BIRD, Cisco IOS), and troubleshooting guidance.
alerts
All targets fire on state transitions only (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 WARN log.
Multiple targets of any type can be configured simultaneously.
alerts.webhooks — Generic HTTP webhook
url(string, required): fullhttp://orhttps://URL to POST events to.secret(string, optional): when set, each request includes anX-Nexus-Signature: sha256=<hex>header — an HMAC-SHA256 of the request body signed with this secret. Use it to verify the sender.
Event payload (JSON):
{"poolId": "abc123", "ipAddress": "10.0.0.1", "healthy": false, "timestamp": 1714000000}alerts.pagerduty — PagerDuty Events API v2
routingKey(string, required): the PagerDuty integration key (found under Services → your service → Integrations tab → Events API v2).severity(string, optional): PagerDuty alert severity for unhealthy events. Valid values:critical(default),error,warning,info. Resolved events always use severityinfo.
Nexus opens a PagerDuty incident when an endpoint goes unhealthy and
resolves it automatically on recovery. Incidents are deduplicated on
nexus/<poolId>/<ipAddress> so repeated
transitions do not create duplicate incidents.
alerts.opsgenie — Atlassian OpsGenie Alerts API
apiKey(string, required): OpsGenie API key with "Create and Update" and "Close" alert permissions. Found under Settings → API key management.priority(string, optional): OpsGenie alert priority for unhealthy events. Valid values:P1(default, critical) throughP5(informational).region(string, optional): API endpoint region.us(default) →api.opsgenie.com,eu→api.eu.opsgenie.com. Useeuonly if your account is on the EU data residency plan.
Nexus creates an OpsGenie alert when an endpoint goes unhealthy and
closes it automatically on recovery. Alerts are deduplicated on alias
nexus/<poolId>/<ipAddress>.
Example
alerts:
webhooks:
- url: "https://hooks.slack.com/services/..."
pagerduty:
- routingKey: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"
severity: "critical"
opsgenie:
- apiKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
priority: "P1"
region: "us"Signature verification for webhooks (Go):
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-Nexus-Signature")), []byte(expected))See Health Alerting for setup walkthroughs, curl-based test commands, and troubleshooting.
redirect — HTTP Redirect Service
enabled(bool): start the HTTP redirect listener. Defaultfalse.listenAddr(string): bind address. Default0.0.0.0.port(int): TCP port to listen on. No default — must be set whenenabled: true. Use80for a first-class HTTP redirect listener, or another port if a reverse proxy (Caddy, nginx) is in front.
The redirect service looks up the incoming HTTP Host
header against the redirect rule table and responds with the configured
301 or 302. Rules are managed via POST /api/v1/redirects
and take effect immediately without a restart. Rules are replicated to
all cluster nodes via state sync.
Example
redirect:
enabled: true
listenAddr: "0.0.0.0"
port: 80See HTTP Redirects reference and HTTPS Redirects user guide.
metrics
enablePrometheus: expose/metricsendpoint (default false).listenAddr,port: server binding.
license
secret: HMAC-SHA256 signing secret. Override withGSLB_LICENSE_SECRETenv var.licenseKey: signed license token. Override withGSLB_LICENSE_KEYenv var.- Env vars take precedence over config file values.
- See
docs/Licensing.mdfor license generation details. UseNEXUS_LICENSE_SECRETwhen runninglicensegen.
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; asn.dbPath required when asn rules
are set; each asn.rules entry must have at least one of
asn/org and a valid endpoint
IP |
health |
(when enabled) type must be
tcp or http; port 1–65535;
checkinterval and timeout parseable Go
durations |
rqlite |
httpAddr and each joinAddrs[] valid
host:port; connectTimeout parseable positive
duration; tls.certFile/keyFile required
together; auth.password required when username
set |
state |
healthPolicy one of the recognised values
(local-or-global-fallback (default),
prefer-local, local-only,
global-any-healthy, global-quorum);
quorumMinPercent 0–100; heartbeatInterval and
heartbeatTTL parseable durations |
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;
pagerduty[].routingKey must not be empty;
pagerduty[].severity one of
critical/error/warning/info; opsgenie[].apiKey
must not be empty; opsgenie[].priority one of
P1–P5; opsgenie[].region one of
us/eu |
auth.oidc |
(when enabled) discoveryUrl and
redirectUri must be valid URLs; discoveryUrl
must be https://; clientId and
clientSecret must be non-empty; defaultRole
must be one of tenant_admin, operator,
viewer (or empty) |
bgp |
(when enabled) localASN non-zero;
routerID valid IPv4 address; listenPort
1–65535 if set; holdTime/keepAliveTime
parseable Go durations if set; each peer remoteASN non-zero
and remoteAddr valid IP; all nodePrefixes and
poolPrefixes[].prefixes valid CIDRs;
withdrawThreshold in 0.0–1.0 |
Reloading configuration
gslbd applies configuration changes through three mechanisms, depending on what changed:
| Change | How it applies | Restart? |
|---|---|---|
| Pools, members, services, health checks, geo rules, redirects, users, … (data-plane) | Live via REST API / WebUI / Terraform / gslbctl —
written to rqlite, effective immediately |
No |
logging, alerts.*, dns.rrl,
database.cacheTTL (safe subset) |
systemctl reload gslbd (SIGHUP) — hot-applied in
place |
No |
Listener addresses/ports (dns, api,
metrics), rqlite, state.nats,
TLS, OIDC, DNSSEC, BGP, telemetry, cluster/node id |
Full restart | Yes — systemctl restart gslbd |
SIGHUP (systemctl reload gslbd)
re-reads the config file and hot-applies the safe subset: log
format/level, alerting channels, RRL (rate limits/allowlist/action), and
the DNS cache TTL. If the new file is invalid it is rejected and the
running config is kept. Any changed field that requires a full restart
is logged explicitly so you know a restart is still
needed.
GitOps (when a repo is configured) drives full-config changes: each node independently detects a repo change, validates it, rewrites its own config file, and gracefully restarts onto it. See the GitOps User Guide.