Set up a complete monitoring stack with Prometheus for metrics collection and Grafana for visualization. Create dashboards to monitor system performance, set up alerting rules, and secure your monitoring infrastructure.
Prerequisites
- Root or sudo access
- At least 2GB RAM
- Open ports 3000, 9090, 9100
What this solves
Prometheus and Grafana provide a powerful monitoring solution for tracking system metrics, application performance, and infrastructure health. Prometheus collects and stores time-series data while Grafana creates visual dashboards and handles alerting. This combination gives you real-time visibility into your servers and applications with customizable alerts when issues arise.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of dependencies.
sudo apt update && sudo apt upgrade -yCreate system users for monitoring services
Create dedicated users for Prometheus and Grafana to run securely without root privileges.
sudo useradd --no-create-home --shell /bin/false prometheus
sudo useradd --no-create-home --shell /bin/false node_exporter
sudo useradd --system --no-create-home --shell /bin/false grafanaCreate directories for Prometheus
Set up the directory structure for Prometheus configuration and data storage.
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus /var/lib/prometheusDownload and install Prometheus
Download the latest Prometheus binary from the official releases and install it to the system.
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz
tar xzf prometheus-2.45.0.linux-amd64.tar.gz
sudo cp prometheus-2.45.0.linux-amd64/prometheus /usr/local/bin/
sudo cp prometheus-2.45.0.linux-amd64/promtool /usr/local/bin/
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtoolDownload and install Node Exporter
Node Exporter collects system metrics like CPU, memory, and disk usage that Prometheus will scrape.
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
tar xzf node_exporter-1.6.1.linux-amd64.tar.gz
sudo cp node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporterConfigure Prometheus
Create the main Prometheus configuration file that defines what metrics to collect and from where.
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "alert_rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- localhost:9093
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node_exporter'
static_configs:
- targets: ['localhost:9100']
- job_name: 'grafana'
static_configs:
- targets: ['localhost:3000']Set the correct ownership for the configuration file.
sudo chown prometheus:prometheus /etc/prometheus/prometheus.ymlCreate Prometheus systemd service
Configure Prometheus to run as a system service that starts automatically on boot.
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.listen-address=0.0.0.0:9090 \
--web.enable-lifecycle
[Install]
WantedBy=multi-user.targetCreate Node Exporter systemd service
Set up Node Exporter to run as a service and collect system metrics continuously.
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter --web.listen-address=0.0.0.0:9100
[Install]
WantedBy=multi-user.targetStart Prometheus services
Enable and start both Prometheus and Node Exporter services.
sudo systemctl daemon-reload
sudo systemctl enable prometheus node_exporter
sudo systemctl start prometheus node_exporterInstall Grafana
Add the official Grafana repository and install Grafana using your system's package manager.
sudo apt install -y software-properties-common wget
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafanaConfigure Grafana
Modify the Grafana configuration to set up basic security and access settings.
[server]
http_port = 3000
domain = example.com
root_url = http://example.com:3000
[security]
admin_user = admin
admin_password = SecureP@ssw0rd123
secret_key = your_secret_key_here
[users]
allow_sign_up = false
allow_org_create = false
[auth.anonymous]
enabled = falseStart Grafana service
Enable Grafana to start on boot and start the service now.
sudo systemctl enable --now grafana-server
sudo systemctl status grafana-serverConfigure firewall rules
Open the necessary ports for Prometheus, Node Exporter, and Grafana to communicate.
sudo ufw allow 9090/tcp comment 'Prometheus'
sudo ufw allow 9100/tcp comment 'Node Exporter'
sudo ufw allow 3000/tcp comment 'Grafana'
sudo ufw reloadAdd Prometheus data source to Grafana
Access Grafana at http://your-server-ip:3000 and log in with admin credentials. Navigate to Configuration > Data Sources and add Prometheus with URL http://localhost:9090.
curl -X POST \
http://admin:SecureP@ssw0rd123@localhost:3000/api/datasources \
-H 'Content-Type: application/json' \
-d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://localhost:9090",
"access": "proxy",
"isDefault": true
}'Import system monitoring dashboard
Import a pre-built dashboard for Node Exporter metrics to visualize system performance immediately.
curl -X POST \
http://admin:SecureP@ssw0rd123@localhost:3000/api/dashboards/import \
-H 'Content-Type: application/json' \
-d '{
"dashboard": {
"id": 1860,
"title": "Node Exporter Full"
},
"inputs": [{
"name": "DS_PROMETHEUS",
"type": "datasource",
"pluginId": "prometheus",
"value": "Prometheus"
}]
}'Create basic alerting rules
Set up Prometheus alerting rules for common system issues like high CPU usage and low disk space.
groups:
- name: system_alerts
rules:
- alert: HighCPUUsage
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "High CPU usage detected"
description: "CPU usage is above 80% for more than 5 minutes"
- alert: LowDiskSpace
expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
for: 2m
labels:
severity: critical
annotations:
summary: "Low disk space"
description: "Disk space is below 10%"
- alert: HighMemoryUsage
expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
for: 5m
labels:
severity: warning
annotations:
summary: "High memory usage"
description: "Memory usage is above 90%"Set correct ownership and reload Prometheus configuration.
sudo chown prometheus:prometheus /etc/prometheus/alert_rules.yml
sudo systemctl reload prometheusSecure with reverse proxy
For production deployments, consider placing Grafana behind a reverse proxy with SSL termination. You can use Traefik with automatic SSL for this purpose.
[server]
domain = monitoring.example.com
root_url = https://monitoring.example.com
serve_from_sub_path = false
[security]
cookie_secure = true
strict_transport_security = trueVerify your setup
Check that all services are running correctly and collecting metrics.
sudo systemctl status prometheus node_exporter grafana-server
curl http://localhost:9090/metrics
curl http://localhost:9100/metrics
curl http://localhost:3000/api/healthAccess the web interfaces to verify functionality.
echo "Prometheus: http://$(curl -s ifconfig.me):9090"
echo "Node Exporter: http://$(curl -s ifconfig.me):9100"
echo "Grafana: http://$(curl -s ifconfig.me):3000"Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Prometheus won't start | Configuration syntax error | promtool check config /etc/prometheus/prometheus.yml |
| Node Exporter metrics missing | Service not running or firewall blocking | sudo systemctl restart node_exporter && curl localhost:9100/metrics |
| Grafana login fails | Incorrect credentials or service down | Check /var/log/grafana/grafana.log for errors |
| Data source connection fails | Prometheus not accessible from Grafana | Verify Prometheus URL is http://localhost:9090 |
| Alerts not firing | Alert rules syntax error | promtool check rules /etc/prometheus/alert_rules.yml |
| Permission denied errors | Incorrect file ownership | sudo chown prometheus:prometheus /etc/prometheus/* |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Default versions
PROMETHEUS_VERSION="2.45.0"
NODE_EXPORTER_VERSION="1.6.1"
GRAFANA_VERSION="10.2.2"
# Usage function
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Install and configure Grafana with Prometheus for system monitoring"
echo ""
echo "Options:"
echo " -h, --help Show this help message"
echo " --prometheus-port Prometheus port (default: 9090)"
echo " --grafana-port Grafana port (default: 3000)"
echo " --node-exporter-port Node exporter port (default: 9100)"
exit 1
}
# Parse arguments
PROMETHEUS_PORT=9090
GRAFANA_PORT=3000
NODE_EXPORTER_PORT=9100
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
;;
--prometheus-port)
PROMETHEUS_PORT="$2"
shift 2
;;
--grafana-port)
GRAFANA_PORT="$2"
shift 2
;;
--node-exporter-port)
NODE_EXPORTER_PORT="$2"
shift 2
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
usage
;;
esac
done
# Cleanup function for rollback
cleanup() {
echo -e "${RED}[ERROR] Installation failed. Cleaning up...${NC}"
systemctl stop prometheus node_exporter grafana-server 2>/dev/null || true
systemctl disable prometheus node_exporter grafana-server 2>/dev/null || true
userdel prometheus 2>/dev/null || true
userdel node_exporter 2>/dev/null || true
userdel grafana 2>/dev/null || true
rm -rf /etc/prometheus /var/lib/prometheus /usr/local/bin/prometheus /usr/local/bin/promtool /usr/local/bin/node_exporter
rm -f /etc/systemd/system/prometheus.service /etc/systemd/system/node_exporter.service
}
trap cleanup ERR
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root${NC}"
exit 1
fi
# Detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}Cannot detect distribution${NC}"
exit 1
fi
echo -e "${GREEN}[1/12] Updating system packages...${NC}"
$PKG_UPDATE
echo -e "${GREEN}[2/12] Installing required packages...${NC}"
$PKG_INSTALL wget tar curl
echo -e "${GREEN}[3/12] Creating system users...${NC}"
useradd --no-create-home --shell /bin/false prometheus 2>/dev/null || true
useradd --no-create-home --shell /bin/false node_exporter 2>/dev/null || true
useradd --system --no-create-home --shell /bin/false grafana 2>/dev/null || true
echo -e "${GREEN}[4/12] Creating Prometheus directories...${NC}"
mkdir -p /etc/prometheus /var/lib/prometheus
chown prometheus:prometheus /etc/prometheus /var/lib/prometheus
chmod 755 /etc/prometheus /var/lib/prometheus
echo -e "${GREEN}[5/12] Downloading and installing Prometheus...${NC}"
cd /tmp
wget -q "https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
tar xzf "prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
cp "prometheus-${PROMETHEUS_VERSION}.linux-amd64/prometheus" /usr/local/bin/
cp "prometheus-${PROMETHEUS_VERSION}.linux-amd64/promtool" /usr/local/bin/
chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool
chmod 755 /usr/local/bin/prometheus /usr/local/bin/promtool
echo -e "${GREEN}[6/12] Downloading and installing Node Exporter...${NC}"
wget -q "https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz"
tar xzf "node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz"
cp "node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter" /usr/local/bin/
chown node_exporter:node_exporter /usr/local/bin/node_exporter
chmod 755 /usr/local/bin/node_exporter
echo -e "${GREEN}[7/12] Configuring Prometheus...${NC}"
cat > /etc/prometheus/prometheus.yml << EOF
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:${PROMETHEUS_PORT}']
- job_name: 'node_exporter'
static_configs:
- targets: ['localhost:${NODE_EXPORTER_PORT}']
- job_name: 'grafana'
static_configs:
- targets: ['localhost:${GRAFANA_PORT}']
EOF
chown prometheus:prometheus /etc/prometheus/prometheus.yml
chmod 644 /etc/prometheus/prometheus.yml
echo -e "${GREEN}[8/12] Creating systemd services...${NC}"
cat > /etc/systemd/system/prometheus.service << EOF
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \\
--config.file /etc/prometheus/prometheus.yml \\
--storage.tsdb.path /var/lib/prometheus/ \\
--web.console.templates=/etc/prometheus/consoles \\
--web.console.libraries=/etc/prometheus/console_libraries \\
--web.listen-address=0.0.0.0:${PROMETHEUS_PORT} \\
--web.enable-lifecycle
Restart=always
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/node_exporter.service << EOF
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter --web.listen-address=0.0.0.0:${NODE_EXPORTER_PORT}
Restart=always
[Install]
WantedBy=multi-user.target
EOF
echo -e "${GREEN}[9/12] Installing Grafana...${NC}"
case "$ID" in
ubuntu|debian)
$PKG_INSTALL software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" > /etc/apt/sources.list.d/grafana.list
apt update
$PKG_INSTALL grafana
;;
*)
cat > /etc/yum.repos.d/grafana.repo << EOF
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
EOF
$PKG_INSTALL grafana
;;
esac
echo -e "${GREEN}[10/12] Starting services...${NC}"
systemctl daemon-reload
systemctl enable prometheus node_exporter grafana-server
systemctl start prometheus node_exporter grafana-server
echo -e "${GREEN}[11/12] Configuring firewall...${NC}"
if command -v ufw &> /dev/null; then
ufw allow ${PROMETHEUS_PORT}/tcp
ufw allow ${NODE_EXPORTER_PORT}/tcp
ufw allow ${GRAFANA_PORT}/tcp
elif command -v firewall-cmd &> /dev/null; then
firewall-cmd --permanent --add-port=${PROMETHEUS_PORT}/tcp
firewall-cmd --permanent --add-port=${NODE_EXPORTER_PORT}/tcp
firewall-cmd --permanent --add-port=${GRAFANA_PORT}/tcp
firewall-cmd --reload
fi
echo -e "${GREEN}[12/12] Verifying installation...${NC}"
sleep 5
# Verification checks
for service in prometheus node_exporter grafana-server; do
if systemctl is-active --quiet $service; then
echo -e "${GREEN}✓ $service is running${NC}"
else
echo -e "${RED}✗ $service is not running${NC}"
exit 1
fi
done
# Check if ports are listening
for port in $PROMETHEUS_PORT $NODE_EXPORTER_PORT $GRAFANA_PORT; do
if netstat -tuln 2>/dev/null | grep -q ":$port " || ss -tuln 2>/dev/null | grep -q ":$port "; then
echo -e "${GREEN}✓ Port $port is listening${NC}"
else
echo -e "${YELLOW}⚠ Port $port may not be ready yet${NC}"
fi
done
# Cleanup temporary files
rm -rf /tmp/prometheus-* /tmp/node_exporter-*
echo -e "${GREEN}"
echo "=============================================="
echo "Installation completed successfully!"
echo "=============================================="
echo "Prometheus: http://localhost:${PROMETHEUS_PORT}"
echo "Grafana: http://localhost:${GRAFANA_PORT}"
echo "Default Grafana credentials: admin/admin"
echo "Node Exporter: http://localhost:${NODE_EXPORTER_PORT}"
echo "=============================================="
echo -e "${NC}"
Review the script before running. Execute with: bash install.sh