SNMP Notifier Integration Guide

Version 1.6.9-option-2 | Updated: August 07, 2026

SNMP Notifier Integration Guide

This document describes how Alertmanager sends SNMP traps to external Network Management Systems (NMS) using snmp-notifier.


1. Architecture

Data Flow

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Prometheus    │────▶│  Alertmanager   │────▶│  snmp-notifier  │────▶│   NMS/Zabbix    │
│  (alert rules)  │     │    (webhook)    │     │   (UDP trap)    │     │   (port 162)    │
└─────────────────┘     └─────────────────┘     └─────────────────┘     └─────────────────┘
        │                       │                       │                       │
   prometheus_rules.yml    POST JSON             SNMP v2c/v3 trap         Receives &
   fires alert             to :9464              to destination           processes

Components

Component Port Description

Alertmanager

9093

Routes alerts to snmp-notifier via webhook

snmp-notifier

9464

Converts JSON alerts to SNMP traps

NMS

162

Receives SNMP traps (Zabbix, Nagios, etc.)

snmp-catcher

8089

Test receiver with Web UI (optional)

Docker Services

# snmp-notifier - production trap sender
snmp-notifier:
  image: maxwo/snmp-notifier:v2.1.0
  ports: 9464 (internal)
  profiles: [snmp]

# snmp-catcher - testing trap receiver
snmp-catcher:
  image: snmp-catcher:local
  ports: 162/udp, 8089 (Web UI)
  profiles: [snmp]

snmp-catcher:local is built from this repository, not pulled. bootstrap.sh rebuilds it when a file under prometheus-grafana-stack/snmp-catcher/ is newer than the image, and keeps the existing image if the build fails — an air-gapped host loaded a current one from the offline bundle. So a change to the catcher does reach an upgraded stack, but on a host with no internet and no fresh bundle it will not, and bootstrap says so rather than failing quietly.


2. Configuration

Environment Variables (.env)

# ============================================
# SNMP Trap Notifications
# ============================================

# Destination NMS address
SNMP_TRAP_ADDRESS=nms.company.com:162

# SNMP Version: V2c or V3
SNMP_VERSION=V2c

# SNMPv2c settings
SNMP_COMMUNITY=public

# SNMPv3 settings (when SNMP_VERSION=V3)
SNMP_AUTH_USERNAME=snmpuser
SNMP_AUTH_PASSWORD=authpassword
SNMP_PRIV_PASSWORD=privpassword
SNMP_AUTH_PROTOCOL=SHA      # SHA or MD5
SNMP_PRIV_PROTOCOL=AES      # AES or DES

snmp-notifier Command Line Options

Option Default Description

--web.listen-address

127.0.0.1:9464

Webhook listen address

--snmp.destination

127.0.0.1:162

NMS trap destination

--snmp.version

V2c

SNMP version (V2c or V3)

--snmp.community

public

SNMPv2c community string

--snmp.timeout

5s

Trap send timeout

--snmp.retries

3

Number of retry attempts

--trap.default-oid

…65666.2.0.99

Default OID when the alert has no oid label

--trap.oid-label

oid

Label with the trigger OID

--trap.resolution-oid-label

oid_resolved

Label with the resolved (clear) OID

--alert.severity-label

severity

Label used for the severity varbind

--trap.description-template

-

Go template for the description varbind

The varbinds are also routed under our PEN via --trap.default-objects-base-oid / --trap.user-objects-base-oid / --trap.user-object — see §5 “How the varbind payload is built” for the full command.

Alertmanager Webhook Configuration

The entrypoint.sh automatically adds snmp-notifier webhook:

receivers:
  - name: 'default'
    webhook_configs:
      - url: 'http://127.0.0.1:9464/alerts'
        send_resolved: true

3. SNMP Versions

SNMPv2c

Simple community-based authentication. Good for internal networks.

SNMP_VERSION=V2c
SNMP_COMMUNITY=public

Security: Community string sent in plaintext. Use only on trusted networks.

Provides authentication and encryption.

SNMP_VERSION=V3
SNMP_AUTH_USERNAME=snmpuser
SNMP_AUTH_PASSWORD=authpassword123
SNMP_PRIV_PASSWORD=privpassword456
SNMP_AUTH_PROTOCOL=SHA
SNMP_PRIV_PROTOCOL=AES

Security Levels:

Level Auth Encryption Variables

noAuthNoPriv

No

No

username only

authNoPriv

Yes

No

username + auth password

authPriv

Yes

Yes

username + auth + priv passwords

Supported Protocols:

Type Options

Authentication

SHA (recommended), MD5

Privacy

AES (recommended), DES


4. Custom OIDs

Using Label in Alert Rules

Add oid label to Prometheus alert rules for custom trap OID:

# prometheus_rules.yml
groups:
  - name: infrastructure
    rules:
      - alert: DbUnreachable
        expr: up{job="mysql"} == 0
        for: 1m
        labels:
          severity: critical
          oid: "1.3.6.1.4.1.65666.2.0.3"    # Custom OID
        annotations:
          summary: "Database {{ $labels.instance }} is unreachable"
          description: "MySQL server has been down for more than 1 minute"

      - alert: HighCpuUsage
        expr: node_cpu_usage > 90
        for: 5m
        labels:
          severity: warning
          oid: "1.3.6.1.4.1.65666.2.0.50"   # Custom OID
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"

Default OID

If no oid label is present, snmp-notifier uses:

1.3.6.1.4.1.65666.2.0.99  (generic alert)

Resolved OID (trigger vs resolved)

Each rule also carries an oid_resolved label. When the alert is firing, the trap’s snmpTrapOID.0 is the oid (trigger); when it resolves, the trap’s snmpTrapOID.0 is the oid_resolved. This is wired in the entrypoint via --trap.oid-label=oid and --trap.resolution-oid-label=oid_resolved.

labels:
  severity: critical
  oid:          "1.3.6.1.4.1.65666.2.0.41"   # sent while firing
  oid_resolved: "1.3.6.1.4.1.65666.2.0.42"   # sent when it clears

oid_resolved values are frequently shared across a warning/critical pair (both clear to the same OID), so they need not be unique. Edit both fields in the config-ui Rules editor (the “OID resolved” field) — see the OID Reference page for the full trigger/resolved map.

OID Structure

1.3.6.1.4.1.65666         Enterprise OID (Friendly Technologies, IANA PEN 65666)
           │
           └── .2.0.X     Trap definitions
                  │
                  ├── .1   AcsCommProblem
                  ├── .3   DbUnreachable
                  ├── .11  LicenseExpiring
                  ├── .21  DeviceAccessDenied
                  └── .99  Generic (default)

5. MIB File

Location

prometheus-grafana-stack/alertmanager/mibs/
├── FRIENDLY-TECH-ACS-MIB.txt    # MIB definition
└── OID-MAPPING.md               # OID reference

OID Categories

Infrastructure Alarms (.2.0.1 - .2.0.10)
Trap OID Name Alertmanager alertname Severity

.2.0.1

ftAcsCommProblem

AcsCommProblem

critical

.2.0.2

ftAcsCommRestored

AcsCommProblem (resolved)

clear

.2.0.3

ftDbUnreachable

DbUnreachable

critical

.2.0.4

ftDbRestored

DbUnreachable (resolved)

clear

.2.0.5

ftTimeDrift

TimeDrift

warning

.2.0.6

ftTimeSynced

TimeDrift (resolved)

clear

Licensing Alarms (.2.0.11 - .2.0.20)
Trap OID Name Alertmanager alertname Severity

.2.0.11

ftLicenseExpiring

LicenseExpiring

warning

.2.0.12

ftLicenseExpired

LicenseExpired

critical

.2.0.13

ftLicenseRenewed

LicenseExpired (resolved)

clear

Device Limit Alarms (.2.0.21 - .2.0.40)
Trap OID Name Alertmanager alertname Severity

.2.0.21

ftDeviceAccessDenied

DeviceAccessDenied

critical

.2.0.22

ftDeviceLimitWarning

DeviceLimitWarning

warning

.2.0.23

ftDeviceLimitExceeded

DeviceLimitExceeded

critical

.2.0.25

ftTR069LimitWarning

TR069LimitWarning

warning

.2.0.26

ftTR069LimitExceeded

TR069LimitExceeded

critical

.2.0.27

ftLWM2MLimitWarning

LWM2MLimitWarning

warning

.2.0.28

ftLWM2MLimitExceeded

LWM2MLimitExceeded

critical

.2.0.29

ftMQTTLimitWarning

MQTTLimitWarning

warning

.2.0.30

ftMQTTLimitExceeded

MQTTLimitExceeded

critical

.2.0.31

ftUSPLimitWarning

USPLimitWarning

warning

.2.0.32

ftUSPLimitExceeded

USPLimitExceeded

critical

Infrastructure Resource Alarms (.2.0.41 - .2.0.70)
Trap OID Name Alertmanager alertname Severity Threshold

.2.0.41

ftServerDown

ServiceDown

critical

.2.0.43

ftAPIDown

APIDown

critical

.2.0.45

ftFrontendDown

FrontendDown

critical

.2.0.47

ftCPUUsageWarning

CPUUsageHigh

warning

>=80%

.2.0.48

ftCPUUsageCritical

CPUUsageCritical

critical

>=90%

.2.0.50

ftMemoryUsageWarning

MemoryUsageHigh

warning

>=80%

.2.0.51

ftMemoryUsageCritical

MemoryUsageCritical

critical

>=90%

.2.0.53

ftDiskSpaceWarning

DiskSpaceFilling

warning

>=80%

.2.0.54

ftDiskSpaceCritical

DiskSpaceCritical

critical

>=90%

.2.0.56

ftTCPSessionsWarning

TCPSessionsWarning

warning

>=800

.2.0.57

ftTCPSessionsCritical

TCPSessionsCritical

critical

>=1000

.2.0.59

ftHTTPSessionsWarning

HTTPSessionsWarning

warning

>=800

.2.0.60

ftHTTPSessionsCritical

HTTPSessionsCritical

critical

>=1000

.2.0.62

ftUDPSessionsWarning

UDPSessionsWarning

warning

>=800

.2.0.63

ftUDPSessionsCritical

UDPSessionsCritical

critical

>=1000

.2.0.65

ftHazelcastNodeDown

HazelcastNodeDown

critical

.2.0.67

ftMySQLDown

MySQLDown

critical

Variable Bindings (trap payload)

Every trap carries the same 7 variable bindings, rooted under our enterprise subtree ftAcsNotifyObjects = 1.3.6.1.4.1.65666.1.1. The order and types below are exactly what snmp-notifier puts on the wire (verified with a live receiver) — they match the OBJECT-TYPE definitions in the MIB one-to-one:

Full OID Name Type Source Example value

.65666.1.1.1

ftAlarmOid

STRING

trap OID + labels

…65666.2.0.67-…68[alertname=MySQLDown,severity=critical]

.65666.1.1.2

ftAlarmSeverity

STRING

severity label

critical

.65666.1.1.3

ftAlarmDescription

STRING

description template

[firing] MySQLDown @ db-1: MySQL is down

.65666.1.1.4

ftAlarmInstance

STRING

instance label

db-1:9104

.65666.1.1.5

ftAlarmName

STRING

alertname label

MySQLDown

.65666.1.1.6

ftAlarmSummary

STRING

summary annotation

MySQL is down

.65666.1.1.7

ftAlarmTimestamp

STRING

startsAt

2026-07-25T14:03:11Z

Severity is a STRING, not an INTEGER. snmp-notifier emits the raw severity label text (critical/warning/info/clear). Do not configure your NMS to expect an enumerated integer.

Two standard SNMP varbinds always precede these: sysUpTime.0 (1.3.6.1.2.1.1.3.0) and snmpTrapOID.0 (1.3.6.1.6.3.1.1.4.1.0, whose value is the per-alert trap OID from the oid label — see §4).

How the varbind payload is built

snmp-notifier splits the payload into default objects and user objects, each rooted at a configurable base OID. Our entrypoint (alertmanager/snmp-notifier-entrypoint.sh) points both bases at our PEN so every field resolves against FRIENDLY-TECH-ACS-MIB instead of the tool’s stock 1.3.6.1.4.1.98789 subtree:

--trap.default-objects-base-oid=1.3.6.1.4.1.65666.1.1   # .1 oid, .2 severity, .3 description
--trap.user-objects-base-oid=1.3.6.1.4.1.65666.1.1      # .4 instance, .5 name, .6 summary, .7 timestamp
--alert.severity-label=severity
--trap.description-template=/etc/snmp-notifier/description.tmpl
--trap.user-object=4=/etc/snmp-notifier/objects/instance.tmpl
--trap.user-object=5=/etc/snmp-notifier/objects/name.tmpl
--trap.user-object=6=/etc/snmp-notifier/objects/summary.tmpl
--trap.user-object=7=/etc/snmp-notifier/objects/timestamp.tmpl
  • Default objects (.1--.3) are built in to snmp-notifier: .1 = trap OID(s)
    labels, .2 = severity (from --alert.severity-label), .3 = the rendered --trap.description-template.

  • User objects (.4--.7) are our additions. Each is a tiny Go template in alertmanager/snmp-notifier-objects/ (mounted at /etc/snmp-notifier/objects/) that emits one field, e.g. instance.tmpl{{ (index .Alerts 0).Labels.instance }}.

  • To add an 8th field: create objects/<field>.tmpl, add --trap.user-object=8=… in the entrypoint loop, and define ftAcsNotifyObjects 8 in the MIB. Keep MIB index = OID suffix.

Installing MIB on NMS

# Copy MIB file to NMS
scp alertmanager/mibs/FRIENDLY-TECH-ACS-MIB.txt nms:/usr/share/snmp/mibs/

# Verify MIB is readable
snmptranslate -m +FRIENDLY-TECH-ACS-MIB -IR ftDbUnreachable
# Expected: FRIENDLY-TECH-ACS-MIB::ftDbUnreachable

6. Templates

Description Template

Location: alertmanager/snmp-notifier-template.tmpl

{{- /* SNMP Notifier Description Template */ -}}
{{ range .Alerts -}}
[{{ .Status }}] {{ .Labels.alertname }}{{ if .Labels.instance }} @ {{ .Labels.instance }}{{ end }}{{ if .Annotations.summary }}: {{ .Annotations.summary }}{{ end }}
{{ end -}}

Output Example:

[firing] DbUnreachable @ mysql-primary: Database connection failed

Available Template Variables

Variable Description

.Alerts

Array of alerts

.Status

“firing” or “resolved”

.Labels.alertname

Alert name

.Labels.severity

Alert severity

.Labels.instance

Instance label

.Annotations.summary

Alert summary

.Annotations.description

Alert description

.StartsAt

Alert start time

.EndsAt

Alert end time (if resolved)

Custom Template Example

{{- /* Custom template with severity and timestamp */ -}}
{{ range .Alerts -}}
ALERT: {{ .Labels.alertname }}
SEVERITY: {{ .Labels.severity | toUpper }}
INSTANCE: {{ .Labels.instance | default "N/A" }}
STATUS: {{ .Status }}
TIME: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ if .Annotations.summary -}}
SUMMARY: {{ .Annotations.summary }}
{{ end -}}
{{ if .Annotations.description -}}
DESCRIPTION: {{ .Annotations.description }}
{{ end -}}
---
{{ end -}}

7. Testing

Bootstrap offers built-in testing with SNMP Trap Catcher:

# In the bootstrap config menu:
#   Configuration › Alerting › SNMP › "Built-in Trap Catcher (testing)"

# Web UI available at:
http://<server>:8089

Features:

  • Real-time trap display

  • SNMPv2c and SNMPv3 support

  • Persistent storage (survives restarts)

  • Clear button to reset

Manual Testing

1. Check Services Running
docker ps | grep -E "snmp-notifier|snmp-catcher"
2. Send Test Alert
curl -X POST http://localhost:9093/api/v2/alerts \
  -H "Content-Type: application/json" \
  -d '[{
    "labels": {
      "alertname": "TestSNMPAlert",
      "severity": "warning",
      "oid": "1.3.6.1.4.1.65666.2.0.99"
    },
    "annotations": {
      "summary": "Test SNMP trap from CLI"
    }
  }]'
3. Check snmp-notifier Logs
docker logs snmp-notifier --tail 20
4. View Traps (if using snmp-catcher)
curl http://localhost:8089/health
# {"status":"ok","total_received":5,"traps_count":5}

Testing with snmptrap Command

# Send test trap directly (bypassing Alertmanager).
# snmpTrapOID.0 = per-alert trap OID (.2.0.3 = ftDbUnreachable), then the 7
# varbinds in wire order. NOTE: severity (.2) is a STRING, not an integer.
snmptrap -v 2c -c public localhost:162 '' \
  1.3.6.1.4.1.65666.2.0.3 \
  1.3.6.1.4.1.65666.1.1.1 s "1.3.6.1.4.1.65666.2.0.3[alertname=DbUnreachable]" \
  1.3.6.1.4.1.65666.1.1.2 s "critical" \
  1.3.6.1.4.1.65666.1.1.3 s "[firing] DbUnreachable @ db-1: DB unreachable" \
  1.3.6.1.4.1.65666.1.1.4 s "db-1:9104" \
  1.3.6.1.4.1.65666.1.1.5 s "DbUnreachable" \
  1.3.6.1.4.1.65666.1.1.6 s "Database server unreachable" \
  1.3.6.1.4.1.65666.1.1.7 s "2026-07-25T14:03:11Z"

Testing SNMPv3

# SHA/AES
snmptrap -v 3 -u snmpuser -l authPriv \
  -a SHA -A authpassword \
  -x AES -X privpassword \
  localhost:162 '' \
  1.3.6.1.4.1.65666.2.0.3 \
  1.3.6.1.4.1.65666.1.1.2 s "TestV3"

8. Troubleshooting

Common Issues

Traps Not Received
  1. Check snmp-notifier is running:

docker ps | grep snmp-notifier
docker logs snmp-notifier
  1. Check firewall allows UDP 162:

# On NMS server
sudo tcpdump -i any udp port 162
  1. Verify destination is correct:

grep SNMP_TRAP_ADDRESS .env
# Should show your NMS address
SNMPv3 Authentication Failed
  1. Check credentials match NMS configuration:

grep -E "SNMP_AUTH|SNMP_PRIV" .env
  1. Verify protocol compatibility:

    • snmp-notifier v2.1.0 supports only auth SHA/MD5 and privacy AES/DES (no SHA-256 / AES-256). SNMP_AUTH_PROTOCOL and SNMP_PRIV_PROTOCOL must match the NMS exactly — a mismatch fails silently (no trap arrives).

  2. Check snmp-notifier logs for auth errors:

docker logs snmp-notifier 2>&1 | grep -i auth
Wrong OID in Trap
  1. Check alert has oid label:

labels:
  oid: "1.3.6.1.4.1.65666.2.0.3"
  1. If no label, default OID is used:

1.3.6.1.4.1.65666.2.0.99
Empty Description
  1. Check template file exists:

docker exec snmp-notifier ls -la /etc/snmp-notifier/
  1. Verify template syntax:

cat alertmanager/snmp-notifier-template.tmpl

Useful Commands

# Restart snmp-notifier
docker compose restart snmp-notifier

# View real-time logs
docker logs -f snmp-notifier

# Check Alertmanager config
curl -s http://localhost:9093/api/v2/status | jq '.config'

# List active alerts
curl -s http://localhost:9093/api/v2/alerts | jq '.[].labels.alertname'

# Resolve test alert
curl -X POST http://localhost:9093/api/v2/alerts \
  -H "Content-Type: application/json" \
  -d '[{
    "labels": {"alertname": "TestSNMPAlert", "severity": "warning"},
    "endsAt": "2024-01-01T00:00:00Z"
  }]'