DEV Community

Cover image for I Built a Free, Self-Hosted SNMP Toolkit — Now With Real-Time WebSocket Push
Sumit Dhaka
Sumit Dhaka

Posted on

I Built a Free, Self-Hosted SNMP Toolkit — Now With Real-Time WebSocket Push

If you've ever worked with SNMP — testing NMS integrations, debugging trap handlers, or validating MIB structures — you know the pain. You end up juggling Net-SNMP CLI commands you can never remember, snmptrapd configs scattered everywhere, and a $500 MIB browser that still looks like it was designed in 2003.

I built Trishul SNMP to fix that. One Docker container. Browser-based. Free.

This post covers what's new in v1.2.4 — the biggest update yet — and why I built it this way.


What Is Trishul SNMP?

It's a self-hosted SNMP dev toolkit that combines five tools into one clean web UI:

What Instead of
SNMP Simulator (UDP agent) snmpsim + CLI config
Walk & Parse → JSON snmpwalk + manual OID lookup
Trap Sender + Receiver snmptrap + snmptrapd
MIB Browser (tree view) iReasoning MIB Browser ($500+)
MIB Manager (upload/validate) Text editor + manual dependency hell

Stack: Python 3.11, FastAPI, pysnmp, pysmi, Bootstrap 5, Docker.

# Install in one command
curl -fsSL https://raw.githubusercontent.com/tosumitdhaka/trishul-snmp/main/install-trishul-snmp.sh | bash
Enter fullscreen mode Exit fullscreen mode

Then open http://localhost:8080. Default login: admin / admin123 — change it immediately in Settings.


What's New in v1.2.4

⚡ Real-Time WebSocket Push — Polling Is Dead

The biggest architectural change: the entire frontend is now event-driven.

Before: Every page polled the backend on a setInterval — dashboard every 30s, simulator every 5s. Stale data was common. Switching pages caused spinners.

After: A single persistent WebSocket connection at /api/ws. The backend broadcasts state changes the moment they happen. Dashboard, Simulator status, and Trap Receiver all update instantly — no refresh needed.

Browser ←──── WS push ────── FastAPI /api/ws
                                    │
                              broadcasts on:
                              - trap received
                              - simulator start/stop
                              - MIB uploaded
                              - stats change
Enter fullscreen mode Exit fullscreen mode

The navbar shows a live green dot when the WebSocket is healthy. On reconnect, the backend sends a full_state message to re-seed everything — so you never see stale data after a network hiccup.

Why this matters for devs: If you're building a trap handler and sending test traps from the UI, you now see the counter increment on the dashboard in real time. No F5 needed.


📊 Live Activity Stats Dashboard

A new 8-counter row on the dashboard shows everything happening in your session:

  • SNMP Requests — Total polls served by the simulator
  • OIDs Loaded — OIDs currently in memory across all loaded MIBs
  • Traps Received / Sent — Live trap counters
  • Walks Executed — How many SNMP walks you've run
  • OIDs Returned — Total OIDs returned across all walks
  • MIBs Uploaded / Times Reloaded — MIB management activity

All counters update via WebSocket push. They're also file-backed — they survive container restarts so you don't lose your session history.


⚙️ Settings — Three New Cards

App Behaviour

Two toggles: auto-start Simulator and auto-start Trap Receiver on container boot. Plus a configurable session timeout (60s–86400s). Settings persist to app_settings.json and take effect on next restart.

Stats Management

Export all counters as JSON (useful for logging test session results) or reset to zero for a clean baseline before a test run.

About

Version, author, and description pulled live from the backend — always in sync with what's actually deployed.


🐛 Notable Fixes

Timestamp bug: The Trap Receiver was showing 1970 for Last Received when the backend returned a Unix epoch 0. Now guarded and shown as --.

Traps Sent undercount: Stats were only incremented in the frontend — if you sent traps via API directly, the counter never moved. Fixed by broadcasting stats from the backend after every successful trap send.

Dashboard spinners on page switch: The WS full_state event fires before DashboardModule.init() registers its listener on page switch, so status tiles stayed as spinners until the next reconnect. Fixed by always seeding via REST on init, regardless of WS state.

MIB Browser state conflict: Navigating to the Browser from Walk & Parse (with a pre-filled OID) would sometimes log Could not find node because the previous session's pending tree state conflicted. Fixed by clearing pendingSelectedOid and pendingExpandedNodes when a programmatic OID search is present.


Who Is This For?

NMS / backend developers who need a real SNMP agent to poll without actual hardware, or need to fire specific trap OIDs to validate their handler code.

DevOps / integration engineers who need to test SNMP monitoring integrations in CI/staging environments.

Network engineers who want to explore MIB structures interactively — search by OID, by name, or by description — and understand what traps a device can fire before it's on the floor.

What It's NOT For

  • Production 24/7 monitoring → use Zabbix, LibreNMS, PRTG
  • Enterprise NMS → use SolarWinds, Cisco Prime
  • High-availability trap collection at scale → use dedicated platforms

Trishul is a developer and testing tool, not a production monitoring system.


Quick Architecture

Browser (8080)
    │ HTTP + WebSocket
    ▼
Nginx (static files + reverse proxy)
    │ REST + WS
    ▼
FastAPI Backend (8000)
    ├── MIB Service (parse, validate, search)
    ├── SNMP Simulator (UDP 1061)
    ├── Trap Manager (send + receive on UDP 1162)
    ├── Walker (SNMP walk client)
    └── WebSocket hub (/api/ws)
Enter fullscreen mode Exit fullscreen mode

Everything runs in Docker with host network mode so the SNMP UDP ports (1061, 1162) are accessible directly from your local machine or test devices.


Try It

# One-command install
curl -fsSL https://raw.githubusercontent.com/tosumitdhaka/trishul-snmp/main/install-trishul-snmp.sh | bash

# Access at
http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

If it's useful, a ⭐ on GitHub goes a long way — it helps other devs find the project.

Happy to answer questions in the comments about architecture decisions, the pysnmp/pysmi integration, or the WebSocket implementation. 🔱

Top comments (0)