snmp_exporter: turning interface counters into Prometheus labels
SNMP Exporter for Prometheus
At a glance
- What is it?
- The Prometheus SNMP Exporter walks a device with SNMP and emits one Prometheus sample per interface index, with labels filled in from the same OID subtree. It is a Go service on port 9116 driven entirely by a generated snmp.yml.
- Who is it for?
- snmp_exporter is the right answer for switches, routers, NAS boxes and anything else that only speaks SNMP, because it removes the manual walking and relabelling that a generic SNMP-to-metrics bridge would still leave you. The mapping is mechanical and inspectable, which means a wrong label is a configuration problem you can read off a diff rather than a mystery.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Star history
- prometheus/snmp_exporter2,190 ★ · +8
| Repository | 2026-10-08 | 2026-10-22 |
|---|---|---|
| prometheus/snmp_exporter | 2.2k | 2.2k |
8 Stars in the last 14 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The problem is index alignment, not SNMP itself
SNMP describes data in OID trees governed by MIB files. Prometheus wants an n-dimensional matrix with labels. The README's position is that these two structures map onto each other perfectly and that the exporter does the translation so nobody has to walk the tree by hand.
The mechanism is column ordering. OID subtrees keep the same order in different places in the tree, so the row for index 2 under ifIndex is the same row as index 2 under ifDescr, ifName, ifHCOutOctets and ifAlias. For a device with an interface at number 2, a partial snmpwalk returns:
1.3.6.1.2.1.2.2.1.1.2 = INTEGER: 2 # ifIndex for '2' is literally just '2'
1.3.6.1.2.1.2.2.1.2.2 = STRING: "eth0" # ifDescr
1.3.6.1.2.1.31.1.1.1.1.2 = STRING: "eth0" # IfName
1.3.6.1.2.1.31.1.1.1.10.2 = INTEGER: 1000 # ifHCOutOctets, 1000 bytes
1.3.6.1.2.1.31.1.1.1.18.2 = STRING: "" # ifAliasBecause the row index is shared across those subtrees, the exporter can join them into one sample with the descriptive fields turned into labels rather than separate time series. Where an SNMP entry carries multiple index values, each one becomes its own Prometheus label.
The README also warns about the security model before it shows any of this. Community strings in SNMP are not treated as secrets because SNMP v1 and v2c send them unencrypted. If that matters for your network, SNMP v3 is the requirement, not a preference.
One exporter process, one URL per device
Binaries come from the GitHub releases page and need no special installation. Start the exporter as a daemon or straight from the command line:
./snmp_exporterEverything else is driven through the /snmp endpoint on port 9116. With no parameters at all, a scrape uses the default transport, which is udp, the default port 161, the default auth public_v2 and the default module if_mib. That combination is the quick start the README recommends: a read-only community on the target device and the interface counters module.
The parameters are where the real configuration lives. auth and module select credentials and MIB module, and the README is explicit that both must exist in snmp.yml or the scrape fails. Transport and port are part of the target syntax rather than separate parameters, written as [transport://]host[:port], so a device on tcp port 1161 becomes target=tcp%3A%2F%2F192.0.0.8%3A1161 with the colon and slashes URL encoded. Prometheus does that encoding for you inside a configuration file, which removes a class of silent zero-sample scrapes.
There are two more optional parameters worth knowing. snmp_context passes an SNMP context, and it overrides the context_name from snmp.yml, which is how per VRF collection on network gear is arranged. snmp_engineid matters for SNMPv3 and can be supplied in the URL for a specific engine. The exporter's own operational metrics sit on a separate /metrics endpoint, so you can watch the thing that is watching the network.
snmp.yml is generated output, and the README says so
This is the single most useful operational fact in the README: the default configuration file is called snmp.yml and should not be edited by hand. If you need different content, the pointer is the generating configuration section, and the generator/ directory in the repository is where that work happens. The shipped snmp.yml covers a variety of common hardware walked with SNMP v2 GETBULK.
Configuration loading has a few behaviours that are easy to miss. The --config.file parameter can be given more than once to load several files, and it supports glob matching, with snmp*.yml given as the example. The --config.expand-environment-variables parameter injects environment variables into some fields, specifically the username, password and priv_password fields in the auths section, and it defaults to disabled. Duplicate module or auth entries are treated as invalid and cannot be loaded at all, which is a deliberate refusal rather than a silent last one wins.
That last point connects to a file in the repository root named auth-split-migration.md. It exists because auths moved out into separate configuration files, and the --config.file flag is how you load them. Anyone with an old deployment should read that document before reorganising their config directory, since the same snmp.yml can now arrive in pieces.
Licensing is Apache-2.0, with LICENSE and NOTICE both present in the tree. That matters for a component sitting between you and your network devices, since you are embedding credential handling in a component you may redistribute internally.
Multi-module scrapes trade deduplication for concurrency
Multi-module handling lets one scrape collect from several modules at once, which is how you get interface counters and vendor tables in the same request. There are two ways to write it. Modules can be separated by a comma, giving module=if_mib,arista_sw, or you can repeat the parameter as multiple params_module entries, giving module=if_mib&module=arista_sw. Both forms are valid and the README shows both URLs.
Concurrency across those modules is set with --snmp.module-concurrency, and the default is 1. That default is a statement about how the exporter treats a device: one walk at a time unless you say otherwise. Devices are frequently the least capable thing in a monitoring path, so raising this is a decision about the target hardware rather than about the exporter.
The cost is stated in the same paragraph. This implementation does not perform any de-duplication of walks between different modules. If two modules overlap on an OID subtree, the work happens twice and you pay for it in load on the device. The Prometheus side of the same feature passes modules as a YAML list under params.
- job_name: 'my'
params:
module:
- if_mib
- synology
- ucd_la_tableRelabelling is where target, auth and module get decided
In a Prometheus configuration, the target, auth and module URL parameters can be controlled through relabelling rather than being written into every static config. The scrape job names its targets, sets metrics_path to /snmp and supplies params, then maps __address__ onto __param_target so the value the exporter receives is the device address, and maps that back onto instance so the resulting series carry a readable instance label.
scrape_configs:
- job_name: 'snmp'
static_configs:
- targets:
- 192.168.1.2 # SNMP device.
- switch.local # SNMP device.
- tcp://192.168.1.3:1161 # SNMP device using TCP transport and custom port.
metrics_path: /snmp
params:
auth: [public_v2]
module: [if_mib]Because the transport prefix lives in the target string itself, a job can mix a plain UDP device, a hostname and a TCP device on a non standard port in one static config. That is a small detail that removes a common complaint about exporters that need a second job per transport.
The project also keeps practical setup material in the repository rather than only on a website: examples/sample-configs holds working setups for a local workstation, network devices and SNMPv2c and v3 auth, plus notes on HTTP proxies such as Zscaler, and examples/systemd holds a sample unit file. Proxy notes matter more than they look, because a corporate TLS interception layer is a common reason an exporter that works on a laptop produces nothing in a data centre.
Version history and the shape of the Go build
The most recent published release is 0.30.1 on 2026-01-07, a single bugfix for a gosnmp import. The release before it, 0.30.0 on 2026-01-05, is where the visible features came from: snmp_engineid support, and a change that makes the exporter warn when the configuration file is missing and fail when auths or modules are missing. It also pre-allocated the OID conversion functions and handled uint32 values in pduValueAsString. The 0.29.0 release on 2025-04-23 added modules for Yamaha RT series, Cisco device and fibre channel, and an MSA fieldserver gateway, alongside several MIB updates.
Reading the release notes tells you where the ongoing work is. Most of it is snmp.yml changes, which is the generator side of the project: ELTEX, keepalived, APC, Raritan, NEC, Mikrotik, Cisco Core. MIB drift is a permanent maintenance burden for an SNMP exporter, and the commit references show it is being paid down continuously rather than in bursts.
The build is conventional Go. go.mod declares Go 1.25.0 and depends on gosnmp v1.44.0 for the protocol work, kingpin for flags and the standard prometheus client libraries. Two Dockerfiles are present, one on a busybox base and one distroless, both copying a prebuilt binary plus snmp.yml and exposing 9116. The Makefile sets DOCKER_ARCHS to amd64, armv7, arm64 and ppc64le, which is a reasonable statement that this runs on the hardware you already have. The last push to the repository was on 2026-09-18.
Editorial conclusion
snmp_exporter is the right answer for switches, routers, NAS boxes and anything else that only speaks SNMP, because it removes the manual walking and relabelling that a generic SNMP-to-metrics bridge would still leave you. The mapping is mechanical and inspectable, which means a wrong label is a configuration problem you can read off a diff rather than a mystery. Two things to check before you rely on it. The snmp.yml shipped in the repository is generated output and the README says not to edit it by hand, so treat generator/ as the source of truth for your modules. And decide early whether you need SNMPv3, because v1 and v2c community strings travel in clear text and the README says so outright. Start with the if_mib module and public_v2 on a test device, then read examples/sample-configs for the v3 and proxy cases.
Frequently asked questions
How does snmp_exporter turn SNMP interfaces into Prometheus metrics?
OID subtrees keep the same row order in different places in the tree, so the exporter joins index 2 of ifIndex, ifDescr, ifName and ifHCOutOctets into one sample. The descriptive columns become labels, giving a series like ifHCOutOctets with ifIndex, ifDescr, ifName and ifAlias as labels. Where an SNMP entry has several index values, each becomes its own label.
What do the auth and module URL parameters do for a scrape?
They select which credentials and which MIB module definition from snmp.yml the exporter uses for that target. The README is explicit that both must be defined in snmp.yml, and release 0.30.0 made a missing auth or module a hard failure rather than an empty scrape. With no parameters the exporter falls back to the public_v2 auth and the if_mib module.
Can I edit snmp.yml directly to add a device module?
The README says the default snmp.yml should not be edited by hand and points to the configuration generating instructions instead, with the generator/ directory in the repository doing that work. You can load extra files with the --config.file parameter, given more than once, and it accepts glob patterns such as snmp*.yml. Duplicate module or auth entries are rejected rather than merged.
Is SNMPv3 required for the snmp_exporter to be safe on a network?
The README states that community strings are not considered secrets because they are sent unencrypted in SNMP v1 and v2c, so SNMP v3 is required for secure access. Credentials for v3 live in the auths section of snmp.yml, where the username, password and priv_password fields can also be filled from environment variables with --config.expand-environment-variables, which is disabled by default.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/prometheus-snmp-exporter)Star history chart for your README
[](https://hysenlabs.com/projects/prometheus-snmp-exporter)