Quickstart (Docker)
This is the fastest path from nothing to your first search. You will run HeliosLogs in a container, log in, send a few events, and query them.
For a from-source build, see Install from source.
1. Run the container
HeliosLogs ships as a single container image. Build it from the repo and run it with two persistent volumes — one for data, one for the secret keys:
# Build the image (first time only).
make build
# Equivalent to: docker build -t helios:latest .
# Run it.
make runmake run is a thin wrapper around:
docker run -p 7300:7300 \
-v helios-data:/app/data \
-v helios-secret:/app/secret \
-e [email protected] \
-e HELIOS_ADMIN_PASSWORD=changeme \
helios:latest-p 7300:7300publishes the HTTP API and UI.helios-dataholds the log partitions and (single-node) control plane.helios-secretholds the encryption and JWT keys — keep this volume.HELIOS_ADMIN_EMAIL/HELIOS_ADMIN_PASSWORDbootstrap the first admin user.
Build dependencies
The default image is a FIPS build and compiles the AWS-LC validated module, so the first make build needs Go, Perl, and CMake in the build environment (already present in the rust:1-bookworm build stage). Subsequent builds are cached. See FIPS 140-3.
Open http://localhost:7300.
2. Log in
Because you set HELIOS_ADMIN_PASSWORD, an admin user already exists — log in with the email and password you passed.
No admin password?
If you start HeliosLogs without HELIOS_ADMIN_PASSWORD and no users exist yet, the browser shows a one-time setup wizard instead: the first visitor claims the instance by creating the admin account. Either path works — see First steps.
3. Send your first events
HeliosLogs accepts newline-delimited JSON (NDJSON) — one event per line — on POST /api/ingest. Each event routes to a (env, index, day) partition by its timestamp:
curl -X POST 'http://localhost:7300/api/ingest?env=default&index=adhoc' \
--data-binary @- <<'JSON'
{"timestamp":"2026-06-14T18:00:00Z","level":"INFO","service":"web","message":"hello from curl"}
{"timestamp":"2026-06-14T18:00:01Z","level":"ERROR","service":"web","message":"goodbye","error_type":"DeadlineExceeded","status":504}
JSON
# {"ingested":2,"errors":0}You don't have to declare any of those fields first — level, service, error_type, and status are all immediately queryable. That's schema-on-read.
4. Or load sample data
Prefer to explore with a realistic dataset? On a fresh install the search page offers a Load sample data button (an admin action that ingests a generated set of events). Click it and HeliosLogs will poll until the data appears.
5. Run your first searches
Go to Search and try these, picking a time range (top-right) that covers your events:
| Query | Finds |
|---|---|
error | events containing "error" anywhere in the message |
level:ERROR | events whose level field is ERROR |
service:web status:504 | implicit AND across two fields |
level:ERROR | stats count by service | error counts per service (table mode) |
Click a field value in the left field panel to filter by it; drag across the histogram to zoom into a time window.
Where to go next
- Understand the model: Core concepts
- Get real data flowing: Ingestion overview
- Learn the query language: Query language
- Set up your team: First steps and Users & RBAC