Ω…ΫŒΩ† Ω…ΩˆΨ§Ψ― ΩΎΨ± جائیں

πŸ—οΈ Architecture β€” How the Stack Connects

Understanding the architecture before installing prevents confusion later. This chapter explains every connection, every port, and every data flow in plain language.


πŸ—ΊοΈ Full Stack Architecture​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ YOUR SERVER / VM β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ healthtune β”‚ β”‚ trackx β”‚ ← Your Node.js apps β”‚
β”‚ β”‚ API (PM2) β”‚ β”‚ API (PM2) β”‚ managed by PM2 β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ OTEL SDK β”‚ OTEL SDK β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ gRPC :4317 β”‚
β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ OTEL Collector β”‚ receives traces from apps β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ forwards traces β”‚
β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Tempo β”‚ :3200 stores traces β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β–Ό β–Ό β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚Prom. β”‚ β”‚ Loki β”‚ β”‚ Grafana β”‚ :3000 β”‚
β”‚ β”‚:9090 β”‚ β”‚ :3100 β”‚ β”‚ (Dashboards) β”‚ Browser β”‚
β”‚ β””β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ scrapes β”‚ receives logs β”‚
β”‚ β–Ό β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚Node β”‚ β”‚ Promtail β”‚ reads PM2 log files β”‚
β”‚ β”‚Expo. β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚:9100 β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“¦ Component Roles​

Prometheus (Metrics)​

  • Pull model β€” Prometheus goes out and fetches metrics from targets
  • Scrapes /metrics endpoint on your apps and Node Exporter
  • Stores data in its own time-series database (TSDB) on disk
  • Query language: PromQL

Node Exporter (Host Metrics)​

  • A small agent that exposes system metrics at http://localhost:9100/metrics
  • Prometheus scrapes this to get CPU, RAM, disk, network stats
  • You never interact with it directly β€” just let it run

Loki (Logs)​

  • Push model β€” Promtail pushes logs to Loki
  • Does NOT index full log content (much cheaper than Elasticsearch)
  • Indexes only labels (app, level, host, etc.)
  • Query language: LogQL

Promtail (Log Shipper)​

  • Reads log files from disk (PM2 logs, Docker logs, syslog)
  • Attaches labels to each log line and pushes to Loki at http://loki:3100
  • Similar role to Filebeat in the ELK stack

Tempo (Traces)​

  • Push model β€” apps send traces via OTEL protocol
  • Stores traces efficiently on disk (designed for high volume)
  • Can receive traces via OTLP gRPC (4317) or HTTP (4318)
  • Acts as a middleman between your apps and Tempo
  • Lets you add processors (sampling, filtering, enriching)
  • Without it: apps send directly to Tempo on port 4317
  • With it: apps β†’ Collector β†’ Tempo (more control)

Grafana (Visualization)​

  • Connects to all data sources: Prometheus, Loki, Tempo
  • You build dashboards with panels (graphs, tables, logs, trace views)
  • The only tool you open in a browser

πŸ”„ Data Flow by Type​

Metrics Flow​

App exposes /metrics endpoint
↓ (Prometheus scrapes every 15s)
Prometheus stores in TSDB
↓ (Grafana queries via PromQL)
Grafana dashboard panel

Logs Flow​

PM2 writes logs to /home/user/.pm2/logs/*.log
↓ (Promtail tails the files)
Promtail adds labels and pushes
↓ (HTTP push to Loki port 3100)
Loki indexes labels + stores log lines
↓ (Grafana queries via LogQL)
Grafana logs panel

Traces Flow​

User HTTP request hits your app
↓ (OTEL SDK creates a trace)
tracing.js sends to port 4317
↓ (OTEL Collector β†’ Tempo)
Tempo stores trace
↓ (Grafana Tempo data source)
Grafana trace visualization

πŸ”Œ Complete Port Map​

PortContainerProtocolDirectionUsed By
3000GrafanaHTTPInboundYour browser
9090PrometheusHTTPInboundBrowser / Grafana
3100LokiHTTPInboundPromtail push / Grafana
3200TempoHTTPInboundGrafana queries
4317OTEL Collector / TempogRPCInboundYour Node.js apps
4318OTEL CollectorHTTPInboundApps (HTTP alternative)
9100Node ExporterHTTPInboundPrometheus scrape
9080PromtailHTTPInternalMetrics about Promtail

Minimum ports to expose externally (firewall rules):

  • 3000 β€” open Grafana in your browser
  • 4317 β€” apps send traces (if apps are on a different server)

All other ports can stay internal (container-to-container via Docker network).


🐳 Docker Networking Rule​

When containers talk to each other inside Docker Compose, use the service name β€” not localhost:

FromToUse This URL
Grafana β†’ Prometheushttp://prometheus:9090
Promtail β†’ Lokihttp://loki:3100
OTEL Collector β†’ Tempohttp://tempo:4317
Prometheus β†’ Node Exporterhttp://node-exporter:9100

But from your PM2 apps on the host machine, use localhost:

// In tracing.js (app runs on host, not in Docker)
url: 'http://localhost:4317'

πŸ’Ύ Data Storage (What Lives Where)​

All persistent data uses Docker named volumes:

ToolWhat It StoresVolume
PrometheusTime-series metricsprometheus_data
LokiLog chunks + indexloki_data
TempoTrace blockstempo_data
GrafanaDashboards, users, settingsgrafana_data

⚠️ docker compose down -v permanently deletes all volumes. Use only for a clean wipe. Use docker compose down (no -v) to stop containers while keeping all data.


🧱 Deployment Options​

OptionSetupBest For
Docker Compose on one VMThis guideSmall-medium teams, simplest
Separate VMs per toolManual configScaling independently
Kubernetes with Helmkube-prometheus-stack chartK8s environments
Grafana Cloud (managed)Zero opsTeams avoiding self-hosting

This documentation covers Docker Compose on one server.