Configure comprehensive monitoring for MinIO object storage with Prometheus metrics collection and Grafana dashboards for performance, capacity, and health tracking.
Prerequisites
- MinIO server installed and running
- Root or sudo access
- Basic familiarity with Prometheus and Grafana
What this solves
MinIO provides detailed metrics for monitoring object storage performance, API requests, and resource usage. This tutorial sets up Prometheus to scrape MinIO metrics and configures Grafana dashboards for real-time visibility into your storage cluster's health, capacity utilization, and request patterns.
Step-by-step configuration
Install and configure Prometheus
First, install Prometheus to collect metrics from MinIO. We'll create a dedicated user and configure it as a systemd service.
sudo useradd --no-create-home --shell /bin/false prometheus
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
sudo chown prometheus:prometheus /usr/local/bin/promtool
Create Prometheus directories and configuration
Set up the required directories and create the main configuration file that will include MinIO as a scrape target.
sudo mkdir /etc/prometheus
sudo mkdir /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus
sudo chown prometheus:prometheus /var/lib/prometheus
Configure MinIO metrics endpoint
MinIO exposes Prometheus metrics on port 9000 by default. Add these environment variables to your MinIO configuration to ensure metrics are properly exposed.
MINIO_PROMETHEUS_AUTH_TYPE=public
MINIO_PROMETHEUS_URL=http://localhost:9000/minio/v2/metrics/cluster
MINIO_PROMETHEUS_JOB_ID=minio-job
Create Prometheus configuration file
Configure Prometheus to scrape MinIO metrics. This configuration includes both cluster and node-level metrics collection.
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "minio_alerts.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'minio-cluster'
metrics_path: /minio/v2/metrics/cluster
static_configs:
- targets: ['localhost:9000']
scrape_interval: 30s
scrape_timeout: 10s
- job_name: 'minio-node'
metrics_path: /minio/v2/metrics/node
static_configs:
- targets: ['localhost:9000']
scrape_interval: 30s
scrape_timeout: 10s
- job_name: 'minio-bucket'
metrics_path: /minio/v2/metrics/bucket
static_configs:
- targets: ['localhost:9000']
scrape_interval: 60s
scrape_timeout: 15s
Create MinIO alerting rules
Define alert conditions for critical MinIO metrics like disk usage, API errors, and node availability.
groups:
- name: minio
rules:
- alert: MinIODiskUsageHigh
expr: (minio_cluster_capacity_usable_free_bytes / minio_cluster_capacity_usable_total_bytes) * 100 < 10
for: 5m
labels:
severity: critical
annotations:
summary: "MinIO cluster disk usage is critically high"
description: "MinIO cluster has less than 10% free disk space remaining."
- alert: MinIONodeOffline
expr: up{job="minio-node"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "MinIO node is offline"
description: "MinIO node {{ $labels.instance }} has been offline for more than 2 minutes."
- alert: MinIOHighAPIErrors
expr: rate(minio_s3_requests_errors_total[5m]) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "High MinIO API error rate"
description: "MinIO is experiencing high API error rate: {{ $value }} errors/second."
- alert: MinIOHighRequestLatency
expr: histogram_quantile(0.99, rate(minio_s3_requests_ttfb_seconds_bucket[5m])) > 10
for: 10m
labels:
severity: warning
annotations:
summary: "MinIO high request latency"
description: "MinIO 99th percentile request latency is {{ $value }} seconds."
Set file ownership and create systemd service
Set proper permissions and create a systemd service file to manage Prometheus.
sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml
sudo chown prometheus:prometheus /etc/prometheus/minio_alerts.yml
[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 \
--storage.tsdb.retention.time=30d
[Install]
WantedBy=multi-user.target
Start Prometheus service
Enable and start the Prometheus service, then verify it's collecting MinIO metrics.
sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus
sudo systemctl status prometheus
Install Grafana
Install Grafana to visualize MinIO metrics collected by Prometheus.
sudo apt-get install -y software-properties-common
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 -a /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install grafana
Configure Grafana data source
Start Grafana and add Prometheus as a data source. We'll configure it via the API for automation.
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
sudo systemctl status grafana-server
Add Prometheus data source via API:
curl -X POST \
http://admin:admin@localhost:3000/api/datasources \
-H 'Content-Type: application/json' \
-d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://localhost:9090",
"access": "proxy",
"isDefault": true
}'
Import MinIO Grafana dashboard
Create a comprehensive MinIO dashboard that displays key metrics for monitoring storage performance and health.
{
"dashboard": {
"id": null,
"title": "MinIO Metrics",
"tags": ["minio", "storage"],
"timezone": "browser",
"panels": [
{
"title": "Cluster Storage Usage",
"type": "stat",
"targets": [
{
"expr": "minio_cluster_capacity_usable_total_bytes",
"legendFormat": "Total Capacity"
},
{
"expr": "minio_cluster_capacity_usable_free_bytes",
"legendFormat": "Free Space"
}
],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0}
},
{
"title": "API Request Rate",
"type": "graph",
"targets": [
{
"expr": "rate(minio_s3_requests_total[5m])",
"legendFormat": "{{ method }} requests/sec"
}
],
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0}
},
{
"title": "Request Errors",
"type": "graph",
"targets": [
{
"expr": "rate(minio_s3_requests_errors_total[5m])",
"legendFormat": "{{ method }} errors/sec"
}
],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 8}
},
{
"title": "Request Duration",
"type": "graph",
"targets": [
{
"expr": "histogram_quantile(0.99, rate(minio_s3_requests_ttfb_seconds_bucket[5m]))",
"legendFormat": "99th percentile"
},
{
"expr": "histogram_quantile(0.95, rate(minio_s3_requests_ttfb_seconds_bucket[5m]))",
"legendFormat": "95th percentile"
}
],
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 8}
}
],
"time": {
"from": "now-1h",
"to": "now"
},
"refresh": "30s"
}
}
Import the dashboard:
curl -X POST \
http://admin:admin@localhost:3000/api/dashboards/db \
-H 'Content-Type: application/json' \
-d @/tmp/minio-dashboard.json
Configure alerting in Grafana
Set up Grafana alerting to receive notifications for critical MinIO issues via email or Slack.
[smtp]
enabled = true
host = localhost:587
user =
password =
from_address = alerts@example.com
from_name = Grafana
[alerting]
enabled = true
execute_alerts = true
Restart Grafana to apply email configuration:
sudo systemctl restart grafana-server
Configure firewall rules
Open the required ports for Prometheus and Grafana access.
sudo ufw allow 9090/tcp comment 'Prometheus'
sudo ufw allow 3000/tcp comment 'Grafana'
sudo ufw reload
Verify your setup
Check that all services are running and collecting metrics properly:
# Check Prometheus status and targets
sudo systemctl status prometheus
curl http://localhost:9090/api/v1/targets
Check Grafana status
sudo systemctl status grafana-server
Verify MinIO metrics are being scraped
curl http://localhost:9090/api/v1/query?query=minio_cluster_capacity_usable_total_bytes
Test MinIO metrics endpoint directly
curl http://localhost:9000/minio/v2/metrics/cluster
Access Grafana at http://your-server-ip:3000 using admin/admin credentials. You should see the MinIO dashboard with live metrics data.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Prometheus can't scrape MinIO metrics | MinIO metrics endpoint not enabled | Add MINIO_PROMETHEUS_AUTH_TYPE=public to MinIO config and restart |
| "No data" in Grafana dashboard | Prometheus data source not configured | Verify Prometheus URL is http://localhost:9090 in Grafana data sources |
| Grafana shows connection refused | Services not started or firewall blocking | Check systemctl status grafana-server and firewall rules |
| Alerts not firing | Alert rules syntax error or thresholds not met | Validate rules with promtool check rules /etc/prometheus/minio_alerts.yml |
| Missing bucket-level metrics | Bucket metrics endpoint not scraped | Verify /minio/v2/metrics/bucket target is active in Prometheus |
Next steps
- Implement MinIO security hardening with IAM policies to secure your monitored storage
- Configure MinIO backup and disaster recovery for data protection
- Configure Prometheus Alertmanager with Slack integration for team notifications
- Setup MinIO multi-tenant monitoring with Prometheus for complex deployments
- Integrate MinIO monitoring with ELK stack for log correlation
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[0;33m'
readonly NC='\033[0m' # No Color
# Configuration
readonly PROMETHEUS_VERSION="2.45.0"
readonly PROMETHEUS_USER="prometheus"
readonly PROMETHEUS_HOME="/var/lib/prometheus"
readonly PROMETHEUS_CONFIG="/etc/prometheus"
# Usage
usage() {
echo "Usage: $0 [MINIO_HOST] [MINIO_PORT]"
echo " MINIO_HOST: MinIO server host (default: localhost)"
echo " MINIO_PORT: MinIO server port (default: 9000)"
exit 1
}
# Parse arguments
MINIO_HOST="${1:-localhost}"
MINIO_PORT="${2:-9000}"
# Validate port is numeric
if ! [[ "$MINIO_PORT" =~ ^[0-9]+$ ]]; then
echo -e "${RED}Error: Port must be numeric${NC}"
usage
fi
# Error handling
cleanup() {
echo -e "${RED}Installation failed. Rolling back changes...${NC}"
systemctl stop prometheus 2>/dev/null || true
systemctl disable prometheus 2>/dev/null || true
rm -f /etc/systemd/system/prometheus.service
rm -rf /usr/local/bin/prometheus /usr/local/bin/promtool
rm -rf "$PROMETHEUS_CONFIG" "$PROMETHEUS_HOME"
userdel "$PROMETHEUS_USER" 2>/dev/null || true
systemctl daemon-reload
}
trap cleanup ERR
# Color output functions
info() { echo -e "${GREEN}$1${NC}"; }
warn() { echo -e "${YELLOW}$1${NC}"; }
error() { echo -e "${RED}$1${NC}"; }
# Check if running as root
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
exit 1
fi
# Detect OS and package manager
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"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y --refresh"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
;;
*)
error "Unsupported distribution: $ID"
exit 1
;;
esac
else
error "Cannot detect OS distribution"
exit 1
fi
info "[1/8] Updating package repositories..."
$PKG_UPDATE
info "[2/8] Installing required packages..."
$PKG_INSTALL wget tar
info "[3/8] Creating prometheus user..."
if ! id "$PROMETHEUS_USER" &>/dev/null; then
useradd --no-create-home --shell /bin/false "$PROMETHEUS_USER"
fi
info "[4/8] Downloading and installing Prometheus..."
cd /tmp
wget -O prometheus.tar.gz "https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
tar xzf prometheus.tar.gz
cp "prometheus-${PROMETHEUS_VERSION}.linux-amd64/prometheus" /usr/local/bin/
cp "prometheus-${PROMETHEUS_VERSION}.linux-amd64/promtool" /usr/local/bin/
chown "$PROMETHEUS_USER:$PROMETHEUS_USER" /usr/local/bin/prometheus
chown "$PROMETHEUS_USER:$PROMETHEUS_USER" /usr/local/bin/promtool
chmod 755 /usr/local/bin/prometheus /usr/local/bin/promtool
rm -rf "prometheus-${PROMETHEUS_VERSION}.linux-amd64" prometheus.tar.gz
info "[5/8] Creating Prometheus directories..."
mkdir -p "$PROMETHEUS_CONFIG" "$PROMETHEUS_HOME"
chown "$PROMETHEUS_USER:$PROMETHEUS_USER" "$PROMETHEUS_CONFIG" "$PROMETHEUS_HOME"
chmod 755 "$PROMETHEUS_CONFIG" "$PROMETHEUS_HOME"
info "[6/8] Creating Prometheus configuration..."
cat > "$PROMETHEUS_CONFIG/prometheus.yml" << EOF
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "minio_alerts.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'minio-cluster'
metrics_path: /minio/v2/metrics/cluster
static_configs:
- targets: ['${MINIO_HOST}:${MINIO_PORT}']
scrape_interval: 30s
scrape_timeout: 10s
- job_name: 'minio-node'
metrics_path: /minio/v2/metrics/node
static_configs:
- targets: ['${MINIO_HOST}:${MINIO_PORT}']
scrape_interval: 30s
scrape_timeout: 10s
- job_name: 'minio-bucket'
metrics_path: /minio/v2/metrics/bucket
static_configs:
- targets: ['${MINIO_HOST}:${MINIO_PORT}']
scrape_interval: 60s
scrape_timeout: 15s
EOF
cat > "$PROMETHEUS_CONFIG/minio_alerts.yml" << 'EOF'
groups:
- name: minio
rules:
- alert: MinIODiskUsageHigh
expr: (minio_cluster_capacity_usable_free_bytes / minio_cluster_capacity_usable_total_bytes) * 100 < 10
for: 5m
labels:
severity: critical
annotations:
summary: "MinIO cluster disk usage is critically high"
description: "MinIO cluster has less than 10% free disk space remaining."
- alert: MinIONodeOffline
expr: up{job="minio-node"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "MinIO node is offline"
description: "MinIO node {{ $labels.instance }} has been offline for more than 2 minutes."
- alert: MinIOAPIRequestsHigh
expr: rate(minio_s3_requests_total[5m]) > 1000
for: 5m
labels:
severity: warning
annotations:
summary: "High MinIO API request rate"
description: "MinIO is receiving {{ $value }} requests per second."
EOF
chown -R "$PROMETHEUS_USER:$PROMETHEUS_USER" "$PROMETHEUS_CONFIG"
find "$PROMETHEUS_CONFIG" -type f -exec chmod 644 {} \;
info "[7/8] Creating systemd service..."
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:9090 \\
--web.enable-lifecycle
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable prometheus
systemctl start prometheus
info "[8/8] Configuring firewall..."
case "$ID" in
ubuntu|debian)
if command -v ufw &> /dev/null; then
ufw allow 9090/tcp
fi
;;
almalinux|rocky|centos|rhel|ol|fedora|amzn)
if command -v firewall-cmd &> /dev/null; then
firewall-cmd --permanent --add-port=9090/tcp
firewall-cmd --reload
fi
;;
esac
# Verification
info "Verifying installation..."
sleep 5
if systemctl is-active --quiet prometheus; then
info "✓ Prometheus service is running"
else
error "✗ Prometheus service failed to start"
exit 1
fi
if /usr/local/bin/promtool check config "$PROMETHEUS_CONFIG/prometheus.yml" &>/dev/null; then
info "✓ Prometheus configuration is valid"
else
error "✗ Prometheus configuration is invalid"
exit 1
fi
# Display information
info ""
info "Installation completed successfully!"
info "Prometheus is accessible at: http://localhost:9090"
info "MinIO metrics will be scraped from: ${MINIO_HOST}:${MINIO_PORT}"
warn ""
warn "Next steps:"
warn "1. Ensure MinIO is configured with:"
warn " MINIO_PROMETHEUS_AUTH_TYPE=public"
warn " MINIO_PROMETHEUS_URL=http://${MINIO_HOST}:${MINIO_PORT}/minio/v2/metrics/cluster"
warn " MINIO_PROMETHEUS_JOB_ID=minio-job"
warn "2. Install Grafana and import MinIO dashboards"
warn "3. Configure alerting channels in your monitoring setup"
Review the script before running. Execute with: bash install.sh