Self-Hosting Alertmanager with Docker Compose
What Is Alertmanager?
Alertmanager handles alerts sent by Prometheus. It groups related alerts, deduplicates them, routes them to the right receiver (email, Slack, PagerDuty, webhook), and manages silences and inhibitions. Without it, Prometheus fires raw alerts with no intelligence — Alertmanager adds the routing and notification logic. Official docs.
Updated March 2026: Verified with latest Docker images and configurations.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 512 MB of free RAM
- 1 GB of free disk space
- A running Prometheus instance (Prometheus setup or Grafana + Prometheus stack)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
alertmanager:
image: prom/alertmanager:v0.31.1
container_name: alertmanager
restart: unless-stopped
ports:
- "9093:9093"
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- alertmanager-data:/alertmanager
command:
- '--config.file=/etc/alertmanager/alertmanager.yml'
- '--storage.path=/alertmanager'
- '--web.external-url=http://alertmanager.example.com'
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9093/-/healthy"]
interval: 30s
timeout: 5s
retries: 3
volumes:
alertmanager-data:
Create alertmanager.yml alongside the Compose file:
# Alertmanager configuration
global:
resolve_timeout: 5m
# SMTP settings for email notifications
smtp_smarthost: 'smtp.example.com:587'
smtp_from: '[email protected]'
smtp_auth_username: '[email protected]'
smtp_auth_password: 'your-smtp-password' # Change this
smtp_require_tls: true
# Alert routing tree
route:
# Default receiver
receiver: 'email-notifications'
# Group alerts by alertname and job
group_by: ['alertname', 'job']
# Wait 30s to collect related alerts before sending
group_wait: 30s
# Wait 5m between notifications for the same group
group_interval: 5m
# Wait 4h before resending an unresolved alert
repeat_interval: 4h
# Route critical alerts to a separate receiver
routes:
- receiver: 'critical-webhook'
match:
severity: critical
group_wait: 10s
repeat_interval: 1h
# Notification receivers
receivers:
- name: 'email-notifications'
email_configs:
- to: '[email protected]'
send_resolved: true
- name: 'critical-webhook'
webhook_configs:
- url: 'http://ntfy:8080/alerts' # Forward to ntfy, Gotify, etc.
send_resolved: true
# Inhibition rules — suppress less severe alerts when critical fires
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'instance']
Start the stack:
docker compose up -d
Initial Setup
- Open
http://your-server-ip:9093in your browser - You’ll see the Alertmanager UI with the Alerts, Silences, and Status tabs
- Check the Status page to verify your configuration loaded correctly
Connect Prometheus to Alertmanager
In your Prometheus prometheus.yml, add:
alerting:
alertmanagers:
- static_configs:
- targets:
- 'alertmanager:9093'
rule_files:
- '/etc/prometheus/alert_rules.yml'
Create a sample alert rule in alert_rules.yml:
groups:
- name: instance_alerts
rules:
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Instance {{ $labels.instance }} is down"
description: "{{ $labels.instance }} has been unreachable for 2 minutes."
- alert: HighMemoryUsage
expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "High memory usage on {{ $labels.instance }}"
description: "Memory usage is above 90% for 5 minutes."
Configuration
Receiver Types
| Receiver | Use Case | Config Key |
|---|---|---|
| Standard notifications | email_configs | |
| Slack | Team chat alerts | slack_configs |
| Webhook | Custom integrations (ntfy, Gotify, n8n) | webhook_configs |
| PagerDuty | On-call escalation | pagerduty_configs |
| OpsGenie | On-call management | opsgenie_configs |
| Microsoft Teams | Team chat alerts | msteams_configs |
| Telegram | Mobile alerts via bot | telegram_configs |
Slack Integration
receivers:
- name: 'slack-notifications'
slack_configs:
- api_url: 'https://hooks.slack.com/services/T00/B00/XXXX'
channel: '#alerts'
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
send_resolved: true
Using amtool CLI
Alertmanager includes amtool for managing alerts from the command line:
# Check current alerts
docker exec alertmanager amtool alert query
# Create a silence for maintenance
docker exec alertmanager amtool silence add alertname="InstanceDown" \
--comment="Scheduled maintenance" \
--duration=2h
# List active silences
docker exec alertmanager amtool silence query
# Verify routing configuration
docker exec alertmanager amtool config routes show
Reverse Proxy
Place behind Nginx Proxy Manager or Caddy for HTTPS access. Set the --web.external-url flag to match your public URL. See Reverse Proxy Setup.
Backup
Back up the Alertmanager data volume (contains silences and notification state):
docker compose stop alertmanager
tar czf alertmanager-backup.tar.gz -C /var/lib/docker/volumes/ alertmanager-data
docker compose start alertmanager
Also back up alertmanager.yml — this is your routing configuration. See Backup Strategy.
Troubleshooting
Alerts Not Sending Emails
Symptom: Alerts fire in Prometheus but no email arrives.
Fix: Check the Alertmanager Status page for errors. Verify SMTP credentials. Test with amtool check-config alertmanager.yml. Common issue: smtp_require_tls: true with a port that doesn’t support STARTTLS.
Duplicate Notifications
Symptom: Same alert sent multiple times within repeat_interval.
Fix: Check group_by labels — alerts with different label sets create separate groups. Add more labels to group_by or use group_by: ['...'] to group all alerts together.
Alerts Stuck in “Pending” State
Symptom: Alert appears in Prometheus as pending but never fires.
Fix: The for duration hasn’t elapsed. Check the alert rule’s for value. Prometheus evaluates rules at the evaluation_interval (default 15s), so for: 5m means the condition must be true for ~20 evaluation cycles.
Config Reload Not Working
Symptom: Changes to alertmanager.yml don’t take effect.
Fix: Send SIGHUP to reload: docker kill -s SIGHUP alertmanager. Or POST to http://localhost:9093/-/reload.
Resource Requirements
- RAM: ~30 MB idle, ~100 MB with thousands of active alerts
- CPU: Very low — alert processing is lightweight
- Disk: ~50 MB for application, minimal for silence/notification state
Verdict
Alertmanager is essential if you run Prometheus — it’s the missing half of the alerting pipeline. Without it, you get raw alerts with no grouping, deduplication, or routing. The learning curve is steeper than simpler tools like ntfy or Gotify, but if you’re already in the Prometheus ecosystem, there’s no better option. For standalone push notifications without Prometheus, use ntfy instead.
Frequently Asked Questions
Do I need Prometheus to use Alertmanager?
Technically no — any system that can send alerts to Alertmanager’s HTTP API can use it. But in practice, Alertmanager is designed as part of the Prometheus ecosystem. Without Prometheus generating alerts from metrics, you’d need to write custom integrations to push alerts. For standalone alerting without Prometheus, ntfy or Gotify are simpler options.
What’s the difference between Alertmanager and Grafana alerting?
Grafana has built-in alerting that can evaluate dashboard queries and send notifications. Alertmanager handles alerts generated by Prometheus alerting rules. The key difference: Grafana alerts are tied to dashboard panels and run on a schedule, while Prometheus alerts evaluate continuously against real-time metrics. For a Prometheus stack, Alertmanager gives you grouping, silencing, and routing that Grafana’s alerting doesn’t replicate as well.
How does alert grouping work?
Alertmanager groups alerts by matching labels. For example, if group_by: ['alertname', 'cluster'] is set in a route, all alerts with the same alertname and cluster label values are bundled into a single notification. This prevents notification storms — instead of 50 separate “disk full” emails for 50 servers, you get one grouped notification listing all affected servers.
Can Alertmanager send notifications to Slack, Teams, or PagerDuty?
Yes. Alertmanager has native receiver integrations for Slack, PagerDuty, OpsGenie, VictorOps, Microsoft Teams (via webhook), email (SMTP), and generic webhooks. Configure receivers in alertmanager.yml under the receivers section. Each route can point to a different receiver, so critical alerts go to PagerDuty while warnings go to Slack.
What happens if Alertmanager goes down?
Prometheus buffers alerts locally and retries sending them to Alertmanager. Short outages (minutes) won’t cause missed alerts — Prometheus will deliver them once Alertmanager is back. For high availability, run two or more Alertmanager instances in a cluster using the --cluster.peer flag. They gossip alert state between themselves, ensuring deduplication even with multiple instances.
How do I silence alerts during maintenance?
Use the Alertmanager web UI at http://your-server:9093/#/silences. Click “New Silence,” set label matchers to target specific alerts (e.g., alertname="DiskFull" and instance="server-5"), set a duration, and add a comment. You can also create silences via the API for automation. Silences automatically expire after the set duration.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments