SNMP Notifier Integration Guide
Version 1.6.9-option-1 | 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:localis built from this repository, not pulled.bootstrap.shrebuilds it when a file underprometheus-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 |
|---|---|---|
|
|
Webhook listen address |
|
|
NMS trap destination |
|
|
SNMP version (V2c or V3) |
|
|
SNMPv2c community string |
|
|
Trap send timeout |
|
|
Number of retry attempts |
|
|
Default OID when the alert has no |
|
|
Label with the trigger OID |
|
|
Label with the resolved (clear) OID |
|
|
Label used for the severity varbind |
|
- |
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.
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.
SNMPv3 (Recommended for Production)
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.
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.1.1.2 |
ftAlarmSeverity |
STRING |
|
|
.65666.1.1.3 |
ftAlarmDescription |
STRING |
description template |
|
.65666.1.1.4 |
ftAlarmInstance |
STRING |
|
|
.65666.1.1.5 |
ftAlarmName |
STRING |
|
|
.65666.1.1.6 |
ftAlarmSummary |
STRING |
|
|
.65666.1.1.7 |
ftAlarmTimestamp |
STRING |
|
|
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 defineftAcsNotifyObjects 8in the MIB. Keep MIB index = OID suffix.
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 |
|---|---|
|
Array of alerts |
|
“firing” or “resolved” |
|
Alert name |
|
Alert severity |
|
Instance label |
|
Alert summary |
|
Alert description |
|
Alert start time |
|
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
Using SNMP Trap Catcher (Recommended)
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
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"
8. Troubleshooting
Common Issues
Traps Not Received
-
Check snmp-notifier is running:
docker ps | grep snmp-notifier docker logs snmp-notifier
-
Check firewall allows UDP 162:
# On NMS server sudo tcpdump -i any udp port 162
-
Verify destination is correct:
grep SNMP_TRAP_ADDRESS .env # Should show your NMS address
SNMPv3 Authentication Failed
-
Check credentials match NMS configuration:
grep -E "SNMP_AUTH|SNMP_PRIV" .env
-
Verify protocol compatibility:
-
snmp-notifier v2.1.0 supports only auth
SHA/MD5and privacyAES/DES(no SHA-256 / AES-256).SNMP_AUTH_PROTOCOLandSNMP_PRIV_PROTOCOLmust match the NMS exactly — a mismatch fails silently (no trap arrives).
-
-
Check snmp-notifier logs for auth errors:
docker logs snmp-notifier 2>&1 | grep -i auth
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"
}]'
Related Documentation
-
Alertmanager Configuration — Channel setup
-
Alertmanager API Guide — Sending alerts programmatically
-
OID Mapping Reference — Full OID list