Configure Prometheus Blackbox Exporter to monitor website availability, SSL certificate expiry, and HTTP response times with comprehensive Grafana dashboards and alert rules.
Prerequisites
- Prometheus server already installed
- Grafana instance for dashboards
- Root or sudo access
What this solves
Prometheus Blackbox Exporter monitors your websites and services from the outside, checking HTTP/HTTPS endpoints, SSL certificates, DNS responses, and TCP connectivity. This tutorial shows you how to set up comprehensive uptime monitoring with SSL certificate tracking and automated alerting through Grafana.
Step-by-step installation
Update system packages
Start by updating your package manager and installing dependencies.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget tarDownload and install Blackbox Exporter
Download the latest Blackbox Exporter release and install it to the system.
cd /tmp
wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.24.0/blackbox_exporter-0.24.0.linux-amd64.tar.gz
tar -xzf blackbox_exporter-0.24.0.linux-amd64.tar.gz
sudo mv blackbox_exporter-0.24.0.linux-amd64/blackbox_exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/blackbox_exporterCreate system user and directories
Create a dedicated user and the necessary directories for Blackbox Exporter.
sudo useradd --system --no-create-home --shell /bin/false blackbox_exporter
sudo mkdir -p /etc/blackbox_exporter
sudo chown blackbox_exporter:blackbox_exporter /etc/blackbox_exporterConfigure Blackbox Exporter
Create the main configuration file with HTTP, HTTPS, and SSL certificate monitoring modules.
modules:
http_2xx:
prober: http
timeout: 5s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200, 201, 202, 204]
method: GET
follow_redirects: true
fail_if_ssl: false
fail_if_not_ssl: false
preferred_ip_protocol: "ip4"
http_post_2xx:
prober: http
timeout: 5s
http:
method: POST
headers:
Content-Type: application/json
body: '{}'
valid_status_codes: [200, 201, 202]
https_2xx:
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200, 201, 202, 204]
method: GET
follow_redirects: true
fail_if_ssl: false
fail_if_not_ssl: true
preferred_ip_protocol: "ip4"
tls_config:
insecure_skip_verify: false
ssl_expiry:
prober: http
timeout: 10s
http:
method: GET
fail_if_not_ssl: true
preferred_ip_protocol: "ip4"
tls_config:
insecure_skip_verify: false
tcp_connect:
prober: tcp
timeout: 5s
tcp:
preferred_ip_protocol: "ip4"
dns_query:
prober: dns
timeout: 5s
dns:
query_name: "example.com"
query_type: "A"
valid_rcodes:
- NOERROR
preferred_ip_protocol: "ip4"
icmp_ping:
prober: icmp
timeout: 5s
icmp:
preferred_ip_protocol: "ip4"Set configuration permissions
Set the correct ownership and permissions for the configuration file.
sudo chown blackbox_exporter:blackbox_exporter /etc/blackbox_exporter/blackbox.yml
sudo chmod 640 /etc/blackbox_exporter/blackbox.ymlCreate systemd service
Create a systemd service file to manage the Blackbox Exporter daemon.
[Unit]
Description=Blackbox Exporter
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=blackbox_exporter
Group=blackbox_exporter
ExecStart=/usr/local/bin/blackbox_exporter \
--config.file=/etc/blackbox_exporter/blackbox.yml \
--web.listen-address=:9115
SyslogIdentifier=blackbox_exporter
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetEnable and start Blackbox Exporter
Enable the service to start on boot and start it immediately.
sudo systemctl daemon-reload
sudo systemctl enable --now blackbox_exporter
sudo systemctl status blackbox_exporterConfigure firewall access
Allow access to the Blackbox Exporter port from your Prometheus server.
sudo ufw allow from 203.0.113.10 to any port 9115 comment 'Prometheus Blackbox Exporter'
sudo ufw reloadConfigure Prometheus targets
Add Blackbox Exporter job to Prometheus
Configure Prometheus to scrape metrics from Blackbox Exporter and define your monitoring targets.
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "blackbox_alerts.yml"
scrape_configs:
- job_name: 'blackbox_exporter'
static_configs:
- targets: ['localhost:9115']
- job_name: 'blackbox_http'
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- http://example.com
- http://api.example.com/health
- http://status.example.com
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
- job_name: 'blackbox_https'
metrics_path: /probe
params:
module: [https_2xx]
static_configs:
- targets:
- https://example.com
- https://api.example.com
- https://dashboard.example.com
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
- job_name: 'blackbox_ssl'
metrics_path: /probe
params:
module: [ssl_expiry]
static_configs:
- targets:
- https://example.com
- https://api.example.com
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
- job_name: 'blackbox_tcp'
metrics_path: /probe
params:
module: [tcp_connect]
static_configs:
- targets:
- example.com:443
- database.example.com:5432
- redis.example.com:6379
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115Create alerting rules
Define alert rules for website downtime, SSL certificate expiry, and slow response times.
groups:
- name: blackbox_alerts
rules:
- alert: WebsiteDown
expr: probe_success == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Website {{ $labels.instance }} is down"
description: "Website {{ $labels.instance }} has been down for more than 5 minutes."
- alert: SSLCertExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 30
for: 1h
labels:
severity: warning
annotations:
summary: "SSL certificate for {{ $labels.instance }} expires soon"
description: "SSL certificate for {{ $labels.instance }} will expire in {{ $value | humanizeDuration }}."
- alert: SSLCertExpiring
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 7
for: 1h
labels:
severity: critical
annotations:
summary: "SSL certificate for {{ $labels.instance }} expires very soon"
description: "SSL certificate for {{ $labels.instance }} will expire in {{ $value | humanizeDuration }}."
- alert: HighResponseTime
expr: probe_duration_seconds > 5
for: 5m
labels:
severity: warning
annotations:
summary: "High response time for {{ $labels.instance }}"
description: "{{ $labels.instance }} response time is {{ $value }}s which is above the 5s threshold."
- alert: HTTPStatusError
expr: probe_http_status_code >= 400
for: 2m
labels:
severity: critical
annotations:
summary: "HTTP error for {{ $labels.instance }}"
description: "{{ $labels.instance }} returned HTTP status {{ $value }}."
- alert: TCPConnectionFailed
expr: probe_success{job="blackbox_tcp"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "TCP connection failed for {{ $labels.instance }}"
description: "TCP connection to {{ $labels.instance }} has been failing for more than 2 minutes."Restart Prometheus
Reload Prometheus configuration to apply the new scrape jobs and alert rules.
sudo systemctl restart prometheus
sudo systemctl status prometheusSet up Grafana dashboards
Import Blackbox Exporter dashboard
Access your Grafana instance and import a comprehensive dashboard for Blackbox monitoring.
{
"dashboard": {
"id": null,
"title": "Blackbox Exporter Overview",
"tags": ["blackbox", "monitoring"],
"timezone": "browser",
"panels": [
{
"title": "Website Status",
"type": "stat",
"targets": [
{
"expr": "probe_success",
"legendFormat": "{{ instance }}"
}
],
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"0": { "text": "DOWN", "color": "red" },
"1": { "text": "UP", "color": "green" }
},
"type": "value"
}
],
"thresholds": {
"steps": [
{ "color": "red", "value": 0 },
{ "color": "green", "value": 1 }
]
}
}
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 }
},
{
"title": "SSL Certificate Expiry (Days)",
"type": "stat",
"targets": [
{
"expr": "(probe_ssl_earliest_cert_expiry - time()) / 86400",
"legendFormat": "{{ instance }}"
}
],
"fieldConfig": {
"defaults": {
"unit": "d",
"thresholds": {
"steps": [
{ "color": "red", "value": 0 },
{ "color": "yellow", "value": 7 },
{ "color": "green", "value": 30 }
]
}
}
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 }
},
{
"title": "Response Time",
"type": "timeseries",
"targets": [
{
"expr": "probe_duration_seconds",
"legendFormat": "{{ instance }}"
}
],
"fieldConfig": {
"defaults": {
"unit": "s"
}
},
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 8 }
}
],
"time": {
"from": "now-1h",
"to": "now"
},
"refresh": "30s"
}
}Configure Grafana alerting
Set up alert rules in Grafana that complement your Prometheus alerts. In this tutorial, we'll focus on setting up Prometheus Alertmanager with email notifications for centralized alert management.
curl -X POST http://admin:admin@localhost:3000/api/dashboards/db \
-H "Content-Type: application/json" \
-d @dashboard.jsonConfigure SSL and advanced monitoring
Add custom SSL monitoring
Create additional modules for specific SSL requirements and certificate chain validation.
modules:
ssl_detailed:
prober: http
timeout: 10s
http:
method: GET
fail_if_not_ssl: true
preferred_ip_protocol: "ip4"
tls_config:
insecure_skip_verify: false
ca_file: "/etc/ssl/certs/ca-certificates.crt"
ssl_client_auth:
prober: http
timeout: 10s
http:
method: GET
fail_if_not_ssl: true
tls_config:
cert_file: "/etc/blackbox_exporter/client.crt"
key_file: "/etc/blackbox_exporter/client.key"
ca_file: "/etc/ssl/certs/ca-certificates.crt"
http_basic_auth:
prober: http
timeout: 5s
http:
valid_status_codes: [200, 201, 202]
method: GET
basic_auth:
username: "monitor"
password: "secure_password"
http_custom_headers:
prober: http
timeout: 5s
http:
valid_status_codes: [200]
method: GET
headers:
Authorization: "Bearer your_token_here"
User-Agent: "Blackbox-Monitor/1.0"
X-API-Key: "your_api_key_here"Restart Blackbox Exporter
Apply the new configuration by restarting the service.
sudo systemctl restart blackbox_exporter
sudo systemctl status blackbox_exporterSet up multi-location monitoring
For comprehensive uptime monitoring, you can deploy Blackbox Exporter on multiple servers. This approach provides redundancy and helps distinguish between local network issues and actual service problems.
scrape_configs:
- job_name: 'blackbox_primary'
metrics_path: /probe
params:
module: [https_2xx]
static_configs:
- targets:
- https://example.com
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: primary-monitor.example.com:9115
- target_label: location
replacement: primary
- job_name: 'blackbox_secondary'
metrics_path: /probe
params:
module: [https_2xx]
static_configs:
- targets:
- https://example.com
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: secondary-monitor.example.com:9115
- target_label: location
replacement: secondaryVerify your setup
sudo systemctl status blackbox_exporter
curl -s http://localhost:9115/metrics | grep probe_success
curl -s "http://localhost:9115/probe?target=https://example.com&module=https_2xx" | grep probe_success
curl -s "http://localhost:9115/probe?target=https://example.com&module=ssl_expiry" | grep probe_ssl_earliest_cert_expiryCheck that Prometheus is collecting the metrics:
curl -s http://localhost:9090/api/v1/query?query=probe_success | jq '.data.result[] | {instance: .metric.instance, status: .value[1]}'
prometheus --config.file=/etc/prometheus/prometheus.yml --web.config.file=/etc/prometheus/web.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.external-url= --config.checkCommon issues
| Symptom | Cause | Fix |
|---|---|---|
| Blackbox Exporter won't start | Configuration syntax error | sudo /usr/local/bin/blackbox_exporter --config.check --config.file=/etc/blackbox_exporter/blackbox.yml |
| No metrics in Prometheus | Incorrect relabel configuration | Check relabel_configs and ensure __address__ points to blackbox_exporter:9115 |
| SSL probe fails | Certificate validation issues | Use insecure_skip_verify: true for self-signed certs or add CA bundle |
| Permission denied on config file | Incorrect file ownership | sudo chown blackbox_exporter:blackbox_exporter /etc/blackbox_exporter/blackbox.yml |
| Probe timeout errors | Network connectivity or slow responses | Increase timeout values in module configuration |
| HTTP authentication fails | Wrong credentials in basic_auth | Verify username/password and use environment variables for secrets |
Next steps
- Configure Prometheus Alertmanager with email notifications for centralized alert management
- Setup Grafana alerting with Slack and Microsoft Teams integration for team notifications
- Set up NGINX monitoring with Prometheus and Grafana to complement your infrastructure monitoring
- Configure custom probe modules for API endpoints and database connectivity
- Set up Prometheus federation for multi-site monitoring architecture
Running this in production?
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
# Configuration
BLACKBOX_VERSION="0.24.0"
BLACKBOX_USER="blackbox_exporter"
BLACKBOX_PORT="9115"
PROMETHEUS_IP="${1:-}"
# Function to print colored output
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Usage message
usage() {
echo "Usage: $0 [PROMETHEUS_IP]"
echo " PROMETHEUS_IP: IP address of Prometheus server for firewall rules (optional)"
exit 1
}
# Cleanup function
cleanup() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
print_error "Installation failed. Performing cleanup..."
sudo systemctl stop blackbox_exporter 2>/dev/null || true
sudo systemctl disable blackbox_exporter 2>/dev/null || true
sudo rm -f /etc/systemd/system/blackbox_exporter.service
sudo rm -rf /etc/blackbox_exporter
sudo rm -f /usr/local/bin/blackbox_exporter
sudo userdel blackbox_exporter 2>/dev/null || true
sudo systemctl daemon-reload
fi
exit $exit_code
}
trap cleanup ERR
# Check if running as root or with sudo
check_privileges() {
if [[ $EUID -ne 0 ]] && ! sudo -n true 2>/dev/null; then
print_error "This script requires root privileges or sudo access"
exit 1
fi
}
# Detect distribution and package manager
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
FIREWALL_CMD="ufw"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
FIREWALL_CMD="firewall-cmd"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
FIREWALL_CMD="firewall-cmd"
;;
*)
print_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
print_error "Cannot detect distribution. /etc/os-release not found."
exit 1
fi
}
# Main installation function
main() {
print_status "Starting Prometheus Blackbox Exporter installation"
check_privileges
detect_distro
echo "[1/8] Updating system packages..."
sudo bash -c "$PKG_UPDATE"
sudo $PKG_INSTALL curl wget tar
echo "[2/8] Downloading Blackbox Exporter..."
cd /tmp
wget "https://github.com/prometheus/blackbox_exporter/releases/download/v${BLACKBOX_VERSION}/blackbox_exporter-${BLACKBOX_VERSION}.linux-amd64.tar.gz"
tar -xzf "blackbox_exporter-${BLACKBOX_VERSION}.linux-amd64.tar.gz"
echo "[3/8] Installing Blackbox Exporter binary..."
sudo mv "blackbox_exporter-${BLACKBOX_VERSION}.linux-amd64/blackbox_exporter" /usr/local/bin/
sudo chmod 755 /usr/local/bin/blackbox_exporter
echo "[4/8] Creating system user and directories..."
sudo useradd --system --no-create-home --shell /bin/false $BLACKBOX_USER 2>/dev/null || true
sudo mkdir -p /etc/blackbox_exporter
sudo chown $BLACKBOX_USER:$BLACKBOX_USER /etc/blackbox_exporter
echo "[5/8] Creating configuration file..."
sudo tee /etc/blackbox_exporter/blackbox.yml > /dev/null <<EOF
modules:
http_2xx:
prober: http
timeout: 5s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200, 201, 202, 204]
method: GET
follow_redirects: true
fail_if_ssl: false
fail_if_not_ssl: false
preferred_ip_protocol: "ip4"
https_2xx:
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200, 201, 202, 204]
method: GET
follow_redirects: true
fail_if_ssl: false
fail_if_not_ssl: true
preferred_ip_protocol: "ip4"
tls_config:
insecure_skip_verify: false
ssl_expiry:
prober: http
timeout: 10s
http:
method: GET
fail_if_not_ssl: true
preferred_ip_protocol: "ip4"
tls_config:
insecure_skip_verify: false
tcp_connect:
prober: tcp
timeout: 5s
tcp:
preferred_ip_protocol: "ip4"
icmp_ping:
prober: icmp
timeout: 5s
icmp:
preferred_ip_protocol: "ip4"
EOF
sudo chown $BLACKBOX_USER:$BLACKBOX_USER /etc/blackbox_exporter/blackbox.yml
sudo chmod 640 /etc/blackbox_exporter/blackbox.yml
echo "[6/8] Creating systemd service..."
sudo tee /etc/systemd/system/blackbox_exporter.service > /dev/null <<EOF
[Unit]
Description=Blackbox Exporter
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=$BLACKBOX_USER
Group=$BLACKBOX_USER
ExecStart=/usr/local/bin/blackbox_exporter \\
--config.file=/etc/blackbox_exporter/blackbox.yml \\
--web.listen-address=:$BLACKBOX_PORT
SyslogIdentifier=blackbox_exporter
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
echo "[7/8] Starting and enabling Blackbox Exporter..."
sudo systemctl daemon-reload
sudo systemctl enable blackbox_exporter
sudo systemctl start blackbox_exporter
echo "[8/8] Configuring firewall..."
if [ -n "$PROMETHEUS_IP" ]; then
case "$PKG_MGR" in
apt)
if command -v ufw >/dev/null 2>&1; then
sudo ufw allow from "$PROMETHEUS_IP" to any port $BLACKBOX_PORT
fi
;;
dnf|yum)
if command -v firewall-cmd >/dev/null 2>&1 && sudo firewall-cmd --state >/dev/null 2>&1; then
sudo firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='$PROMETHEUS_IP' port protocol='tcp' port='$BLACKBOX_PORT' accept"
sudo firewall-cmd --reload
fi
;;
esac
print_status "Firewall configured for Prometheus IP: $PROMETHEUS_IP"
else
print_warning "No Prometheus IP provided. Configure firewall manually if needed."
fi
# Verification
print_status "Verifying installation..."
if sudo systemctl is-active --quiet blackbox_exporter; then
print_status "✓ Blackbox Exporter service is running"
else
print_error "✗ Blackbox Exporter service is not running"
exit 1
fi
if curl -s "http://localhost:$BLACKBOX_PORT/metrics" >/dev/null; then
print_status "✓ Blackbox Exporter metrics endpoint is accessible"
else
print_error "✗ Blackbox Exporter metrics endpoint is not accessible"
exit 1
fi
print_status "Blackbox Exporter installation completed successfully!"
echo ""
echo "Service status: $(sudo systemctl is-active blackbox_exporter)"
echo "Metrics endpoint: http://$(hostname -I | awk '{print $1}'):$BLACKBOX_PORT/metrics"
echo "Config file: /etc/blackbox_exporter/blackbox.yml"
echo ""
echo "Test with: curl http://localhost:$BLACKBOX_PORT/probe?target=https://example.com&module=https_2xx"
}
main "$@"
Review the script before running. Execute with: bash install.sh