Skip to content

Quickstart

This is the golden path: account → API key → drop the agent into Compose → see logs and metrics in the UI.

You will not write any application code in this guide. The agent collects host and container metrics, tails container stdout/stderr, and scrapes any Prometheus /metrics endpoint you already expose — opt-in per container via Docker labels.

Create an account at app.getlumin.dev/signup. Every account starts on the free Hobby tier, and signup needs no card. The Terms of Service and the Privacy Policy apply.

Once your account exists, sign in at app.getlumin.dev. The ten minutes this guide promises start now.

You land in a default project. Projects are the unit of tenancy — every API key, every log row, every metric belongs to exactly one project. For now, the default project is fine; you can rename it under Settings → Project.

Open Settings → API keys → New key. Name it something like lumin-agent and leave Kind on “Server / agent” (the default). You will see a key that starts with lmn_priv_… — copy it now. Lumin never shows the secret again.

Browser app instead? Pick Kind = Browser SDK instead. You’ll get a lmn_pub_* key that can only post browser events — safe to bake into a frontend bundle. See the Browser SDK guide.

This key authenticates the agent. It is a write-only ingest credential: it can POST /v1/logs, /v1/metrics, /v1/events, and /v1/agent/snapshot for this project only. It cannot read any data and cannot reach the app UI. If it ever leaks, rotate it from the same screen.

Add three blocks to your existing docker-compose.yml:

services:
# ...your existing services...
lumin-docker-proxy:
image: wollomatic/socket-proxy:1.13.1
restart: unless-stopped
user: "0:0"
environment:
SP_LISTENIP: 0.0.0.0
SP_ALLOWFROM: lumin-agent
SP_ALLOW_HEAD: /_ping
SP_ALLOW_GET: '/v1\.[0-9]+/containers/(json|[0-9a-f]{64}/(json|stats|logs))'
SP_ALLOWHEALTHCHECK: "true"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
read_only: true
cap_drop: [ALL]
security_opt: ["no-new-privileges:true"]
healthcheck:
test: ["CMD", "/healthcheck"]
interval: 5s
timeout: 3s
retries: 5
start_period: 5s
lumin-agent:
image: luminmonitor/lumin-agent:latest
restart: unless-stopped
environment:
LUMIN_API_KEY: ${LUMIN_AGENT_API_KEY} # the lmn_priv_... you minted
LUMIN_ENDPOINT: https://api.getlumin.dev
LUMIN_HOSTNAME: ${HOSTNAME:-prod-1}
LUMIN_INTERVAL: 15s
DOCKER_HOST: tcp://lumin-docker-proxy:2375
HOST_PROC: /host/proc
HOST_SYS: /host/sys
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
read_only: true
tmpfs: [/tmp]
cap_drop: [ALL]
security_opt: ["no-new-privileges:true"]
depends_on:
lumin-docker-proxy:
condition: service_healthy

Put LUMIN_AGENT_API_KEY=lmn_priv_… in your .env next to the compose file, then:

Terminal window
docker compose up -d lumin-docker-proxy lumin-agent

The agent will register a host snapshot within fifteen seconds. Open Infrastructure in the UI and the host should appear.

luminmonitor/lumin-agent is public, so the pull needs no docker login. It ships linux/amd64 and linux/arm64 in one manifest — an Arm host (Hetzner CAX, Oracle Ampere, Raspberry Pi) pulls the same tag as an x86 host. Use :latest to follow releases, or pin a version like luminmonitor/lumin-agent:0.1.0 in production. See Image tags and platforms.

Not using Compose? The agent has no Compose dependency — it reads the Docker API and Docker labels. See Run without Compose for the docker run equivalent, and for what works on Swarm, Portainer, and Coolify.

The lumin-docker-proxy sidecar is not optional. It mediates every Docker API call the agent makes. See the agent security model for why mounting /var/run/docker.sock:ro directly is not safe.

4. Opt your existing services into log shipping

Section titled “4. Opt your existing services into log shipping”

The agent does not tail any container by default. To stream a container’s stdout/stderr into Lumin, add two Docker labels:

services:
api:
image: my-api:latest
labels:
lumin.logs: "true"
lumin.service: "api" # optional; defaults to container name

Redeploy with docker compose up -d api. Within thirty seconds the agent discovers the new label, opens a follow-stream against the container, and starts forwarding lines. Open Logs in the UI — WHERE service = "api" should start scrolling in real time.

JSON log lines with a level field are parsed as structured logs (Caddy’s access logs, any logger writing JSON to stdout). Unstructured lines fall back to a best-effort level sniff (error, warn, info, …) and default to INFO when nothing matches.

If a service already exposes a Prometheus /metrics endpoint (Spring Boot Actuator, prometheus/client_golang, FastAPI middleware, …), three more labels are all you need:

services:
api:
image: my-api:latest
labels:
lumin.logs: "true"
lumin.service: "api"
lumin.metrics: "true"
lumin.metrics.port: "8080"
lumin.metrics.framework: "gin" # gin | spring | express | fastapi | axum

The framework label tells the agent how to normalise stack-specific names into Lumin’s canonical http.requests / http.latency_ms / http.errors schema, so different services chart side by side. See the stack guides for the exact metric names each framework emits and the framework value to pass.

If you want per-user session timelines, install @lumin-monitor/browser in your frontend. The same guide covers how to tag your server-side logs with the browser session id so you can filter them with attr.session_id:…. See the Browser SDK guide for the full setup.