GuiderUtveckling och driftPrometheus och Grafana

Övervaka dina servrar med Prometheus och Grafana

Prometheus och Grafana på Debian 13 i rootless Podman bakom Caddy, med node_exporter på varje server, en färdig dashboard, larm till mobilen via ntfy och Grafanas kontakter med tillverkaren avstängda.

Testad på Prometheus 3.15.0, Grafana 13.2.3, Alertmanager 0.34.1 och node_exporter 1.9.0 på Debian 13 (trixie) på en server hos Melonslab Uppdaterad 2 oktober 2026

Rekommenderad server för guiden

VC-S Micro · 2 vCPU · 8 GB Minne · 250 GB Lagring

Månadsvis, ingen bindningstid 7 dagars öppet köp

90 kr/mån

Beställ nu
På den här sidan

Det här sätter du upp

Fyra program arbetar tillsammans här:

  • node_exporter körs på varje server du övervakar och rapporterar dess mätvärden för CPU, minne, disk och nätverk.
  • Prometheus hämtar mätvärdena var 15:e sekund, sparar dem och kontrollerar dina larmregler.
  • Alertmanager skickar ett meddelande när en regel löser ut, här till din mobil via ntfy.
  • Grafana visar mätvärdena som dashboards i webbläsaren.

Prometheus, Alertmanager och Grafana körs i en pod under en egen användare som heter monitoring, bakom Caddy från Podman-guiden. Bara Grafana går att nå, via Caddy. Vi har också en guide för Zabbix: välj Zabbix om du vill ha ett enda program som du ställer in genom att klicka i dess webbgränssnitt, och Prometheus och Grafana om du hellre har din konfiguration i textfiler och vill använda Grafanas dashboards.

Prometheus, Alertmanager och node_exporter är öppen källkod under Apache 2.0-licensen och utvecklas av Prometheus-projektet, ett graduerat projekt inom Cloud Native Computing Foundation, som är en del av den amerikanska ideella organisationen Linux Foundation. De kontaktar ingen extern tjänst som standard. Grafana är öppen källkod under GNU AGPL 3.0 och utvecklas av Grafana Labs (Raintank Inc.), ett företag i New York i USA. Som standard skickar Grafana användningsstatistik till stats.grafana.org var 24:e timme, frågar grafana.com efter nya versioner av sig själv och sina plugins, hämtar ett nyhetsflöde och laddar ner plugins vid start: på vår testserver uppdaterade den sitt Prometheus-plugin från grafana.com inom 20 sekunder efter första starten. Steg 5 stänger av allt detta.

Varje steg nedan har körts på en server hos Melonslab med Debian 13:

  • node_exporter svarade Prometheus från podden, och port 9100 svarade inte från tre testplatser på internet.
  • En andra node_exporter svarade bara över HTTPS med lösenord: utan lösenord gav den 401, och utan rätt certifikat avbröts anslutningen.
  • Standardinloggningen admin/admin nekades från internet, och detsamma gällde nya registreringar och besökare som inte är inloggade. Grafana loggade varje besökares riktiga adress.
  • Dashboarden Node Exporter Full visade CPU, minne, disk och nätverk för båda servrarna.
  • När disken fylldes till 93 % kom larmet till ntfy-ämnet efter fem minuter, och ett Resolved-meddelande följde när utrymmet frigjorts. En andra server som slutade svara rapporterades inom tre minuter, och larmet hävdes inom fem minuter efter att den svarat igen.
  • Med inställningarna i steg 5 slog Grafana bara upp grafana.com när vi importerade en dashboard eller öppnade listan över plugins.
  • En säkerhetskopia av Grafanas data återställdes med dashboarden kvar, och allt startade igen av sig självt efter en omstart av servern.

Den andra servern i testerna var en container på samma server hos Melonslab, med samma node_exporter-paket och inställningar som i steg 9. Brandväggsreglerna för en riktig andra server i steg 9 testades inte.

Podden använde mellan 320 och 500 MB minne när den övervakade två servrar. Det mesta är Grafana, som använde mellan 250 och 410 MB; Prometheus använde 30 till 40 MB och Alertmanager omkring 15 MB. node_exporter använde omkring 25 MB på varje server.

Innan du börjar

Du behöver:

  • en server uppsatt som i Podman-guiden, med Caddy igång och ufw från säkerhetsguiden;
  • en A-post och en AAAA-post för grafana.example.com som pekar på din server;
  • något som tar emot larmen: ett ntfy-ämne, på din egen ntfy-server eller på den publika ntfy.sh, och ntfy-appen i mobilen som prenumererar på det. På ntfy.sh kan alla som känner till ämnets namn läsa dess meddelanden, så välj ett långt namn som inte går att gissa, till exempel det som openssl rand -hex 12 skriver ut.

Exemplen använder grafana.example.com för Grafana, 203.0.113.10 för serverns IPv4-adress, som ip -brief address show eth0 visar, 2001:db8::10 för dess IPv6-adress, web1.example.com för en andra server du vill övervaka och ntfy.example.com/servers för ntfy-ämnet. Byt ut dem genomgående.

1. Installera node_exporter

Som root installerar du node_exporter från Debian:

apt update
apt install -y --no-install-recommends prometheus-node-exporter curl

Debians paket körs som en egen användare, startar vid uppstart och får Debians säkerhetsuppdateringar. --no-install-recommends hoppar över en uppsättning extra insamlare, till exempel för SMART och IPMI, som en virtuell server inte har någon nytta av. Kontrollera att den svarar:

curl -s http://127.0.0.1:9100/metrics | grep -m1 node_uname_info

node_exporter lyssnar på port 9100 på alla adresser. Det måste den: Prometheus i sin rootless pod når servern från serverns egen IPv4-adress, inte från 127.0.0.1. ufw håller porten stängd mot internet, så öppna inte 9100.

2. Skapa användaren

useradd -m -s /bin/bash monitoring
loginctl enable-linger monitoring
machinectl shell monitoring@

3. Skapa Grafanas administratörslösenord

Som monitoring:

openssl rand -base64 18 | tr -d '\n' | podman secret create grafana-admin-password -
podman secret inspect --showsecret --format '{{.SecretData}}' grafana-admin-password

Den andra raden visar lösenordet. Spara det i din lösenordshanterare. Grafana sätter det för användaren admin vid första starten, så det välkända standardlösenordet admin är aldrig aktivt, inte ens en minut. Det spelar roll: i vårt test hittade skannrar det nya namnet via dess certifikat och begärde Grafanas startsida inom en minut efter att Caddy fått certifikatet.

4. Skriv konfigurationen

mkdir -p ~/monitoring
cd ~/monitoring

Skapa prometheus.yml, som talar om för Prometheus vad den ska hämta:

global:
  scrape_interval: 15s

rule_files:
  - /etc/prometheus/rules.yml

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["localhost:9093"]

scrape_configs:
  - job_name: node
    static_configs:
      - targets: ["host.containers.internal:9100"]
        labels:
          instance: monitor

Inifrån podden pekar host.containers.internal på servern utanför, där node_exporter körs. instance: monitor är namnet servern får i Grafana; välj ett eget.

Skapa rules.yml, med två larm:

groups:
  - name: servers
    rules:
      - alert: ServerDown
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }} is not answering"
      - alert: DiskAlmostFull
        expr: 1 - node_filesystem_avail_bytes{fstype!~"tmpfs|ramfs"} / node_filesystem_size_bytes > 0.85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }}: {{ $labels.mountpoint }} is {{ $value | humanizePercentage }} full"

ServerDown löser ut när Prometheus inte har nått en server på två minuter, och DiskAlmostFull när en disk har varit mer än 85 % full i fem minuter.

Skapa alertmanager.yml, med ditt ntfy-ämne:

route:
  receiver: ntfy
  group_by: [alertname, instance]

receivers:
  - name: ntfy
    webhook_configs:
      - url: https://ntfy.example.com/servers?template=alertmanager

?template=alertmanager (ntfy 2.14 eller senare) gör att ntfy omvandlar Alertmanagers meddelande till en läsbar notis med titel. group_by skickar en notis per larm och server. Utan den lägger Alertmanager alla larm i samma notis.

Skapa datasources.yml, som kopplar Grafana till Prometheus:

apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    uid: prometheus
    url: http://localhost:9090
    isDefault: true

5. Definiera podden

mkdir -p ~/.config/containers/systemd
cd ~/.config/containers/systemd

Skapa monitoring.pod:

[Pod]
PodName=monitoring
# Grafana, reached through Caddy only
PublishPort=127.0.0.1:8102:3000

[Install]
WantedBy=default.target

Prometheus och Alertmanager publicerar ingen port. Grafana når dem inne i podden, på localhost.

Skapa prometheus.container:

[Container]
ContainerName=prometheus
Image=quay.io/prometheus/prometheus:latest
Pod=monitoring.pod
Volume=%h/monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
Volume=%h/monitoring/rules.yml:/etc/prometheus/rules.yml:ro
Volume=prometheus-data:/prometheus
Exec=--config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/prometheus --storage.tsdb.retention.time=30d --storage.tsdb.retention.size=5GB
AutoUpdate=registry

[Service]
Restart=always

Skapa alertmanager.container:

[Container]
ContainerName=alertmanager
Image=quay.io/prometheus/alertmanager:latest
Pod=monitoring.pod
Volume=%h/monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
Volume=alertmanager-data:/alertmanager
# One Alertmanager, no cluster
Exec=--config.file=/etc/alertmanager/alertmanager.yml --storage.path=/alertmanager --cluster.listen-address=
AutoUpdate=registry

[Service]
Restart=always

Det tomma --cluster.listen-address= stänger av klusterläget, som du inte behöver med en enda Alertmanager. Utan det avslutas Alertmanager direkt i en rootless pod.

Och grafana.container:

[Container]
ContainerName=grafana
Image=docker.io/grafana/grafana:latest
Pod=monitoring.pod
Volume=grafana-data:/var/lib/grafana
Volume=%h/monitoring/datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml:ro
Secret=grafana-admin-password
Environment=GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/grafana-admin-password
Environment=GF_SERVER_ROOT_URL=https://grafana.example.com/
# No usage reports, update checks, news feed, plugin downloads or Gravatar
Environment=GF_ANALYTICS_REPORTING_ENABLED=false GF_ANALYTICS_CHECK_FOR_UPDATES=false
Environment=GF_ANALYTICS_CHECK_FOR_PLUGIN_UPDATES=false GF_PLUGINS_PREINSTALL_DISABLED=true
Environment=GF_NEWS_NEWS_FEED_ENABLED=false GF_SECURITY_DISABLE_GRAVATAR=true
Environment=GF_PLUGINS_PUBLIC_KEY_RETRIEVAL_DISABLED=true
AutoUpdate=registry

[Service]
Restart=always

Det här gör GF_-raderna:

  • GF_SERVER_ROOT_URL är Grafanas publika adress, som den använder i länkar.
  • GF_ANALYTICS_REPORTING_ENABLED=false stoppar användningsstatistiken som skickas till stats.grafana.org var 24:e timme. Enligt Grafana Labs integritetspolicy kan sådana rapporter innehålla operativsystem, land, plats, version och hur programmet används.
  • De två CHECK_FOR-raderna stoppar versionskontrollerna mot grafana.com.
  • GF_PLUGINS_PREINSTALL_DISABLED=true hindrar Grafana från att ladda ner och uppdatera sina medföljande app-plugins från grafana.com vid varje start.
  • GF_NEWS_NEWS_FEED_ENABLED=false tar bort nyhetsflödet, och GF_SECURITY_DISABLE_GRAVATAR=true hindrar att användarnas bilder hämtas från Gravatar.
  • GF_PLUGINS_PUBLIC_KEY_RETRIEVAL_DISABLED=true gör att Grafana kontrollerar signaturer på plugins med sin inbyggda nyckel, i stället för att hämta den från grafana.com var tionde dag.

Anonym åtkomst och registrering av nya användare är avstängda i Grafana som standard, så de behöver ingen rad här. Steg 7 kontrollerar båda.

6. Starta den

systemctl --user daemon-reload
systemctl --user start monitoring-pod
podman ps --format '{{.Names}} {{.Status}}'

Alla fyra, monitoring-infra, prometheus, alertmanager och grafana, visar Up. Kontrollera att Prometheus når node_exporter:

podman exec prometheus wget -qO- localhost:9090/api/v1/targets | grep -o '"health":"[a-z]*"'

Den skriver ut "health":"up".

7. Sätt Caddy framför

Gå tillbaka till root med exit, byt till machinectl shell caddy@ och lägg till det här blocket sist i ~/Caddyfile:

grafana.example.com {
    reverse_proxy 127.0.0.1:8102
}

Starta om Caddy med systemctl --user restart caddy. Kontrollera sedan från din egen dator att standardinloggningen och registrering nekas:

curl -s -H 'Content-Type: application/json' -d '{"user":"admin","password":"admin"}' https://grafana.example.com/login
curl -s -H 'Content-Type: application/json' -d '{"email":"test@example.com"}' https://grafana.example.com/api/user/signup
curl -s https://grafana.example.com/api/search

De svarar Invalid username or password, User signup is disabled och Unauthorized. Grafana loggar nekade anrop, som de här tre, med besökarens riktiga adress, som den läser från Caddys header X-Forwarded-For. Som monitoring visar podman logs grafana | grep remote_addr dem med din egen adress. Grafanas port är bara öppen på 127.0.0.1, så ingen på internet kan nå Grafana förbi Caddy och förfalska den headern.

8. Logga in och lägg till dashboarden

Öppna https://grafana.example.com och logga in som admin med lösenordet från steg 3.

Node Exporter Full är en välanvänd färdig dashboard för node_exporter, publicerad på grafana.com med id 1860. Så här importerar du den:

  • Öppna Dashboards, välj New och sedan Import dashboard.
  • Ange 1860 i fältet Grafana.com dashboard URL or ID och välj Load.
  • Välj Import.

När du importerar med id hämtar din server dashboarden från grafana.com. Vill du undvika det laddar du ner JSON-filen från dashboardens sida på grafana.com och använder Upload dashboard JSON file i stället.

Dashboarden öppnas på din server. Job och Instance högst upp väljer server; de första raderna visar CPU, minne, nätverkstrafik och diskutrymme, och de hopfällda raderna nedanför innehåller detaljerna.

9. Övervaka en annan server

node_exporter har varken lösenord eller kryptering som standard, så ge den båda på en server som Prometheus når över internet. Som root på den andra servern:

apt update
apt install -y --no-install-recommends prometheus-node-exporter apache2-utils
mkdir -p /etc/node-exporter
cd /etc/node-exporter
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days 3650 -nodes \
  -keyout node-exporter.key -out node-exporter.crt \
  -subj "/CN=web1.example.com" -addext "subjectAltName=DNS:web1.example.com"
chgrp prometheus node-exporter.key
chmod 640 node-exporter.key

Det skapar ett eget certifikat för servern, giltigt i tio år. Välj nu ett långt lösenord som Prometheus ska logga in med, och spara det till nästa steg. htpasswd frågar efter det två gånger, och bara dess bcrypt-hash hamnar i node_exporters konfiguration:

HASH=$(htpasswd -nBC 12 "" | tr -d ':\n')
cat > web.yml <<EOF
tls_server_config:
  cert_file: /etc/node-exporter/node-exporter.crt
  key_file: /etc/node-exporter/node-exporter.key
basic_auth_users:
  prometheus: $HASH
EOF
chgrp prometheus web.yml
chmod 640 web.yml

Peka node_exporter mot filen, och låt din övervakningsserver nå porten från båda sina adresser:

sed -i 's|^ARGS=.*|ARGS="--web.config.file=/etc/node-exporter/web.yml"|' /etc/default/prometheus-node-exporter
systemctl restart prometheus-node-exporter
ufw allow from 203.0.113.10 to any port 9100 proto tcp
ufw allow from 2001:db8::10 to any port 9100 proto tcp
cat node-exporter.crt

Prometheus ansluter över IPv6 när web1.example.com har en AAAA-post, och därför behövs båda adresserna. Kopiera certifikatet som cat skrev ut. Om båda servrarna finns hos Melonslab når de inte varandra direkt som standard: koppla ihop dem först. Vill du inte öppna någon port alls fungerar också en VPN med WireGuard mellan servrarna, och då hämtar Prometheus via VPN-adressen i stället.

Som monitoring på övervakningsservern sparar du certifikatet och lösenordet bredvid konfigurationen:

cd ~/monitoring
nano web1.crt        # paste the certificate
nano web1.password   # the password, on one line
chmod 644 web1.crt web1.password

Prometheus körs som en annan användare i sin container, så filerna måste vara läsbara. Din hemkatalog är fortfarande stängd för andra användare på servern, vilket ls -ld ~ visar som drwx------. Lägg till ett jobb sist i prometheus.yml:

  - job_name: web1
    scheme: https
    tls_config:
      ca_file: /etc/prometheus/web1.crt
    basic_auth:
      username: prometheus
      password_file: /etc/prometheus/web1.password
    static_configs:
      - targets: ["web1.example.com:9100"]
        labels:
          instance: web1

Och i ~/.config/containers/systemd/prometheus.container lägger du till två rader under de andra Volume=-raderna:

Volume=%h/monitoring/web1.crt:/etc/prometheus/web1.crt:ro
Volume=%h/monitoring/web1.password:/etc/prometheus/web1.password:ro

Starta om Prometheus och kontrollera konfigurationen:

systemctl --user daemon-reload
systemctl --user restart prometheus
podman exec prometheus promtool check config /etc/prometheus/prometheus.yml

promtool skriver SUCCESS för konfigurationen och reglerna. Kontrollen av målen från steg 6 skriver nu "health":"up" två gånger, och i Grafana visar Job web1 den andra servern.

Prometheus jämför serverns certifikat med det du kopierade, så ingen kan utge sig för att vara servern, och lösenordet håller alla andra ute. Från alla andra adresser svarar porten inte alls.

10. Testa larmen

Stoppa node_exporter på den andra servern en stund:

systemctl stop prometheus-node-exporter

Inom ungefär tre minuter visar mobilen Alert: ServerDown med Instance: web1: regeln väntar två minuter, Prometheus kontrollerar den en gång i minuten, och Alertmanager väntar 30 sekunder på andra larm att skicka tillsammans med det. Starta den igen med systemctl start prometheus-node-exporter. Ett Resolved: ServerDown-meddelande följer inom fem minuter, eftersom Alertmanager skickar uppdateringar om ett pågående larm högst var femte minut.

Så länge ett larm är aktivt upprepar Alertmanager det var fjärde timme. Alerting och sedan Alert rules i Grafana visar båda reglerna och deras läge. Länken Source i meddelandet pekar in i podden och går inte att öppna från mobilen.

Regeln ServerDown täcker inte själva övervakningsservern: om den ligger nere finns inget kvar som kan skicka larmet. För att få veta det övervakar du Grafanas adress från något annat ställe, till exempel med Uptime Kuma på en annan server.

11. Kontrollera vad Grafana kontaktar

För att se vilka namn servern slår upp, som root:

apt install -y tcpdump
timeout 600 tcpdump -i eth0 -n -l 'udp port 53' | grep -o 'A? [^ ]*'

Låt det köra medan du använder Grafana några minuter. Med inställningarna från steg 5 slog Grafana bara upp grafana.com när vi importerade en dashboard med id, och när vi öppnade Administration, Plugins and data, Plugins: den sidan listar katalogen över plugins från grafana.com. Dina larm syns som uppslag av din ntfy-server. Prometheus och Alertmanager slog inte upp något annat, varken före eller efter en omstart.

12. Diskutrymme

Prometheus sparar sina mätvärden i 30 dagar och låter dem aldrig växa förbi 5 GB, beroende på vilken gräns som nås först. Det är flaggorna --storage.tsdb.retention i steg 5. Våra två servrar gav Prometheus omkring 1 800 tidsserier, och efter 40 minuter tog data 2,2 MB. Enligt Prometheus dokumentation tar ett lagrat mätvärde 1 till 2 byte, vilket för två servrar var 15:e sekund blir ungefär 10 till 20 MB per dag, så 30 dagar håller sig långt under gränsen på 5 GB; vi körde den inte i 30 dagar. För att se hur mycket den använder, som monitoring:

podman unshare du -sh ~/.local/share/containers/storage/volumes/prometheus-data/_data

13. Håll den uppdaterad

Slå på Podmans dagliga uppdateringar som monitoring:

systemctl --user enable --now podman-auto-update.timer

Taggarna latest följer varje ny version, även nya huvudversioner. Både Prometheus och Grafana publicerar uppgraderingsanvisningar, som är värda att läsa när huvudversionen ändras. Vill du i stället stanna på en versionsserie av Grafana använder du en tagg som 13.2 i grafana.container och byter den för hand när du vill gå vidare. node_exporter kommer från Debian, så de automatiska uppdateringarna från säkerhetsguiden installerar dess säkerhetsuppdateringar.

14. Säkerhetskopiera

Grafana sparar sina användare, dashboards och inställningar i en databas i volymen grafana-data. Stoppa Grafana en kort stund för att kopiera volymen, som monitoring:

mkdir -p ~/backup
systemctl --user stop grafana
podman volume export grafana-data > ~/backup/grafana-data.tar
systemctl --user start grafana
tar -czf ~/backup/monitoring-config.tar.gz monitoring .config/containers/systemd

Den andra filen innehåller din konfiguration från steg 4, 5 och 9, inklusive den andra serverns lösenord. Kopiera ~/backup till en annan maskin och förvara den säkert.

Prometheus mätvärden är inte med. De går oftast att undvara: de byggs upp igen från det att Prometheus körs igen, och det du förlorar är bara historiken. Vill du behålla dem kopierar du volymen prometheus-data på samma sätt, med Prometheus stoppad.

För att återställa Grafanas data på en ny server, efter steg 1 till 6:

systemctl --user stop grafana
podman volume rm grafana-data
podman volume create grafana-data
podman volume import grafana-data ~/backup/grafana-data.tar
podman unshare chown 472:0 "$(podman volume inspect --format '{{.Mountpoint}}' grafana-data)"
systemctl --user start grafana

chown ger tillbaka volymen till Grafanas användare i containern, 472.

Felsökning

Alertmanager startar inte, och podman logs alertmanager visar no private IP address found, and explicit IP not provided. Flaggan --cluster.listen-address= från steg 5 saknas. I en rootless pod ser Alertmanager bara serverns publika adress och vägrar starta ett kluster på den.

Ett mål visar "health":"down", och podman exec prometheus wget -qO- localhost:9090/api/v1/targets visar server returned HTTP status 401 Unauthorized. Lösenordet i web1.password stämmer inte med det du gav htpasswd. Kontrollera att filen bara innehåller lösenordet.

Felet för målet visar x509: certificate signed by unknown authority. web1.crt är inte certifikatet från den andra servern, till exempel om du har skapat ett nytt där. Kopiera det igen från /etc/node-exporter/node-exporter.crt och starta om Prometheus.

Grafana startar inte efter en återställning, och dess logg visar GF_PATHS_DATA='/var/lib/grafana' is not writable. Raden podman unshare chown från steg 14 saknas.

Grafanas inloggningssida laddas, men admin och ditt lösenord nekas. Lösenordet sätts bara när Grafana skapar sin databas. Om Grafana startade en gång innan hemligheten fanns är lösenordet fortfarande admin. Sätt det till hemlighetens lösenord, som monitoring:

podman exec grafana grafana cli admin reset-admin-password "$(podman secret inspect --showsecret --format '{{.SecretData}}' grafana-admin-password)"

Kommandot avslutas med Admin password changed successfully.

Kör det på din egen server

VC-S Micro

90 kr/mån

vCPU
2
Minne
8 GB
Lagring
250 GB
Trafik
10 TB
Standard
HDD · RAID 10
  • Full root-åtkomst
  • Nativt /64 IPv6
  • RAID-skyddad lagring
  • Malmö, Sverige
  • Månadsvis, ingen bindningstid
  • 7 dagars öppet köp
Alla guider