Skip to content

Coordinator Module - API Gateway

The Coordinator module provides REST API for frontend applications and orchestrates queries across multiple Node instances via FlightSQL/HTTP.

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         Homer Coordinator                            │
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │                      REST API (:8080)                         │   │
│  │  /api/v4/transactions/search                                  │   │
│  │  /api/v4/auth/sessions                                        │   │
│  │  /api/v4/dashboards                                           │   │
│  │  ...                                                          │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                              │                                       │
│                              ▼                                       │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │                    FlightService                              │   │
│  │         (Query routing to nodes via HTTP)                     │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                              │                                       │
│         ┌────────────────────┼────────────────────┐                 │
│         ▼                    ▼                    ▼                 │
│  ┌─────────────┐      ┌─────────────┐      ┌─────────────┐         │
│  │   Node 1    │      │   Node 2    │      │   Node 3    │         │
│  │ :50051/HTTP │      │ :50051/HTTP │      │ :50051/HTTP │         │
│  └─────────────┘      └─────────────┘      └─────────────┘         │
│                                                                      │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │                   Settings DB (DuckDB)                        │   │
│  │        Users, Dashboards, User Settings                       │   │
│  └──────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘

Key Features

  • REST API - Full API for Homer UI (v1, v3, v4 endpoints)
  • Multi-node routing - Query distribution across multiple nodes
  • JWT Authentication - Secure API access with tokens
  • OAuth2 Support - External authentication providers
  • Settings Storage - DuckDB-based user and dashboard storage
  • Embedded UI - Optional built-in web interface

Configuration

Basic Configuration

{
  "coordinator": {
    "enable": true,
    "http_server": {
      "enable": true,
      "host": "0.0.0.0",
      "port": 8080,
      "read_timeout": 30,
      "write_timeout": 30,
      "static_path": ""
    },
    "nodes": [
      {
        "name": "local",
        "host": "127.0.0.1",
        "port": 50051,
        "use_tls": false,
        "token": "your-node-token",
        "priority": 1
      }
    ],
    "settings_db_path": "/var/lib/homer/homer_settings.duckdb",
    "transaction_view_max_opens": 3,
    "ip_alias_cache_ttl_sec": 30,
    "jwt": {
      "secret": "your-jwt-secret-minimum-32-characters",
      "expire_hours": 24
    },
    "auth": { "type": "internal" }
  }
}

transaction_view_max_opens (default 3) caps how many successful GET /export/view/:uuid responses each shared view token may serve before it is exhausted (the expires_at TTL still applies).

ip_alias_cache_ttl_sec (default 30, min 5, max 86400) controls how long the coordinator reuses the in-memory IP-alias lookup table when enriching search/QoS/message rows. Creating, updating, or deleting an alias still clears the cache immediately.

Multi-Node Configuration

{
  "coordinator": {
    "enable": true,
    "http_server": {
      "host": "0.0.0.0",
      "port": 8080
    },
    "nodes": [
      {
        "name": "node-eu",
        "host": "node-eu.example.com",
        "port": 50051,
        "use_tls": true,
        "token": "eu-node-token",
        "priority": 1
      },
      {
        "name": "node-us",
        "host": "node-us.example.com",
        "port": 50051,
        "use_tls": true,
        "token": "us-node-token",
        "priority": 2
      },
      {
        "name": "node-asia",
        "host": "node-asia.example.com",
        "port": 50051,
        "use_tls": true,
        "token": "asia-node-token",
        "priority": 3
      }
    ],
    "settings_db_path": "/var/lib/homer/homer_settings.duckdb",
    "jwt": {
      "secret": "your-jwt-secret-minimum-32-characters",
      "expire_hours": 24
    },
    "auth": { "type": "internal" }
  }
}

With OAuth2 Providers

Authorization code flow (server exchanges code, loads userinfo, provisions DuckDB user). See AUTH_LDAP_AND_OAUTH.md.

{
  "coordinator": {
    "enable": true,
    "http_server": {
      "host": "0.0.0.0",
      "port": 8080
    },
    "nodes": [
      {
        "name": "local",
        "host": "127.0.0.1",
        "port": 50051
      }
    ],
    "settings_db_path": "/var/lib/homer/homer_settings.duckdb",
    "jwt": {
      "secret": "your-jwt-secret",
      "expire_hours": 24
    },
    "auth": { "type": "internal" },
    "oauth2_provider": {
      "enable": true,
      "name": "google",
      "type": "oauth2",
      "provider_name": "Google",
      "provider_image": "/assets/google.svg",
      "position": 1,
      "client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
      "client_secret": "YOUR_CLIENT_SECRET",
      "auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
      "token_url": "https://oauth2.googleapis.com/token",
      "redirect_url": "http://localhost:8080/api/v4/auth/oauth2/google/callback",
      "profile_url": "https://openidconnect.googleapis.com/v1/userinfo",
      "scopes": ["openid", "email", "profile"],
      "use_pkce": false,
      "callback_url": "http://localhost:8080/",
      "auto_redirect": false
    }
  }
}

Configuration Parameters

http_server

Parameter Type Default Description
enable bool true Enable HTTP server
host string "0.0.0.0" Listen address
port int 8080 HTTP server port
read_timeout int 30 Read timeout in seconds
write_timeout int 30 Write timeout in seconds
static_path string "" Path to UI static files (optional)
gamedata_dir string "/usr/local/homer-core/gamedata" On-disk directory served read-only at /gamedata/ for large game assets (Doom widget IWAD). A missing directory yields 404s; empty string disables the route. See docs/VOIPGames.md.

nodes

Parameter Type Default Description
name string - Node identifier
host string - Node hostname or IP
port int 50051 Node FlightSQL port
use_tls bool false Use TLS for connection
token string "" Authentication token for node
priority int 1 Query routing priority (lower = higher priority)

jwt

Parameter Type Default Description
secret string "" JWT signing secret (min 32 characters recommended). When empty at startup, Homer generates a random secret, persists it as .homer_jwt_secret beside settings_db_path, and always enforces JWT on protected routes. Set explicitly in config for multi-host deployments.
expire_hours int 24 Token expiration time in hours

auth

coordinator.auth may be a string (legacy), or an object with a type field:

Form Description
{"type":"internal"} (recommended) Same bootstrap and defaults as the string "internal" (admin admin). On startup, if no users row exists for that admin username, the coordinator inserts it once. If admin_password_hash is omitted, a random password is generated and logged once at startup. Login checks users only.
String "internal" Backward compatible; same semantics as {"type":"internal"}.
{"type":"ldap"} / {"type":"oauth"} Declares preferred password-auth mode metadata; does not enable LDAP/OAuth by itself (coordinator.ldap, oauth2_provider still apply). No internal bootstrap.
Omitted (coordinator without auth) Same as {"type":"internal"} (default admin bootstrap with random password when hash omitted).
Object without type (or empty type) Same as {"type":"internal"}: internal bootstrap applies; unset admin_user defaults to admin; empty admin_password_hash triggers a one-time random password in logs.

First login (type internal or string "internal"): username admin. Password is either from admin_password_hash (SHA-256 hex for --reset-admin-password, or bcrypt from the setup wizard), or the random bootstrap password printed in coordinator logs on first startup when no hash is configured.

Reset admin password — set coordinator.auth.admin_password_hash (and optional admin_user) in modular homer.json or via HOMER_COORDINATOR_AUTH_ADMIN_PASSWORD_HASH, then run:

homer --config-path /path/to/homer.json --reset-admin-password

The process opens coordinator.settings_db_path, ensures schema, updates or inserts the users row for admin_user, and exits (no HTTP server). Details, JSON examples, and env overrides: AUTH_LDAP_AND_OAUTH.md.

Password hashes: Users created or updated via the API store bcrypt in users.password_hash. Login also accepts legacy SHA-256 hex (default bootstrap admin, migrated homer-app users). --reset-admin-password still expects SHA-256 hex in admin_password_hash (see AUTH_LDAP_AND_OAUTH.md).

Generating a SHA-256 hex hash (for admin_password_hash / reset only):

# Linux/macOS
echo -n "your-password" | sha256sum | cut -d' ' -f1

# Example: password "sipcapture" produces:
# 883ffc1f37fd0fe542b0fb9740035c4383e7d976c411161d24e62edace280f90
Parameter Type Default Description
type string (see table above) internal, ldap, or oauth. If the whole auth section is omitted, or type is omitted / empty on the object, the effective type is internal.
admin_user string "admin" Admin username when type is internal (including when type is omitted and normalized to internal).
admin_password_hash string "" SHA-256 hex for bootstrap / --reset-admin-password, or bcrypt when set by the setup wizard. When empty on first bootstrap, the coordinator generates a random admin password and logs it once. API user password changes use bcrypt separately.
fallback_auth_type string "" If set to internal or ldap, password login tries this backend after the client-selected type fails (wrong password or backend unavailable). Must not be oauth. Empty disables the second attempt.
disable_password_login bool false If true, hide internal/LDAP from GET /auth/providers and return 403 on POST /auth/sessions. Use with OAuth2 for IdP-only login. Env: HOMER_COORDINATOR_AUTH_DISABLE_PASSWORD_LOGIN.

oauth2_provider

Single optional OAuth2 IdP object (OAuthProviderConfig in src/config/config.go). Uses the OAuth 2.0 authorization code flow on the coordinator (redirect → IdP → callback with code → token + userinfo → one-time browser token → POST /auth/oauth2/token for JWT).

Parameter Type Description
enable bool Enable this provider
name string Stable id for URLs (/api/v4/auth/oauth2/{name}/...)
type string Usually oauth2
provider_name string Display name
provider_image string Provider logo path
position int Display order in discovery
client_id string OAuth2 client id
client_secret string Client secret (required when use_pkce is false)
auth_url string IdP authorization endpoint
token_url string IdP token endpoint
redirect_url string Registered redirect URI (must equal https://<host>/api/v4/auth/oauth2/<name>/callback)
profile_url string UserInfo / profile GET URL
scopes string[] Optional; default openid, email
use_pkce bool Public clients: set true; client_secret may be empty
callback_url string Browser redirect after callback with ?token= or ?oauth_error=
skip_auto_provision bool If true, user must pre-exist in DuckDB
admin_groups string[] Profile group claim values that grant admin JWT
group_claim string JSON claim for groups (default groups)
auto_redirect bool If true, UI may redirect immediately to this provider

The deprecated oauth2_providers array is still accepted at startup and migrated with a log warning; prefer oauth2_provider.

API Endpoints

Authentication

Method Endpoint Description
POST /api/v4/auth/sessions Create session (login)
DELETE /api/v4/auth/sessions/:id Delete session (logout)
GET /api/v4/auth/providers List password backends (internal, ldap) and OAuth2 provider metadata
GET /api/v4/me Get current user info
Method Endpoint Description
GET /api/v4/transactions List transactions
POST /api/v4/transactions/search Search transactions
POST /api/v4/transactions/messages Get transaction messages (with optional Lua call-id correlation, see LUA_CORRELATION.md)
POST /api/v4/transactions/view/link Create a one-time SIP trace view URL (data.url_viewGET /export/view/:uuid) for external app redirects — see Dashboard URL search — external apps
GET /export/view/:uuid Standalone HTML SIP transaction view (no JWT; counts toward view token open limit)
GET /api/v4/messages/:id Get single message
GET /api/v4/messages/:id/decoded Get decoded message
POST /api/v4/transactions/qos Get QoS data
POST /api/v4/transactions/events Application log lines (proto 100) for session(s)

Dashboards

Method Endpoint Description
GET /api/v4/dashboards List dashboards
POST /api/v4/dashboards Create dashboard
GET /api/v4/dashboards/:id Get dashboard
PUT /api/v4/dashboards/:id Update dashboard
DELETE /api/v4/dashboards/:id Delete dashboard

Users (Admin)

Method Endpoint Description
GET /api/v4/users List users
POST /api/v4/users Create user
GET /api/v4/users/:id Get user
PATCH /api/v4/users/:id Update user
DELETE /api/v4/users/:id Delete user

Settings & Configuration

Method Endpoint Description
GET /api/v4/mappings List field mappings
GET /api/v4/hepsubs List HEP subscriptions
GET /api/v4/aliases List aliases
GET /api/v4/db/nodes List configured nodes
GET /api/v4/modules Get modules status

Statistics

Method Endpoint Description
POST /api/v4/statistics/query Execute statistics query (rawquery validated; read-only SQL only)
GET /api/v4/statistics/databases List databases
GET /api/v4/statistics/measurements List measurements
GET /api/v4/statistics/metrics List metrics

Health & Status

Method Endpoint Description
GET /health Health check
GET /api/v1/status System status with nodes info

Deployment Patterns

Standalone (All-in-One)

Single server running Ingest, Storage, Node, and Coordinator:

┌───────────────────────────────────────────────────────────┐
│                       Homer Server                         │
│  ┌─────────┐ ┌─────────┐ ┌──────┐ ┌─────────────┐        │
│  │ Ingest  │ │ Storage │ │ Node │ │ Coordinator │        │
│  │ :9060   │ │         │ │:50051│ │   :8080     │        │
│  └────┬────┘ └────┬────┘ └───┬──┘ └──────┬──────┘        │
│       │           │          │           │                │
│       └───────────┴──────────┴───────────┘                │
│                         │                                  │
│                  ┌──────┴──────┐                          │
│                  │  DuckLake   │                          │
│                  └─────────────┘                          │
└───────────────────────────────────────────────────────────┘

Separate instances for each module:

                       ┌─────────────────┐
                       │   Coordinator   │
                       │     :8080       │
                       └────────┬────────┘
                                │
           ┌────────────────────┼────────────────────┐
           ▼                    ▼                    ▼
    ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
    │  Ingest 1    │    │  Ingest 2    │    │  Ingest 3    │
    │  Storage 1   │    │  Storage 2   │    │  Storage 3   │
    │  Node 1      │    │  Node 2      │    │  Node 3      │
    │  :50051      │    │  :50051      │    │  :50051      │
    └──────┬───────┘    └──────┬───────┘    └──────┬───────┘
           │                   │                   │
           ▼                   ▼                   ▼
    ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
    │  DuckLake   │     │  DuckLake   │     │  DuckLake   │
    │  (Region 1) │     │  (Region 2) │     │  (Region 3) │
    └─────────────┘     └─────────────┘     └─────────────┘

Read-Heavy Setup

Multiple Coordinators behind load balancer:

                    ┌─────────────────┐
                    │  Load Balancer  │
                    └────────┬────────┘
                             │
           ┌─────────────────┼─────────────────┐
           ▼                 ▼                 ▼
    ┌─────────────┐   ┌─────────────┐   ┌─────────────┐
    │ Coordinator │   │ Coordinator │   │ Coordinator │
    │    :8080    │   │    :8080    │   │    :8080    │
    └──────┬──────┘   └──────┬──────┘   └──────┬──────┘
           │                 │                 │
           └─────────────────┼─────────────────┘
                             │
                    ┌────────┴────────┐
                    │   Node Pool     │
                    │  (FlightSQL)    │
                    └─────────────────┘

Settings Database

The Coordinator uses a DuckDB database for storing:

  • users — accounts and credentials
  • user_preferences — generic per-user JSON blobs (/api/v4/me/settings)
  • global_settings — system-wide key/value rows (/api/v4/advanced)
  • dashboard_settings — saved dashboards
  • user_mapping_settings — per-user mapping widget overrides
  • correlation_scripts — Lua correlation + script API rows
  • dashboard_alerts, export_share_links, transaction_view_tokens — supporting tables

The database is created automatically at settings_db_path.

Default schema

The canonical DDL is created in EnsureSettingsSchema in src/coordinator/services/settings_db.go (DuckDB: BIGINT ids, JSON data, etc.). Do not rely on older table names such as user_settings or hep_scripts.

Example Configurations

See examples in the examples/ directory:

  • homer-coordinator.json - Coordinator only
  • homer-writer.json - Ingest + Storage + Node
  • homer.json - Ingest + Storage + Node + Coordinator (all-in-one)

Security Considerations

  1. JWT secret — Set coordinator.jwt.secret (or HOMER_COORDINATOR_JWT_SECRET) to a strong random value in production. If omitted, Homer persists /.homer_jwt_secret beside settings_db_path and always enforces JWT on protected routes (SECURITY.md).
  2. Admin password — Prefer bcrypt via Users API or wizard; explicit admin_password_hash (SHA-256 hex) for bootstrap and --reset-admin-password. No default cleartext password is injected when hash is omitted.
  3. Statistics SQLPOST /api/v4/statistics/query validates rawquery (same rules as /api/v4/query).
  4. TLS — Enable use_tls for node connections in production
  5. Network — Restrict coordinator access via firewall/reverse proxy
  6. OAuth2 — Use HTTPS callback URLs in production