Ingest receiver

The ingest receiver accepts beacons from browsers and serves the collector bundle. The docker/ingest stack ships Ambilobe.Ingest with the collector built into the image, so a deployment needs no separate CDN.

Bring the receiver up after the datastores. It writes events to ClickHouse and reads its per-app config from Postgres, and it applies pending rum_config migrations on startup.

What the receiver does #

  • Accepts beacons at POST /v1/events.
  • Serves the @ambilobe/rum-web browser bundle at GET /v1/rum/*.
  • Validates, enriches, rate-limits, and writes events into the ClickHouse rum.events table.
  • Reads tenants, apps, tokens, and policies from the rum_config Postgres database.

Required configuration #

Two connection strings are required: the rum_config Postgres database and the ClickHouse rum database. Compose refuses to start the container if either is missing, and the receiver itself exits with a single FATAL log line if the credentials do not actually work.

docker/ingest/.env bash
# docker/ingest/.env
INGEST_HTTP_PORT=8081

# Required: rum_config Postgres. Host `postgres` is the docker/pg
# service name on the shared `ambilobe` network.
INGEST_CONFIGDB_CONNECTIONSTRING=Host=postgres;Port=5432;Database=rum_config;Username=ambilobe;Password=CHANGEME

# Required: ClickHouse rum.events. Host `clickhouse` is the
# docker/clickhouse service name on the shared `ambilobe` network.
INGEST_CLICKHOUSE_CONNECTIONSTRING=Host=clickhouse;Port=8123;Database=rum;Username=ambilobe;Password=CHANGEME

Optional configuration #

The most common optional settings:

  • GeoIP (INGEST_GEOIP_DBPATH, INGEST_GEOIP_HOST_PATH): optional. Leave the path empty to disable it; the receiver then logs a warning at startup and emits empty geo columns. To enable it, set both the in-container path and the matching host path.
  • Schema migrations (INGEST_CONFIGDB_AUTOMIGRATE): apply pending rum_config migrations on startup. Set false to manage the schema out of band.
  • Rate-cap single-instance flag (INGEST_RATECAP_EXPECTSINGLEINSTANCE): rate caps are enforced per pod, so set this true to acknowledge a single-instance deployment and silence the startup warning. See Configuration for the multi-replica trade-off.
  • Public base URL: the receiver's public origin is stored on its ingest service row (its PublicBaseUrl), not as a container env var. A superuser sets it when registering the receiver. See Routing.
docker/ingest/.env bash
# docker/ingest/.env (selected optional settings)

# GeoIP is optional. Leave the path empty to disable it entirely.
INGEST_GEOIP_DBPATH=
INGEST_GEOIP_HOST_PATH=/dev/null

# Apply pending rum_config migrations on startup.
INGEST_CONFIGDB_AUTOMIGRATE=true

# Rate caps are enforced in-process. Acknowledge a single-instance
# deployment to silence the startup warning.
INGEST_RATECAP_EXPECTSINGLEINSTANCE=false

# Serve the collector bundle from /v1/rum/*. Set false to front it
# with a CDN or edge cache instead.
INGEST_COLLECTOR_SERVE_ASSETS=true

Environment variable conventions #

The Compose file uses two substitution forms. Required credentials use ${VAR:?msg} so docker compose hard-fails before the container starts when the value is unset. Optional settings use ${VAR:-default} to fall back to a sane default.

docker/ingest/docker-compose.yml yaml
# In docker/ingest/docker-compose.yml, a required credential uses
# the ${VAR:?msg} form so compose hard-fails before the container starts:
Ingest__ConfigDb__ConnectionString: ${INGEST_CONFIGDB_CONNECTIONSTRING:?INGEST_CONFIGDB_CONNECTIONSTRING is required (see .env.example)}

# An optional setting gets a sane default with ${VAR:-default}:
Ingest__Collector__ServeAssets: ${INGEST_COLLECTOR_SERVE_ASSETS:-true}

Health and metrics #

The receiver exposes /healthz, which checks both backends, and /metrics, a Prometheus scrape target under the meter name ambilobe.ingest. The container healthcheck polls /healthz.

The collector bundle #

The collector version is baked into the image at build time, so the receiver serves the matching bundle with no separate CDN. To put a CDN in front of it, point the CDN at the receiver as origin and set INGEST_COLLECTOR_SERVE_ASSETS=false if you want the receiver to stop serving the bundle itself.