How to receive SNMP traps in Nagios Core

SNMP traps let routers, switches, and appliances report events at the moment they happen instead of waiting for a scheduled poll. In Nagios Core, the trap must pass through a local receiver and arrive as a passive service result before it appears in monitoring state.

Net-SNMP provides snmptrapd, which listens for notifications and can call a traphandle program when an accepted trap arrives. The handler can write a PROCESS_SERVICE_CHECK_RESULT command into the Nagios Core command FIFO, which is normally /var/lib/nagios4/rw/nagios.cmd on Debian and Ubuntu package installs.

The trap daemon user becomes a trusted command submitter, so give it only the command-file group it needs and restrict accepted trap sources. A single SNMPv2c linkUp test proves the handoff; production handlers can map specific OIDs to different services, return codes, or plugin output.

Steps to receive SNMP traps in Nagios Core:

  1. Install the Net-SNMP trap daemon and client tools on the monitoring server.
    $ sudo apt update && sudo apt install --assume-yes snmptrapd snmp

    Debian and Ubuntu packages create a Debian-snmp service user for snmptrapd. Use the equivalent package and service user on other Linux distributions.

  2. Confirm that Nagios Core accepts external commands and passive service results.
    $ sudo grep -E '^(check_external_commands|command_file|accept_passive_service_checks)=' /etc/nagios4/nagios.cfg
    check_external_commands=1
    command_file=/var/lib/nagios4/rw/nagios.cmd
    accept_passive_service_checks=1

    Enable external commands first when check_external_commands is 0 or the command file path is missing.
    Related: How to enable external commands in Nagios Core

  3. Check the command FIFO group.
    $ sudo ls -ld /var/lib/nagios4/rw /var/lib/nagios4/rw/nagios.cmd
    drwxrwsr-x 1 nagios nagios 4096 Jun 25 00:27 /var/lib/nagios4/rw
    prw-rw---- 1 nagios nagios    0 Jun 25 00:27 /var/lib/nagios4/rw/nagios.cmd

    The leading p on nagios.cmd means it is a FIFO. The group shown on the command file is the group that trusted local integrations need for write access.

  4. Create an object file for the passive trap result.
    $ sudoedit /etc/nagios4/conf.d/snmp-trap-receive.cfg
  5. Add a passive host and service that match the trap handler target.
    snmp-trap-receive.cfg
    define command {
        command_name            check_snmp_trap_passive
        command_line            /usr/lib/nagios/plugins/check_dummy $ARG1$ "$ARG2$"
    }
     
    define host {
        use                     linux-server
        host_name               web01.example.net
        alias                   Web server trap source
        address                 192.0.2.10
        active_checks_enabled   0
        passive_checks_enabled  1
    }
     
    define service {
        use                     generic-service
        host_name               web01.example.net
        service_description     SNMP Trap
        active_checks_enabled   0
        passive_checks_enabled  1
        check_command           check_snmp_trap_passive!0!Waiting for SNMP trap
        max_check_attempts      1
    }

    Skip the host block if web01.example.net already exists. Nagios Core ignores passive results for host or service names that are not loaded in the running configuration.
    Related: How to add a service check in Nagios Core

  6. Create the trap handler script.
    $ sudoedit /usr/local/sbin/nagios-snmp-trap-handler
  7. Add the handler that converts a received trap into a passive service result.
    nagios-snmp-trap-handler
    #!/bin/sh
    NAGIOS_CMD=/var/lib/nagios4/rw/nagios.cmd
    NAGIOS_HOST=${1:?host name required}
    NAGIOS_SERVICE=${2:-SNMP Trap}
     
    read trap_host
    read trap_transport
    trap_sender=$trap_transport
    case "$trap_transport" in
        *'['*']:'*)
            trap_sender=${trap_transport#*[}
            trap_sender=${trap_sender%%]*}
            ;;
    esac
     
    trap_oid=unknown
    while IFS= read -r line; do
        case "$line" in
            *snmpTrapOID.0*|*1.3.6.1.6.3.1.1.4.1.0*|*iso.3.6.1.6.3.1.1.4.1.0*)
                trap_oid=${line##* }
                ;;
        esac
    done
     
    now=$(date +%s)
    printf '[%s] PROCESS_SERVICE_CHECK_RESULT;%s;%s;1;WARNING - SNMP trap %s from %s\n' \
        "$now" "$NAGIOS_HOST" "$NAGIOS_SERVICE" "$trap_oid" "$trap_sender" > "$NAGIOS_CMD"

    The handler maps every accepted trap to a WARNING result for one service. Add OID-specific branches later when different traps need different return codes or service descriptions.

  8. Make the trap handler executable.
    $ sudo chmod 0755 /usr/local/sbin/nagios-snmp-trap-handler
  9. Allow the snmptrapd service user to write to the Nagios Core command FIFO group.
    $ sudo usermod --append --groups nagios Debian-snmp

    Use the group that owns /var/lib/nagios4/rw/nagios.cmd on the monitoring server. Do not make the command FIFO world-writable; any process that can write this FIFO can submit Nagios Core external commands.

  10. Verify that the trap daemon user has the command-file group.
    $ id Debian-snmp
    uid=101(Debian-snmp) gid=103(Debian-snmp) groups=103(Debian-snmp),101(nagios)
  11. Open the snmptrapd configuration file.
    $ sudoedit /etc/snmp/snmptrapd.conf
  12. Authorize the trap sender and call the handler.
    snmptrapd.conf
    authCommunity log,execute monitor-traps 192.0.2.10
    traphandle default /usr/local/sbin/nagios-snmp-trap-handler web01.example.net "SNMP Trap"

    Replace monitor-traps with a site-specific community and restrict the source to trusted sender addresses. Prefer SNMPv3 authentication and privacy when the sending devices support it.

  13. Validate the Nagios Core object configuration.
    $ sudo nagios4 -v /etc/nagios4/nagios.cfg
    Nagios Core 4.4.6
    ##### snipped #####
    Reading configuration data...
       Read main config file okay...
       Read object config files okay...
    ##### snipped #####
    Total Warnings: 0
    Total Errors:   0
    
    Things look okay - No serious problems were detected during the pre-flight check

    Fix every reported object, command, template, or path error before reloading Nagios Core.
    Related: How to validate the Nagios Core configuration

  14. Reload Nagios Core so the passive service object becomes active.
    $ sudo systemctl reload nagios4

    Use the service name and control method from the local installation when Nagios Core was installed from source.
    Related: How to manage the Nagios Core system service

  15. Restart snmptrapd so it reads the new configuration and group membership.
    $ sudo systemctl restart snmptrapd
  16. Enable snmptrapd at boot.
    $ sudo systemctl enable snmptrapd
  17. Send a test trap from the authorized sender.
    $ snmptrap -v 2c -c monitor-traps monitor.example.net "" \
      .1.3.6.1.6.3.1.1.5.4 \
      .1.3.6.1.2.1.2.2.1.1.2 i 2

    Run the test from the host or device address allowed by authCommunity. The OID 1.3.6.1.6.3.1.1.5.4 is the standard linkUp notification.

  18. Check that snmptrapd logged the received trap.
    $ sudo journalctl --unit=snmptrapd --no-pager --since '5 minutes ago'
    Jun 25 00:28:55 monitor snmptrapd[228]: 2026-06-25 00:28:55 web01.example.net [UDP: [192.0.2.10]:41660->[192.0.2.5]:162]:
    Jun 25 00:28:55 monitor snmptrapd[228]: iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.6.3.1.1.5.4
    Jun 25 00:28:55 monitor snmptrapd[228]: iso.3.6.1.2.1.2.2.1.1.2 = INTEGER: 2
  19. Confirm that Nagios Core shows the passive trap result.
    $ curl --silent --show-error --get \
      'http://monitor.example.net/nagios4/cgi-bin/statusjson.cgi' \
      --data-urlencode 'query=service' \
      --data-urlencode 'hostname=web01.example.net' \
      --data-urlencode 'servicedescription=SNMP Trap'
    {
      "result": {
        "type_text": "Success"
      },
      "data": {
        "service": {
          "plugin_output": "WARNING - SNMP trap iso.3.6.1.6.3.1.1.5.4 from 192.0.2.10",
          "check_type": 1,
          "accept_passive_checks": true
        }
      }
    }

    check_type 1 means Nagios Core processed a passive result. Use the local CGI URL and authentication method for that site; the same plugin output should appear on the service status page.