Skip to content

Docker

eodia analytics is built as a single image from the repository’s Dockerfile. It contains the API (which also serves the script and the collection endpoint), the interface and the worker; the argument given to the container chooses what it runs. docker-compose.prod.yml puts this image together with PostgreSQL and Caddy. All configuration goes through environment variables.

Fenêtre de terminal
docker build -t eodia-analytics .

It is based on Node 22. The applications run from their TypeScript sources with tsx; the interface (next build) and the script (/a.js, /p.js, with esbuild) are compiled at build time. Optionally, the build downloads the DB-IP Lite country database (CC BY 4.0 license), which GEOIP_DB then points to.

RoleCommandPortWhat it does
apidocker run eodia-analytics api4600REST /api/v1, authentication, /a.js, /p.js, /collect, /collect/server
webdocker run eodia-analytics web3600the Next.js interface
workerdocker run eodia-analytics worker—the job queue: partitions, retention, daily salt, generated views, export and erasure requests
all (default)docker run eodia-analytics3600, 4600api, web and worker in a single container

In all mode, a small supervisor starts the three processes, prefixes their logs ([api], [web], [worker]), forwards shutdown, and stops the whole container as soon as one of them dies: the orchestrator then restarts it in full.

docker-compose.prod.yml runs one service per role:

ServiceImageRole
dbpostgres:17-alpinethe database: configuration, raw data, views (data volume)
apieodia-analyticsthe API and collection; applies migrations on startup
workereodia-analyticsthe jobs (INPROCESS_WORKER=0 for the API)
webeodia-analyticsthe interface
caddycaddy:2-alpineautomatic HTTPS, ports 80 and 443
Fenêtre de terminal
docker compose -f docker-compose.prod.yml up -d --build # build and start
docker compose -f docker-compose.prod.yml logs -f api # follow the API
docker compose -f docker-compose.prod.yml ps # status and health of the services
docker compose -f docker-compose.prod.yml down # stop (volumes are kept)

docker/Caddyfile serves DOMAIN over HTTPS (Let’s Encrypt; ACME_EMAIL as the contact), compresses responses, sets HSTS and a few security headers, then routes:

PathTo
/a.js, /p.jsapi:4600: the script, and the preview mode drawing
/collect, /collect/*api:4600: the public collection endpoint and server-side collection
/api/*api:4600: REST and authentication
everything elseweb:3600

Caddy keeps no access log: it would store visitors’ IP addresses. If you put another proxy in front, also turn off its access log for /collect, or strip the addresses from it.

  • Writes are batched in the receiving process: one batch per second (COLLECT_FLUSH_MS) or every 500 events. A clean shutdown (SIGTERM) flushes the buffer; an abrupt shutdown loses at most one second of events.
  • Several API replicas can receive together: the daily salt is in the database, so the hash is the same everywhere. Visits, however, are assigned in memory: behind a load balancer without affinity, a visit can be split in two. Prefer affinity by address.
  • Several workers can run together: each one claims its jobs with FOR UPDATE SKIP LOCKED.
  • Raw data (collect) is partitioned by month; the worker creates partitions three months ahead. A DEFAULT partition serves as a safety net and must stay empty: Administration › Settings › Collection monitors it.
  • Each site’s retention period (25 months at most) is applied every night.

Two things are enough to rebuild an instance:

  • the database (db), for example with pg_dump; the views and the read role are recreated by the migrations;
  • the SECRET_KEY key: without it, the site secrets cannot be read.

eodia analytics is free software by Eodia.