Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Monitoring with Prometheus and Grafana: Complete Setup

By Kokil Thapa | Last reviewed: September 2026

Production outages rarely announce themselves. You notice them when a client calls or a payment webhook fails. Monitoring with Prometheus and Grafana: Complete Setup gives you a pull-based metrics stack that watches CPU, memory, HTTP latency, queue depth, and database health before users feel pain. Prometheus collects time-series data. Grafana turns it into dashboards and alerts. This guide walks through a production-ready install on Ubuntu 24.04 for the PHP and Laravel stacks I maintain daily.

What does Monitoring with Prometheus and Grafana: Complete Setup include?

A complete stack has four layers. Prometheus pulls metrics from exporters and your app. Alertmanager routes firing alerts. Grafana queries Prometheus for charts. Node Exporter exposes host stats. This differs from push tools like NetData, which you can read about in our NetData zero-config monitoring guide.

Prometheus + Grafana StackNode ExporterHost metricsMySQL ExporterDB metricsApp /metricsLaravel routePrometheusPull + TSDBGrafanaDashboardsAlertmanagerSlack / emailScrape interval: 15s default
Monitoring with Prometheus and Grafana: Complete Setup architecture — exporters expose metrics, Prometheus scrapes and stores them, Grafana visualises, Alertmanager notifies.

Prometheus uses a pull model. It requests /metrics endpoints on a fixed interval. That keeps apps simple. They expose numbers; Prometheus handles storage and queries. Grafana never talks to exporters directly. It always queries Prometheus through PromQL.

Core components at a glance

  • Prometheus server — scrapes targets, evaluates alert rules, stores time-series data on disk.
  • Exporters — translate system or app state into Prometheus text format.
  • Grafana — dashboards, variables, and optional unified alerting.
  • Alertmanager — deduplicates, groups, and routes notifications.
  • Service discovery — optional; static configs work fine for small fleets.

How do you install Prometheus and Grafana on Ubuntu?

Start on a dedicated monitoring VM or the same server you watch. Separate hosts reduce blast radius. For sister sites on shared EC2, I run one Prometheus instance per environment. Use a non-root user and systemd units for clean restarts after deploys.

Install Prometheus 3.x

  1. Create a system user and directories:
sudo useradd --no-create-home --shell /usr/sbin/nologin prometheus
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus /var/lib/prometheus

Download the latest stable release from the official Prometheus download page. Extract binaries to /usr/local/bin/.

curl -LO https://github.com/prometheus/prometheus/releases/download/v3.2.1/prometheus-3.2.1.linux-amd64.tar.gz
tar xvf prometheus-3.2.1.linux-amd64.tar.gz
sudo cp prometheus-3.2.1.linux-amd64/prometheus /usr/local/bin/
sudo cp prometheus-3.2.1.linux-amd64/promtool /usr/local/bin/

Create /etc/prometheus/prometheus.yml:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

rule_files:
  - /etc/prometheus/rules/*.yml

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node'
    static_configs:
      - targets: ['app1.example.com:9100', 'app2.example.com:9100']

  - job_name: 'mysql'
    static_configs:
      - targets: ['db.example.com:9104']

Add a systemd unit at /etc/systemd/system/prometheus.service:

[Unit]
Description=Prometheus
After=network-online.target

[Service]
User=prometheus
Group=prometheus
ExecStart=/usr/local/bin/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/var/lib/prometheus \
  --web.listen-address=127.0.0.1:9090
Restart=always

[Install]
WantedBy=multi-user.target

Bind Prometheus to localhost. Put Nginx or Apache in front with TLS. Our Let's Encrypt and Certbot HTTPS guide covers the certificate side.

Install Grafana 11.x

sudo apt-get install -y apt-transport-https software-properties-common
sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install grafana
sudo systemctl enable --now grafana-server

Grafana listens on port 3000 by default. Change the admin password on first login. Add Prometheus as a data source at Configuration → Data sources → Prometheus with URL http://127.0.0.1:9090.

Prometheus Scrape Pipeline1. Discover2. Scrape3. ParseRelabelDrop / renameTSDB Block15-day retentionPromQLGrafana queriesFailed scrapes appear as up=0 — alert on that first
Each scrape cycle discovers targets, pulls /metrics, relabels series, and writes blocks Prometheus and Grafana query later.

Which exporters should you scrape for a Laravel production stack?

Host metrics alone miss app-level failures. A server can show 30% CPU while every queue job stalls. Layer exporters so you see the full picture from metal to business logic.

Node Exporter on every app server

curl -LO https://github.com/prometheus/node_exporter/releases/download/v1.9.0/node_exporter-1.9.0.linux-amd64.tar.gz
tar xvf node_exporter-1.9.0.linux-amd64.tar.gz
sudo cp node_exporter-1.9.0.linux-amd64/node_exporter /usr/local/bin/
sudo useradd --no-create-home node_exporter
sudo tee /etc/systemd/system/node_exporter.service <<'EOF'
[Unit]
Description=Node Exporter

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter --web.listen-address=127.0.0.1:9100
Restart=always

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now node_exporter

Watch node_memory_MemAvailable_bytes, node_filesystem_avail_bytes, and rate(node_cpu_seconds_total[5m]). Disk full errors kill Laravel logs and MySQL before CPU spikes.

MySQL, Redis, and Nginx exporters

For MySQL 9.7 or 8.4 LTS, run mysqld_exporter with a read-only monitoring user. Point it at port 9104. Redis 8.10 uses redis_exporter on 9121. Nginx needs the stub_status module plus nginx-prometheus-exporter.

On booking platforms like Adventure Third Pole Trek, queue backlog and DB connection counts matter more than raw CPU. Tie those metrics to user-facing symptoms.

Application metrics from Laravel

Install promphp/prometheus_client_php or expose a custom /metrics route behind IP allowlisting. Track HTTP request duration histograms, failed login counts, and queue job failures. Validate the route with our JSON formatter tool when debugging structured log payloads alongside metrics.

Never expose /metrics publicly without auth. Scrape over VPN or private network only. Prometheus should reach the target; the internet should not.

How do Prometheus and Grafana compare to other monitoring tools?

Teams often ask whether to adopt Prometheus or stick with Nagios, NetData, or a SaaS APM. Each fits a different ops maturity and team size.

ToolModelBest forTrade-off
Prometheus + GrafanaPull, PromQL, self-hostedMulti-service fleets, custom metrics, alert tuningYou operate storage, upgrades, and HA yourself
NagiosPush/check scriptsSimple up/down checks, legacy shopsWeak time-series; clunky dashboards
NetDataPush, per-host agentFast visibility on one serverHarder to centralise across many hosts
SaaS APM (Datadog, etc.)Agent + cloudTeams without ops headcountCost scales with hosts; Rs 15,000+/month (~USD 110) adds up

For ongoing server support contracts, Prometheus wins when you already run GitLab CI and Deployer. Metrics sit beside the same infrastructure you patch weekly. Read our Prometheus and Grafana full monitoring stack article for a lighter single-server variant.

Pick Your Monitoring Tier1–2 serversNetData or UptimeKuma checks3–10 serversPrometheus+ Grafana10+ servicesPrometheus HAThanos / MimirLaravel + MySQL + Redis stackNode + mysqld + redis + app /metrics
Prometheus and Grafana fit the 3–10 server sweet spot common on Nepal agency and SaaS deployments.

How do you build Grafana dashboards and Prometheus alert rules?

Dashboards without alerts are vanity. Alerts without runbooks wake people at 2 AM for nothing. Start with four golden signals: latency, traffic, errors, and saturation.

Import community dashboards first

Grafana.com hosts dashboard IDs you can import. Use 1860 for Node Exporter Full, 7362 for MySQL overview, and 11835 for Redis. Tweak panel thresholds to match your hardware. A 2 GB VPS behaves differently from a 16 GB production node.

Write alert rules that page humans sparingly

Store rules in /etc/prometheus/rules/alerts.yml:

groups:
  - name: host_alerts
    rules:
      - alert: HostDown
        expr: up{job="node"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Node exporter down on {{ $labels.instance }}"

      - alert: DiskSpaceLow
        expr: node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} < 0.10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Less than 10% disk free on {{ $labels.instance }}"

      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
        for: 3m
        labels:
          severity: critical
        annotations:
          summary: "5xx rate above 5% on {{ $labels.instance }}"

Install Alertmanager and point Prometheus at it. Route severity=critical to SMS or phone. Send warnings to Slack only. Full routing patterns live in our Alertmanager alerting guide.

Validate before you trust a dashboard

Run load tests or trigger a known failure. Confirm the graph moves and the alert fires within your for window. I've seen teams deploy Grafana panels that query the wrong job label for months. Use promtool check rules and promtool test rules in CI.

What production mistakes break Prometheus and Grafana setups?

Most failures I debug are config issues, not Prometheus bugs. The stack is stable when you respect retention, security, and label cardinality.

Cardinality explosions

Never put user IDs or order IDs in metric labels. Each unique label combination creates a new time series. A burst of label values can OOM Prometheus in minutes. Keep labels to environment, service, endpoint, and status code.

Scrape targets behind firewalls

Prometheus must reach each exporter. If your app servers sit behind UFW, allow port 9100 from the monitoring host IP only. Document the rule alongside SSH hardening from our SSH key-only auth guide.

Forgetting retention and backups

Default TSDB retention is 15 days. Set --storage.tsdb.retention.time=30d if disk allows. Prometheus data is not a backup. Pair metrics with nightly DB dumps covered in our automated server backups guide.

Top Setup FailuresHigh-cardinality labelsOOM / slow queriesPublic /metricsData leak riskUFW blocks scrapeup=0 false alarmsDashboards onlyNo AlertmanagerFix: private network + alert rules + retention planValidate with promtool before deploy
Avoid these four failures when completing Monitoring with Prometheus and Grafana: Complete Setup on production Linux hosts.

After every Deployer symlink swap, confirm PHP-FPM and queue workers still expose metrics. Opcache resets should not break scrape paths. Our Laravel queues with Redis production guide pairs well with queue-depth alerts.

For legal-tech portals like Notary Nepal, uptime during business hours matters most. Set maintenance windows in Alertmanager so planned deploys do not page the team. Document who responds and what "rollback" means.

Enterprise clients evaluating enterprise application development often ask for observability in the SOW. Prometheus plus Grafana satisfies that without locking you into proprietary agents.

Key Takeaways

  • Install Prometheus on a dedicated or co-located host; bind it to localhost and reverse-proxy Grafana with TLS.
  • Scrape Node Exporter, database exporters, and a secured Laravel /metrics route — host CPU alone is not enough.
  • Import Grafana dashboard 1860 first, then add alert rules for up==0, disk space, and 5xx error rates.
  • Keep label cardinality low; never expose metrics endpoints to the public internet.
  • Pair the stack with log review, backups, and a runbook — dashboards detect problems, they do not fix them.
  • Validate rules with promtool and test alerts before trusting them overnight.

People Also Ask

Do Prometheus and Grafana work with Laravel 13?

Yes. Laravel 13 runs on PHP 8.3 or higher. Expose metrics via a package or custom route. Scrape it like any other target. Framework version does not change the Prometheus pull model.

How much RAM does Prometheus need?

Budget 1–2 GB for a small fleet of five targets with moderate cardinality. High-cardinality apps need 4 GB or more. Watch TSDB head blocks with prometheus_tsdb_head_series.

Can Grafana send alerts without Alertmanager?

Grafana has built-in alerting that can notify Slack or email. For Prometheus-native rules, Alertmanager remains the standard. Many teams use both: Prometheus rules for infra, Grafana alerts for business KPIs.

Is Prometheus free for commercial use?

Yes. Prometheus and Grafana OSS are open source under Apache 2.0. You pay for compute, storage, and the time to operate them. Grafana Labs also sells Enterprise tiers with SSO and reporting if you outgrow OSS.

Ship observability before the next outage

Monitoring with Prometheus and Grafana: Complete Setup is not a weekend side project. It is baseline infrastructure for any Laravel or WordPress fleet you expect to run past launch day. Start with one app server, Node Exporter, and three alert rules. Expand to MySQL, Redis, and custom app metrics as traffic grows.

If you want the stack designed, installed, and tied into your existing Ubuntu server monitoring workflow, contact us for a scoped setup. You can also browse testing and optimization services or see live platforms in the portfolio. For related reading, see API monitoring with Prometheus and Grafana and Grafana dashboards practical guide. Strong metrics turn 3 AM guesswork into a five-minute fix.

Frequently Asked Questions

Installing Prometheus to scrape exporters on a schedule, storing metrics locally, wiring Grafana to Prometheus as a data source, and adding Alertmanager for Slack or email notifications on threshold breaches.

Budget 1–2 GB for a small fleet of five targets with moderate cardinality. High-cardinality apps need 4 GB or more. Watch TSDB head blocks with prometheus_tsdb_head_series.

Yes. Prometheus and Grafana OSS are open source under Apache 2.0. You pay for compute, storage, and the time to operate them.

Create a dedicated prometheus system user, download Prometheus 3.x binaries to /usr/local/bin, and write /etc/prometheus/prometheus.yml with scrape jobs for Prometheus itself, Node Exporter, and database targets. Run Prometheus via systemd bound to 127.0.0.1:9090. Install Grafana 11.x from the official APT repository, enable grafana-server, change the default admin password, and add Prometheus at http://127.0.0.1:9090 as a data source. Put Nginx or Apache with TLS in front of both services rather than exposing ports publicly.

Node Exporter on every app server exposes CPU, memory, and disk metrics on port 9100. Add mysqld_exporter on 9104 for MySQL 9.7 or 8.4 LTS, redis_exporter on 9121 for Redis 8.10, and nginx-prometheus-exporter when Nginx serves traffic. Host metrics alone miss queue stalls and connection exhaustion. Expose Laravel application metrics via promphp/prometheus_client_php or a custom /metrics route tracking HTTP latency histograms, failed logins, and queue job failures. Scrape over a private network only.

Prometheus uses a pull model with PromQL and suits multi-service fleets where you want custom metrics and alert tuning, but you operate storage and upgrades yourself. Nagios fits simple up/down checks but lacks strong time-series dashboards. NetData gives fast per-host visibility but is harder to centralise across many servers. SaaS APM like Datadog costs Rs 15,000+/month (~USD 110) and scales with host count. For teams already running GitLab CI and Deployer on three to ten servers, Prometheus plus Grafana is the practical self-hosted choice.

Grafana 11.x includes built-in alerting that can notify Slack or email directly from dashboard panels. For Prometheus-native alert rules evaluated by the Prometheus server, Alertmanager remains the standard routing layer for deduplication, grouping, and severity-based notification paths. Many production teams use both: Prometheus rules with Alertmanager for infrastructure alerts like HostDown and disk space, and Grafana alerts for business KPI panels. Route severity=critical to SMS or phone and send warnings to Slack only.

Yes. Laravel 13 runs on PHP 8.3 or higher and does not change the Prometheus pull model. Install promphp/prometheus_client_php or expose a custom /metrics route that returns Prometheus text format. Register the Laravel target in prometheus.yml alongside Node Exporter and database exporters. Track HTTP request duration, failed login counts, and queue job failures so you catch application-level failures when CPU still looks healthy. After Deployer symlink swaps, confirm PHP-FPM and queue workers still expose the scrape path.

The article recommends starting Prometheus with --web.listen-address=127.0.0.1:9090 and placing Nginx or Apache with TLS in front for external access. Binding to localhost reduces blast radius because Prometheus stores all scraped metrics and has no built-in authentication on its query API. The same pattern applies to Node Exporter on 127.0.0.1:9100. Never expose /metrics endpoints to the public internet without authentication. Allow scrape ports from the monitoring host IP only through UFW, documented alongside your SSH hardening rules.

Start with community dashboards from Grafana.com before building custom panels. Import dashboard ID 1860 for Node Exporter Full to see CPU, memory, and filesystem metrics. Use 7362 for MySQL overview and 11835 for Redis. Adjust panel thresholds to match your hardware because a 2 GB VPS behaves differently from a 16 GB production node. Dashboards without alerts are vanity, so pair imported panels with Prometheus alert rules for up==0, disk space below 10%, and 5xx error rates above 5%.

Store rules in /etc/prometheus/rules/alerts.yml and reference them from prometheus.yml. Start with HostDown when up{job="node"} == 0 for two minutes, DiskSpaceLow when root filesystem free space drops below 10% for five minutes, and HighErrorRate when the 5xx rate exceeds 5% over five minutes for three minutes. Point Prometheus alerting at Alertmanager on localhost:9093. Validate rules with promtool check rules and promtool test rules in CI before trusting them overnight. Trigger a known failure to confirm graphs move and alerts fire within the for window.

Each unique label combination creates a new time series in the TSDB. Putting user IDs, order IDs, or other high-cardinality values in metric labels can OOM Prometheus within minutes during traffic bursts. Keep labels limited to environment, service, endpoint, and HTTP status code. Watch prometheus_tsdb_head_series to track series growth. High-cardinality workloads need 4 GB RAM or more versus 1–2 GB for a small fleet with moderate labels. This is one of the most common production mistakes, not a Prometheus software bug.

You can co-locate Prometheus on the app server or use a dedicated monitoring VM. A separate host reduces blast radius when the application server fails under load. On shared EC2 infrastructure, running one Prometheus instance per environment keeps staging and production metrics isolated. Use static_configs in prometheus.yml for small fleets; service discovery is optional. Either way, Prometheus must reach every exporter target, so document UFW rules allowing port 9100 from the monitoring host IP only.

Default TSDB retention is 15 days. Set --storage.tsdb.retention.time=30d if disk space allows on your monitoring host. Prometheus metrics are operational visibility, not a backup strategy. Pair the stack with nightly database dumps from your existing backup workflow. After every Deployer symlink swap, confirm scrape targets still respond. Plan 1–2 GB RAM for five moderate targets and expand retention or memory as you add MySQL, Redis, and Laravel application metrics. Monitor disk usage on /var/lib/prometheus because full disks kill logging before CPU alerts fire.

The article highlights four recurring failures: label cardinality explosions from dynamic IDs in metrics, scrape targets blocked by UFW because Prometheus cannot reach exporters behind firewalls, missing retention planning with default 15-day storage and no backup pairing, and Grafana panels querying wrong job labels for months without validation. Also avoid exposing /metrics publicly, forgetting to re-check exporters after PHP-FPM reloads following Deployer deploys, and paging the team during planned maintenance without Alertmanager silence windows. Run promtool validation in CI and test alerts before overnight on-call coverage.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: