All-in-one repo to spin up a monitoring & logging stack on Docker. Target: Proxmox LXC (unprivileged) running Debian 12 + Docker.
# 1) Copy repo to your LXC host (monstack), then:
cp .env.example .env 2>/dev/null || true # if you keep an example
# Edit .env and set GRAFANA_ADMIN_PASSWORD
docker compose pull
docker compose up -dServices:
- Grafana: http://:${GRAFANA_PORT}
- Prometheus: http://:${PROMETHEUS_PORT}
- Loki: http://:${LOKI_PORT}
- Alertmanager: http://:${ALERTMANAGER_PORT}
- Tempo UI / Trace API: http://:${TEMPO_PORT}
- Pyroscope: http://:${PYROSCOPE_PORT} (view flamegraphs directly in Pyroscope UI)
- Mimir (Prometheus-compatible API): http://:${MIMIR_PORT}
- OTLP Collector (gRPC ${OTELCOL_OTLP_GRPC_PORT}, HTTP ${OTELCOL_OTLP_HTTP_PORT}, metrics ${OTELCOL_METRICS_PORT})
- Promtail (container + host logs → Loki)
- Demo service (optional overlay): http://:18000
- Demo Nginx gateway + exporter (optional overlay): http://:${NGINX_PORT:-18080}
- NPMplus (demo reverse proxy UI): http://:${NPMPLUS_UI_PORT:-18081} (HTTP ingress on ${NPMPLUS_HTTP_PORT:-18090}, HTTPS on ${NPMPLUS_HTTPS_PORT:-18443})
docker-compose.yml— all servicesprometheus/prometheus.yml— scrape targets + alerting -> Alertmanagerprometheus/alert_rules/*.yml— example alerting rulesloki/loki-config.yaml— filesystem backend with boltdb-shipper + compactor retentionotel-collector/config.yaml— OpenTelemetry Collector pipelines (OTLP ingest → Tempo/Mimir/Prometheus/Loki)tempo/tempo.yaml— Tempo single-binary config + local filesystem storagemimir/mimir.yaml— Grafana Mimir single-binary config + local filesystem storagepyroscope/config.yaml— Pyroscope single-binary config + local filesystem storagepromtail/promtail-config.yaml— ships Docker and system logs to Lokigrafana/provisioning/*— auto-provision Prometheus & Loki datasources and dashboardsalertmanager/alertmanager.yml— minimal route/receiver (extend as needed)scripts/deploy_stack.sh— SSH deploy helpermongo-exporter/— lightweight MongoDB → Prometheus exporter used by the demo overlaytelegraf/telegraf.conf— Telegraf collector (nginx stub_status + host stats + access log tail for the Grafana Nginx board)TODO.md— live checklist/report for the actively requested fixes (linked from AGENTS.md)
Note: Promtail now ships system & container logs directly to Loki; application telemetry uses the OpenTelemetry Collector.
Core (folder Root):
- Stack Overview (
grafana/dashboards/stack-overview.json) — infrastructure + service SLO view with logs/traces links. - Demo Service Deep Dive (
grafana/dashboards/demo-service.json) — queue depth, latency, error insight for the Node.js workload (backed by/metricsondemo-app).
Imported (folder imported/ — automatically provisioned):
- Pino HTTP Logs (
grafana/dashboards/imported/pino-http-logs.json, Grafana ID 21900) — live Loki queries overpinoJSON logs with filters for service / level / status codes. - Node Exporter Full (
grafana/dashboards/imported/node-exporter-full.json, ID 1860) — detailed host metrics fromnode-exporter+cadvisor. - Redis Exporter (
grafana/dashboards/imported/redis-dashboard.json, ID 11835) — Redis cache activity viaredis_exporter. - MongoDB Overview (
grafana/dashboards/imported/mongodb-overview.json, ID 2583) — MongoDB storage + ops frommongodb-exporter. - NodeJS Application (
grafana/dashboards/imported/nodejs-application.json, ID 11159) — process/runtime stats from Prometheus default metrics (viaprom-client). - Nginx (
grafana/dashboards/imported/nginx-metrics.json, ID 14900) — request/latency metrics from the demo Nginx gateway hittingdemo-app.
-
Ensure services are running
docker compose -f docker-compose.yml -f docker-compose.demo.yml ps
Confirm
grafana,otel_collector,prometheus,tempo,loki,mimir,pyroscope, and the demo services are allUp. -
Generate telemetry load (optional but recommended)
DEMO_BASE_URL=http://localhost:18000 \ DEMO_SMOKE_ITERATIONS=25 \ DEMO_SMOKE_PAUSE_MS=250 \ npm --prefix demo-app run simulate
-
Grafana UI — open
http://localhost:${GRAFANA_PORT}(default3000) and check:- Dashboard Stack Overview shows host CPU/memory, request rate, job depth, logs pane, and Tempo trace search.
- Dashboard Demo Service Deep Dive shows request latency histograms, error counts, job durations, queue states, log stream, and slow traces.
- Folder imported/ contains: Pino HTTP Logs (Loki), Node Exporter Full, Loki Stack Monitoring, Redis, MongoDB, NodeJS Application, and Nginx dashboards — all should show live data once the demo overlay + load generator are running.
-
Pyroscope UI — open
http://localhost:${PYROSCOPE_PORT}(default4040) to inspect live flamegraphs fromdemo-node-app. -
Traces & logs — from Grafana Explore you can:
- Query Tempo datasource for
service.name="demo-node-app". - Query Loki datasource
{service="demo-node-app"}to view structured logs.
- Query Tempo datasource for
Spin up data generators before deploying to Proxmox:
# Build the demo app image once
docker compose -f docker-compose.yml -f docker-compose.demo.yml build demo-app
# Start the full stack plus demo generators
docker compose -f docker-compose.yml -f docker-compose.demo.yml up -d
# Optional: run targeted smoke scenario (ensure stack is up)
docker compose -f docker-compose.yml -f docker-compose.demo.yml run --rm \
-e DEMO_SMOKE_ITERATIONS=30 \
demo-app npm run simulate
# Or from host with services exposed locally:
# DEMO_BASE_URL=http://localhost:18000 DEMO_SMOKE_ITERATIONS=30 npm --prefix demo-app run simulate
# # Optional tunables: DEMO_SMOKE_PAUSE_MS, DEMO_JOB_TIMEOUT_MSIncluded demo components (docker-compose.demo.yml):
demo-app— Node.js (Express) service with MongoDB + Redis + BullMQ, instrumented for traces, metrics, logs (exposed on port 18000)nginx+nginx-exporter— reverse proxy in front ofdemo-app(port${NGINX_PORT:-18080}) with metrics scraped by Prometheus.redis-exporter+mongodb-exporter— Redis exporter plus the custom Node-based Mongo Prometheus bridge inmongo-exporter/.telegraf_nginx— Telegraf agent that scrapes nginx stub_status + host metrics and tails the access logs (nginxlog_resp_bytes) for both the built-in nginx and NPMplus instances.npmplus— instance NPMplus lokal untuk mencoba konfigurasi proxy host dan menghasilkan log akses/galat yang sama dengan lingkungan produksi.demo-load— curl-based traffic generator that now targetsnginxto exercise proxy + exporter metrics.- Pyroscope data is produced directly by
demo-appvia the Pyroscope SDK mongo&redis— backing data stores used by the demo service (ephemeral volumes)- By default
NGINX_PORTmaps to18080; override it in.envif the port is taken.
Grafana dashboards should populate within ~1 minute; Pyroscope and Tempo will display synthetic profiles and traces. Tear down with:
docker compose -f docker-compose.yml -f docker-compose.demo.yml downThe demo overlay also ships NPMplus so you can:
- exercise the proxy-host UI without a second server,
- relay traffic to
demo-appthrough NPMplus, and - generate the same access/error logs that Telegraf tails for the Grafana dashboard (
agent,client_ip,verb, etc.).
Default port mapping:
| Component | Default |
|---|---|
| Public HTTP | http://localhost:${NPMPLUS_HTTP_PORT:-18090} |
| Public HTTPS | https://localhost:${NPMPLUS_HTTPS_PORT:-18443} |
| Admin UI |
http://localhost:${NPMPLUS_UI_PORT:-18081} (login using NPMPLUS_ADMIN_EMAIL / NPMPLUS_ADMIN_PASSWORD, default admin@demo.local / Demo1234!) |
| GoAccess UI | http://localhost:${NPMPLUS_GOACCESS_PORT:-18091} |
Quick tour:
docker compose -f docker-compose.yml -f docker-compose.demo.yml up -d npmplus(already included when you bring up the overlay).- Open the UI (default
http://localhost:18081) and follow the upstream onboarding wizard to create the first admin user. - Add a Proxy Host:
- Domain:
demo.local(or any test domain), - Scheme:
http, - Forward Hostname/IP:
demo_app, - Forward Port:
8000, - Enable “Block Common Exploits” and “Cache Assets”.
- Domain:
- Run the smoke test (
npm --prefix demo-app run simulate) so logs keep flowing.
Telegraf reads both the local nginx log (/var/log/nginx/proxy_access.log) and the NPMplus log directory (/npmplus-data/logs/...). No extra agent is required—Prometheus scrapes a single nginxlog_resp_bytes metric enriched with all the labels your dashboard expects.
Environment overrides:
NPMPLUS_HTTP_PORT,NPMPLUS_HTTPS_PORT,NPMPLUS_UI_PORT,NPMPLUS_GOACCESS_PORT,NPMPLUS_ACME_EMAIL,NPMPLUS_ADMIN_EMAIL,NPMPLUS_ADMIN_PASSWORD, andTZcan be set via.env. Set ACME email to a real address when requesting certificates; the defaultnpmplus@local.testis only meant for local testing.
Prefer SSH context for remote Docker access instead of exposing 0.0.0.0:2375.
Example: DOCKER_HOST=ssh://user@monstack docker compose up -d.
If you must enable TCP API, use TLS on port 2376 and firewall it strictly.
- Docker Remote API: use SSH or TLS; avoid 0.0.0.0:2375
- Limit who can reach Grafana/Prometheus/Loki/Tempo/Pyroscope/OTel Collector ports
- Secure OTLP ports if ingesting telemetry from remote hosts
- Change default Grafana admin password in
.env - Tune Loki retention in
.envandloki-config.yaml; adjust Tempo/Pyroscope retention and Mimir limits in their configs as needed