- Go 89.3%
- Shell 9.4%
- Dockerfile 1.3%
| .forgejo/workflows | ||
| config | ||
| fetcher | ||
| influx | ||
| packaging | ||
| .env.example | ||
| .gitignore | ||
| .goreleaser.yml | ||
| Containerfile | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| README.md | ||
opnsense-netflow-otel
Polls OPNsense's NetworkInsight API (interface bandwidth + top talkers/ports) and writes the results to InfluxDB as time series.
How it works
Every POLL_INTERVAL_SECONDS the daemon:
- Fetches per-interface octets/packets from
FlowInterfaceTotalsand writes them to thenetflow_interfacemeasurement (tags:interface,direction; fields:octets,packets,bps). - Fetches the top
TOP_Nsource addresses fromFlowSourceAddrTotalsand writes a snapshot tonetflow_top_src_addr(tag:src_addr; field:octets). - Fetches the top
TOP_Ndestination ports fromFlowDstPortTotalsand writes a snapshot tonetflow_top_dst_port(tags:dst_port,label; field:octets).
Each poll queries a window twice as wide as the interval, so a missed or slow tick never leaves a gap — InfluxDB overwrites points with an identical timestamp + tag set, so the overlap is safe to re-send.
Environment variables
Copy .env.example to .env and fill in the values. .env is loaded
automatically on startup (real environment variables always take priority
over it).
| Variable | Required | Default | Description |
|---|---|---|---|
OPNSENSE_KEY |
yes | — | OPNsense API key (System > Access > Users > user > API keys). |
OPNSENSE_SECRET |
yes | — | OPNsense API secret paired with the key above. |
OPNSENSE_BASE_URL |
yes | — | Base URL of the OPNsense instance, e.g. https://opnsense.local. |
INFLUXDB_URL |
yes | — | InfluxDB 2.x server URL, e.g. http://localhost:8086. |
INFLUXDB_TOKEN |
yes | — | InfluxDB API token with write access to the target bucket. |
INFLUXDB_ORG |
yes | — | InfluxDB organization name. |
INFLUXDB_BUCKET |
yes | — | InfluxDB bucket to write points into. |
POLL_INTERVAL_SECONDS |
no | 30 |
How often to poll OPNsense and write to InfluxDB, in seconds. |
TOP_N |
no | 10 |
How many entries to keep in each top-talkers/top-ports snapshot. |
DEBUG |
no | — | Unused by the app; kept for parity with .env.example. |
The OPNsense NetworkInsight plugin (Reporting > Insight) must be enabled and have been collecting data for a while, otherwise the API returns empty results.
Running locally
1. Start a local InfluxDB 2.x
docker run -d --name netflow-influxdb -p 8086:8086 \
-e DOCKER_INFLUXDB_INIT_MODE=setup \
-e DOCKER_INFLUXDB_INIT_USERNAME=admin \
-e DOCKER_INFLUXDB_INIT_PASSWORD=adminadmin \
-e DOCKER_INFLUXDB_INIT_ORG=home \
-e DOCKER_INFLUXDB_INIT_BUCKET=netflow \
-e DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=devtoken123 \
influxdb:2
Check it's up:
curl http://localhost:8086/health
The UI is at http://localhost:8086 (login admin / adminadmin).
2. Configure .env
cp .env.example .env
Fill in OPNSENSE_KEY, OPNSENSE_SECRET, OPNSENSE_BASE_URL for your
OPNsense box, and set:
INFLUXDB_URL="http://localhost:8086"
INFLUXDB_TOKEN=devtoken123
INFLUXDB_ORG="home"
INFLUXDB_BUCKET="netflow"
(matching the container's org/bucket/token above).
3. Run the daemon
go run .
It logs each poll cycle and any fetch/write errors. Stop it with Ctrl+C.
4. Verify data is arriving
docker exec -it netflow-influxdb influx query \
--org home --token devtoken123 \
'from(bucket:"netflow") |> range(start: -10m) |> group(columns:["_measurement"]) |> count()'
You should see non-zero counts for netflow_interface, netflow_top_src_addr,
and netflow_top_dst_port. Or browse the Data Explorer in the InfluxDB UI.
5. Tear down
docker rm -f netflow-influxdb
Building a binary
go build -o opnsense-netflow-otel .
./opnsense-netflow-otel