awesome-prometheus-alerts/site/src/pages/index.astro
Samuel Berthe ab87fdcf30
feat/dual license (#550)
* ci: remove node version pin in site build workflow

* docs: clarify dual license (CC BY 4.0 for content, MIT for site code)

Alert rules and content (_data/rules.yml, dist/) are licensed under
Creative Commons CC BY 4.0. The site source code (site/) is licensed
under MIT. Both are now documented in LICENSE, site/LICENSE, the footer,
and the FAQ.
2026-04-10 21:36:57 +02:00

345 lines
18 KiB
Text

---
import BaseLayout from '../layouts/BaseLayout.astro';
import StatsBar from '../components/StatsBar.astro';
import ServiceCard from '../components/ServiceCard.astro';
import SearchWidget from '../components/SearchWidget.astro';
import { data, getGroupSlug, getRuleCount, getTotalRuleCount, getTotalServiceCount, getPopularServices } from '../data/rules';
import { SITE_URL, GITHUB_URL, schemaAuthor, schemaPublisher, schemaWebSite, SITE_DATE_PUBLISHED, LICENSE_CC_BY_URL, LICENSE_MIT_URL } from '../data/site';
const base = import.meta.env.BASE_URL.replace(/\/$/, '');
const totalRules = getTotalRuleCount();
const totalServices = getTotalServiceCount();
const popularServices = getPopularServices();
const org = {
'@type': 'Organization',
'@id': `${SITE_URL}#organization`,
name: schemaPublisher.name,
url: GITHUB_URL,
logo: {
'@type': 'ImageObject',
url: `${SITE_URL}favicon.svg`,
},
sameAs: [GITHUB_URL, SITE_URL],
contactPoint: {
'@type': 'ContactPoint',
contactType: 'technical support',
url: `${GITHUB_URL}/issues`,
},
};
const buildDate = new Date().toISOString().slice(0, 10);
const faqItems = [
{
'@type': 'Question',
name: 'What are Prometheus alerting rules?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Prometheus alerting rules are PromQL-based conditions evaluated by the Prometheus server. When a condition is true for a specified duration, an alert fires and is routed by AlertManager to receivers like Slack, PagerDuty, or email. Rules are defined as YAML files and cover metrics thresholds, absence of expected data, and rate-of-change conditions.',
},
},
{
'@type': 'Question',
name: 'How do I use these Prometheus alert rules?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Find the service you want to monitor, copy the YAML snippet for any rule, and paste it into your Prometheus rules file (e.g., alerts/my-service.yml). Reload Prometheus to apply the rules. Adjust thresholds to match your workload — the values provided are sensible defaults but may need tuning.',
},
},
{
'@type': 'Question',
name: 'What exporters and services are covered?',
acceptedAnswer: {
'@type': 'Answer',
text: `Awesome Prometheus Alerts covers ${totalServices} services across ${data.groups.length} categories: ${data.groups.map((g) => `${g.name} (${g.services.map((s) => s.name).join(', ')})`).join('; ')}.`,
},
},
{
'@type': 'Question',
name: 'What is the difference between warning and critical severity?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Critical alerts require immediate human attention — the system is down or severely degraded and revenue or reliability is directly impacted. Warning alerts need attention soon but are not immediately urgent. Info alerts are awareness-only, such as configuration changes or underutilized resources. Set up AlertManager routes to page on-call engineers only for critical alerts.',
},
},
{
'@type': 'Question',
name: 'What is PromQL?',
acceptedAnswer: {
'@type': 'Answer',
text: 'PromQL (Prometheus Query Language) is the functional query language used to select, filter, and aggregate time-series data in Prometheus. Alert rules use PromQL expressions — for example, rate(http_requests_total[5m]) > 100 fires when request rate exceeds 100/s over a 5-minute window.',
},
},
{
'@type': 'Question',
name: 'Can I contribute new alert rules?',
acceptedAnswer: {
'@type': 'Answer',
text: `Yes! Contributions are welcome. Open a pull request on GitHub at ${GITHUB_URL} with your new rules added to the _data/rules.yml file. Follow the existing format: provide a clear rule name, a description explaining what the alert means and why it matters, a tested PromQL expression, an appropriate severity, and a sensible "for" duration to avoid false positives.`,
},
},
{
'@type': 'Question',
name: 'What is AlertManager and how does it relate to these rules?',
acceptedAnswer: {
'@type': 'Answer',
text: 'AlertManager is the component that receives firing alerts from Prometheus and handles deduplication, grouping, silencing, and routing to receivers (Slack, PagerDuty, email, webhooks). The alert rules in this collection fire alerts from Prometheus — AlertManager then decides who to notify and when. See the AlertManager Configuration guide on this site for setup examples.',
},
},
{
'@type': 'Question',
name: 'How do I silence or suppress an alert?',
acceptedAnswer: {
'@type': 'Answer',
text: 'AlertManager supports silences — time-bounded mutes applied via its UI or API that suppress notifications without disabling the rule. For recurring suppression (nights, weekends, deployments), use inhibition rules or time-based PromQL patterns. See the Sleep Peacefully guide on this site for timezone-aware suppression examples using day_of_week() and hour() functions.',
},
},
{
'@type': 'Question',
name: 'What is the license for these alert rules?',
acceptedAnswer: {
'@type': 'Answer',
text: `The alert rules and content are licensed under Creative Commons CC BY 4.0 — you are free to use, adapt, and redistribute them, including commercially, as long as you provide attribution. The site source code is licensed under MIT. See the LICENSE file in the GitHub repository for details.`,
},
},
];
const jsonLd = {
'@context': 'https://schema.org',
'@graph': [
org,
{
'@type': 'SoftwareSourceCode',
name: 'awesome-prometheus-alerts',
description: 'Collection of Prometheus alerting rules — YAML configurations for 90+ services',
url: GITHUB_URL,
codeRepository: GITHUB_URL,
programmingLanguage: 'YAML',
author: schemaAuthor,
license: LICENSE_MIT_URL,
},
{
'@type': 'Dataset',
name: 'Awesome Prometheus Alerts',
description: `Collection of ${totalRules} production-ready Prometheus alerting rules covering ${totalServices} services and 13 categories including databases, Kubernetes, cloud providers, and more.`,
url: SITE_URL,
creator: schemaAuthor,
datePublished: SITE_DATE_PUBLISHED,
dateModified: buildDate,
keywords: ['Prometheus', 'alerting rules', 'monitoring', 'PromQL', 'SRE', 'DevOps', 'observability'],
license: LICENSE_CC_BY_URL,
isAccessibleForFree: true,
},
{
'@type': 'FAQPage',
'@id': `${SITE_URL}#faq`,
mainEntity: faqItems,
},
{
'@type': 'WebSite',
'@id': `${SITE_URL}#website`,
name: schemaWebSite.name,
url: SITE_URL,
description: `Collection of ${totalRules} copy-pasteable Prometheus alerting rules for ${totalServices} services.`,
publisher: { '@id': `${SITE_URL}#organization` },
potentialAction: {
'@type': 'SearchAction',
target: {
'@type': 'EntryPoint',
urlTemplate: `${SITE_URL}rules/?q={search_term_string}`,
},
'query-input': 'required name=search_term_string',
},
},
{
'@type': 'SoftwareApplication',
name: schemaWebSite.name,
applicationCategory: 'DeveloperApplication',
operatingSystem: 'All',
url: SITE_URL,
image: `${SITE_URL}favicon.svg`,
description: `Collection of ${totalRules} copy-pasteable Prometheus alerting rules for ${totalServices} services — covering databases, Kubernetes, cloud providers, message brokers, and more.`,
author: schemaAuthor,
publisher: { '@id': `${SITE_URL}#organization` },
offers: {
'@type': 'Offer',
price: 0,
priceCurrency: 'USD',
},
},
{
'@type': 'ItemList',
name: 'Site Navigation',
itemListElement: [
{ '@type': 'SiteNavigationElement', position: 1, name: 'Alert Rules', url: `${SITE_URL}rules/` },
{ '@type': 'SiteNavigationElement', position: 2, name: 'AlertManager Config', url: `${SITE_URL}alertmanager/` },
{ '@type': 'SiteNavigationElement', position: 3, name: 'Blackbox Exporter', url: `${SITE_URL}blackbox-exporter/` },
{ '@type': 'SiteNavigationElement', position: 4, name: 'Sleep Peacefully', url: `${SITE_URL}sleep-peacefully/` },
],
},
],
};
---
<BaseLayout
title="Awesome Prometheus Alerts | Copy-pasteable Prometheus alerting rules"
description={`Collection of ${totalRules} copy-pasteable Prometheus alerting rules for ${totalServices} services — covering databases, Kubernetes, cloud providers, message brokers, and more.`}
jsonLd={jsonLd}
>
<!-- Hero -->
<section class="bg-gradient-to-b from-slate-50 dark:from-slate-900/50 to-white dark:to-slate-950 border-b border-slate-200 dark:border-slate-800">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-16 text-center">
<div class="flex justify-center mb-6">
<img
src={`${base}/images/prometheus-logo.png`}
alt="Prometheus"
class="h-16 w-auto"
width="64"
height="64"
/>
</div>
<h1 class="text-3xl sm:text-4xl font-bold text-slate-900 dark:text-white mb-4">
Awesome Prometheus Alert Rules
</h1>
<p class="text-lg text-slate-500 dark:text-slate-400 mb-8 max-w-2xl mx-auto">
{totalRules} copy-pasteable Prometheus alerting rules.
Find, copy, and deploy alerts in seconds.
</p>
<!-- Search -->
<div class="max-w-xl mx-auto mb-8">
<SearchWidget />
</div>
<!-- CTA buttons -->
<div class="flex flex-wrap justify-center gap-3">
<a
href={`${base}/rules/`}
class="inline-flex items-center gap-2 px-5 py-2.5 bg-brand hover:bg-brand/90 text-white font-medium rounded-lg transition-colors"
>
Browse all rules
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</a>
<a
href="https://github.com/samber/awesome-prometheus-alerts"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-2 px-5 py-2.5 border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-200 font-medium rounded-lg hover:border-slate-300 dark:hover:border-slate-600 transition-colors"
>
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/></svg>
GitHub
</a>
</div>
</div>
</section>
<!-- Stats -->
<section class="border-b border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-950">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<StatsBar />
</div>
</section>
<!-- Popular services -->
<section class="border-b border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-950">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-10">
<h2 class="text-xl font-bold text-slate-900 dark:text-white mb-5">Popular services</h2>
<div class="flex flex-wrap gap-2">
{popularServices.map(({ service, groupSlug, serviceSlug }) => (
<a
href={`${base}/rules/${groupSlug}/${serviceSlug}/`}
class="inline-flex items-center px-3 py-1.5 rounded-full text-sm font-medium bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-brand/10 dark:hover:bg-brand-dark/10 hover:text-brand dark:hover:text-brand-dark transition-colors border border-slate-200 dark:border-slate-700"
>
{service.name}
</a>
))}
</div>
</div>
</section>
<!-- Categories grid -->
<section class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<h2 class="text-xl font-bold text-slate-900 dark:text-white mb-8">Browse by category</h2>
<div class="space-y-10">
{data.groups.map((group) => {
const groupSlug = getGroupSlug(group);
const groupRuleCount = group.services.reduce((sum, svc) => sum + getRuleCount(svc), 0);
return (
<div>
<div class="flex items-center justify-between mb-4">
<h3 class="text-base font-semibold text-slate-700 dark:text-slate-300">
<a href={`${base}/rules/${groupSlug}/`} class="hover:text-brand dark:hover:text-brand-dark transition-colors">
{group.name}
</a>
</h3>
<span class="text-xs text-slate-400 dark:text-slate-500">
{group.services.length} services · {groupRuleCount} rules
</span>
</div>
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3">
{group.services.map((service) => (
<ServiceCard service={service} group={group} base={base} />
))}
</div>
</div>
);
})}
</div>
</section>
<!-- Guides section -->
<section class="bg-slate-50 dark:bg-slate-900/50 border-t border-slate-200 dark:border-slate-800">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<h2 class="text-xl font-bold text-slate-900 dark:text-white mb-6">Guides</h2>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<a href={`${base}/alertmanager/`} class="group block p-5 rounded-xl bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700/60 hover:border-brand/40 dark:hover:border-brand-dark/40 hover:shadow-sm transition-all">
<div class="text-brand dark:text-brand-dark mb-2">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
</div>
<h3 class="font-semibold text-slate-800 dark:text-slate-100 group-hover:text-brand dark:group-hover:text-brand-dark transition-colors mb-1">AlertManager Config</h3>
<p class="text-sm text-slate-500 dark:text-slate-400">Prometheus and AlertManager configuration examples and troubleshooting.</p>
</a>
<a href={`${base}/blackbox-exporter/`} class="group block p-5 rounded-xl bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700/60 hover:border-brand/40 dark:hover:border-brand-dark/40 hover:shadow-sm transition-all">
<div class="text-brand dark:text-brand-dark mb-2">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
</div>
<h3 class="font-semibold text-slate-800 dark:text-slate-100 group-hover:text-brand dark:group-hover:text-brand-dark transition-colors mb-1">Blackbox Exporter</h3>
<p class="text-sm text-slate-500 dark:text-slate-400">Worldwide probes, Prometheus config, geohash/Grafana map setup.</p>
</a>
<a href={`${base}/sleep-peacefully/`} class="group block p-5 rounded-xl bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700/60 hover:border-brand/40 dark:hover:border-brand-dark/40 hover:shadow-sm transition-all">
<div class="text-brand dark:text-brand-dark mb-2">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" /></svg>
</div>
<h3 class="font-semibold text-slate-800 dark:text-slate-100 group-hover:text-brand dark:group-hover:text-brand-dark transition-colors mb-1">Sleep Peacefully</h3>
<p class="text-sm text-slate-500 dark:text-slate-400">Time-based alert suppression and timezone-aware PromQL patterns.</p>
</a>
</div>
</div>
</section>
<!-- FAQ section -->
<section class="border-t border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-950">
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<h2 class="text-xl font-bold text-slate-900 dark:text-white mb-8">Frequently asked questions</h2>
<dl class="grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-2">
{faqItems.map((item) => (
<details class="group border-b border-slate-100 dark:border-slate-800">
<summary class="flex cursor-pointer items-center justify-between gap-3 py-3 text-sm font-semibold text-slate-800 dark:text-slate-100 list-none [&::-webkit-details-marker]:hidden">
{item.name}
<svg class="w-4 h-4 flex-shrink-0 text-slate-400 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</summary>
<p class="pb-4 text-sm text-slate-500 dark:text-slate-400 leading-relaxed">{item.acceptedAnswer.text}</p>
</details>
))}
</dl>
</div>
</section>
</BaseLayout>