Home / LibreNMS Integration

Integrating NetLens with LibreNMS

Share the NetLens (NfSen) data folders over NFS so a LibreNMS server on a different machine can show NetFlow graphs and Top-N statistics.

Works with: NetLens (Dockerized NfSen 1.3.6p1 + NfDump 1.6.17) on one VPS, LibreNMS installed manually on a second Ubuntu server. Tested and verified with LibreNMS on Ubuntu 24.04.

1. Overview

LibreNMS has a built-in Netflow tab. It needs three things from NfSen:

  1. RRD graph files — read via config nfsen_rrds (profiles-stat/live/<source>.rrd) — the channel graphs.
  2. Raw flow files — read via the nfdump binary, which LibreNMS runs on its own server: nfdump -M <base>/profiles-data/live/<source> -T -R <range> -n N -s .... It must be able to see profiles-data/live/... and have nfdump installed. This produces the Top-N statistics.
  3. Matching names — the NfSen source (ident) must map to the LibreNMS device hostname (section 6).

When LibreNMS runs on a different machine (your case), the cleanest way to give it items 1 and 2 is an NFS read-only share of the two data folders.

TL;DR — the 30-second version:
  1. NfSen (Docker) stays on the VPS and keeps writing to its local folders — we never let another writer touch the live data.
  2. Share only two folders over NFS, read-only: nfsen-data/ (raw flow files) and nfsen-stat/ (RRD graphs).
  3. Install nfdump 1.6.25 on the LibreNMS server to match the container's v1.6 file format (see section 5 for why not 1.7.3 or 1.6.17).
  4. Tell LibreNMS where the data is (lnms config:set) — the Netflow tab appears on every device page.
  5. Never run two NfSen instances writing to the same shared folder. Ever.

2. Architecture

   Your VPS (Docker NetLens)                  LibreNMS server
   ---------------------------                -----------------
   docker-compose.yml                          LibreNMS web UI
   |-- nfsen-data/  = profiles-data --NFS(ro)-->  /var/nfsen/profiles-data
   |-- nfsen-stat/  = profiles-stat --NFS(ro)-->  /var/nfsen/profiles-stat
   |-- nfsen-var/   = logs (NOT shared)
   `-- nfsen-etc/   = config (NOT shared - contains .htpasswd!)

   NfSen writes here          |        LibreNMS READS here (never writes)
   (one writer only)          |        nfdump (1.6.25) reads the flow files
                              v        RRD files render the channel graphs
Rule: NFS share = READ-ONLY for the LibreNMS server. NfSen never reads back from it. This is the "one writer" rule — it can never corrupt data.

3. NFS server setup (on the VPS running NetLens)

Step 1 — Install the NFS server

sudo apt update
sudo apt install -y nfs-kernel-server

Step 2 — Find your project path

cd /path/to/netlens      # where nfsen-data/ and nfsen-stat/ live (e.g. /root/netlens)
pwd                      # remember this as <VPS_PROJECT_PATH>

Step 3 — Add the exports

Edit /etc/exports and add (replace the IP and path):

<VPS_PROJECT_PATH>/nfsen-data  <LibreNMS_IP>/32(ro,sync,no_subtree_check)
<VPS_PROJECT_PATH>/nfsen-stat  <LibreNMS_IP>/32(ro,sync,no_subtree_check)

Example (LibreNMS server = 192.168.1.50, project in /root/netlens):

/root/netlens/nfsen-data  192.168.1.50/32(ro,sync,no_subtree_check)
/root/netlens/nfsen-stat  192.168.1.50/32(ro,sync,no_subtree_check)
  • ro = read-only (recommended; the LibreNMS server only needs to read).
  • We deliberately do not export nfsen-var/ or nfsen-etc/nfsen-etc contains .htpasswd (your Web UI password hashes).
  • If you ever want NfSen to write onto the share instead (alternative pattern, section 11), change to rw + no_root_squash then. Not now.

Step 4 — Activate and verify

sudo exportfs -rav
sudo systemctl enable --now nfs-server
sudo showmount -e localhost        # you should see the 2 exports

Step 5 — Firewall (cloud VPS + ufw)

Allow NFS from the LibreNMS IP:

sudo ufw allow from 103.159.37.199 to any port 111 proto tcp
sudo ufw allow from 103.159.37.199 to any port 2049 proto tcp
sudo ufw allow from 103.159.37.199 to any port 111 proto udp
sudo ufw allow from 103.159.37.199 to any port 2049 proto udp
On some cloud providers NFS also uses the rpcbind range 20048+ etc. If mounting fails, temporarily disable ufw to test, then open the ports the error mentions.

4. NFS client setup (on the LibreNMS server)

Step 1 — Install the NFS client

sudo apt update
sudo apt install -y nfs-common

Step 2 — Create the mount points

Important: use the same paths LibreNMS expects, so no symlinks are needed:

sudo mkdir -p /var/nfsen/profiles-data /var/nfsen/profiles-stat

Step 3 — Mount (replace <VPS_IP> and the project path)

sudo mount -t nfs4 <VPS_IP>:<VPS_PROJECT_PATH>/nfsen-data /var/nfsen/profiles-data
sudo mount -t nfs4 <VPS_IP>:<VPS_PROJECT_PATH>/nfsen-stat /var/nfsen/profiles-stat

Example:

sudo mount -t nfs4 103.187.23.163:/root/netlens/nfsen-data /var/nfsen/profiles-data
sudo mount -t nfs4 103.187.23.163:/root/netlens/nfsen-stat /var/nfsen/profiles-stat

Step 4 — Make it permanent (/etc/fstab)

Append these two lines (each has exactly 6 fields: device, mountpoint, fstype, options, dump, pass):

<VPS_IP>:<VPS_PROJECT_PATH>/nfsen-data  /var/nfsen/profiles-data  nfs4  ro,soft,timeo=50,retrans=2,_netdev 0 0
<VPS_IP>:<VPS_PROJECT_PATH>/nfsen-stat  /var/nfsen/profiles-stat  nfs4  ro,soft,timeo=50,retrans=2,_netdev 0 0

(ro + soft = safe for a monitoring box: if NFS hiccups, LibreNMS just shows "no data" instead of hanging forever. _netdev tells systemd to wait for the network before mounting at boot.)

Gotchas (all bit us in production):
  • Write only the two fstab lines above. Do not paste the sudo mount commands from Step 3 into /etc/fstab — boot then fails with "/etc/fstab: parse error" and the shares never come back.
  • Check the file is clean: sudo cat -A /etc/fstab (each line must end with just $ — no ^M/CRLF if you pasted from Windows).
  • After a reboot the mounts must be there with plain df -h | grep nfsen. If they are gone, run sudo mount -a (should be silent) and re-check fstab.

Step 5 — Verify you can see the data

ls /var/nfsen/profiles-data/live/        # should list your sources, e.g. router1
ls /var/nfsen/profiles-stat/live/        # should list .rrd files

5. Install nfdump on the LibreNMS server (important version rule)

LibreNMS runs nfdump against your flow files. The file format must match the container's nfdump, otherwise LibreNMS cannot read anything:

  • Your Docker container uses nfdump 1.6.17 (raw flow file format v1.6.x).
  • nfdump 1.7+ writes/reads a NEW binary format — it cannot read 1.6.17 files.
  • Your LibreNMS is Ubuntu 24.04: the default package there is nfdump 1.7.3 = WRONG. Do not use it.
  • Ubuntu 20.04's apt package is nfdump 1.6.17 = perfect match (only relevant if you ever run LibreNMS on 20.04).
Important — do not use 1.6.17 on 24.04. Its argument/range parsing has a stack buffer overflow that Ubuntu 24.04's newer glibc/GCC catches at runtime: nfdump -M ... -R . dies with "*** buffer overflow detected ***". 1.6.25 is the last release of the 1.6.x tree — same v1.6 file format as the container's 1.6.17, but with years of bug fixes. Build it from source:

Step 1 — Install the build dependencies

sudo apt update
sudo apt install -y build-essential autoconf automake libtool pkg-config \
  flex bison byacc libpcap-dev libbz2-dev

Step 2 — Download and extract the 1.6.25 source

cd /tmp
wget https://github.com/phaag/nfdump/archive/v1.6.25.tar.gz
tar xzf v1.6.25.tar.gz
cd nfdump-1.6.25

Step 3 — Build and install (same configure family the Dockerfile uses)

sh ./autogen.sh
./configure --prefix=/usr/local
make -j"$(nproc)"
sudo make install
sudo ldconfig

Step 4 — Verify the version

/usr/local/bin/nfdump -V     # must show: Version: 1.6.25

(Ignore any /usr/bin/nfdump 1.7.3 that apt left behind — LibreNMS will be pointed at /usr/local/bin/nfdump, section 6.)

Step 5 — Quick read test (should print flow stats, not an error)

/usr/local/bin/nfdump -M /var/nfsen/profiles-data/live/router1 -R . -s record/flows | tail -5
  • The -M argument is the full path to the source directory (<base>/profiles-data/live/<source>).
  • -R selects the time range. . = all files. Without -R, nfdump refuses with: "-M needs either -r or -R to specify the file or file list."
  • -R . reads every file since the beginning — on a busy profile that takes minutes (18M flows took ~40 s in testing). It is not stuck. For a fast check use a file range instead: /usr/local/bin/nfdump -M /var/nfsen/profiles-data/live/<source> -R 'nfcapd.202608151945:nfcapd.202608151950' -s record/flows | tail -5
  • Never pass a directory path to -R — nfdump 1.6.x tries to parse it as a time range and crashes with "*** buffer overflow detected ***".
  • If it says Can't open ... permission denied, fix per section 9.

6. Configure LibreNMS

Step 1 — Run these as the librenms user (or with sudo -u librenms)

lnms config:set nfsen_enable true
lnms config:set nfsen_split_char '_'
lnms config:set nfsen_base.+ '/var/nfsen/'
lnms config:set nfsen_rrds.+ '/var/nfsen/profiles-stat/live/'
lnms config:set nfsen_rrds.+ '/var/nfsen/profiles-stat'
lnms config:set nfdump /usr/local/bin/nfdump   # the 1.6.25 we built (NOT /usr/bin/nfdump = 1.7.3)
lnms config:set nfsen_subdirlayout 0   # IMPORTANT: this NfSen stores flow files FLAT
                                         # (nfcapd.YYYYMMDDHHMM, no subdirs - its nfsen.conf
                                         # has no $SUBdirlayout). Without 0, LibreNMS looks
                                         # for files in YYYY/MM/DD/ subdirs and finds nothing.
lnms config:set nfsen_suffix '_none'   # REQUIRED, never leave empty: LibreNMS runs
                                         # preg_replace('/' . nfsen_suffix . '/', ...) and an
                                         # empty suffix = empty regex = NULL = the RRD check
                                         # always fails = Netflow tab never appears. Use any
                                         # string that never occurs in device hostnames.
If your device hostnames include your domain, use the real domain suffix instead of _none (the LibreNMS docs' trick): lnms config:set nfsen_suffix '_yourdomain_com'. Whatever you choose, the value must be non-empty — empty = no Netflow tab.

Step 2 — Find the tab

Open LibreNMS → Devices → click the device → Netflow tab at the end of the tab bar under the device header (scroll it sideways if it wraps). Quick test: open http://<librenms>/device/device=<id>/tab=netflow/.

Step 3 — Tab missing?

Work through section 8. The three usual causes: nfsen_enable not true, nfsen_suffix empty, or the RRD file name not matching the device's actual hostname (section 7).

Step 4 — What you should see

Stats (Top N) use nfdump → your NFS data. Graphs use the RRDs. Note: the General view can look empty (it looks for per-channel subfolders this NfSen doesn't create) — the Stats view is the one with your flow data.

Tuning knobs (optional, all documented in LibreNMS):

lnms config:set nfsen_last_default 900
lnms config:set nfsen_top_default 20
lnms config:set nfsen_stats_default srcip
lnms config:set nfsen_order_default packets
lnms config:set nfsen_last_max 153600      # max seconds for stats

7. Matching NfSen sources to LibreNMS devices (the common gotcha)

LibreNMS finds a device's flow data by name. The NfSen source (ident) name becomes the RRD filename and the directory name under profiles-data/live/.

  • The NfSen ident must match the LibreNMS device hostname, but: NfSen idents are limited to 21 characters, and dots (.) are replaced by nfsen_split_char (we set _).
  • Example: LibreNMS device hostname core-router.example.com (longer than 21) → NfSen source ident core_router_example_com (dots → _, short). With nfsen_split_char '_' set, LibreNMS looks for the RRD named after the transformed hostname.

Devices added by IP — use symlinks

If your device is added by IP in LibreNMS: create symbolic links so the IP-based names resolve to the real source. You need two — one for the RRD graphs and one for the raw flow data (nfdump stats use it too).

Important: the NFS exports are read-only (ro), so you cannot create symlinks on the LibreNMS server — the mount rejects writes. Create them on the VPS instead (inside the project folders, next to docker-compose.yml — they show up on the LibreNMS side through NFS):
# on the VPS (NfSen host), inside the project folder:
cd /path/to/netlens/nfsen-stat/live
sudo ln -s router1.rrd 192_168_1_50.rrd     # <deviceIP with _ >.rrd

cd /path/to/netlens/nfsen-data/live
sudo ln -s router1 192_168_1_50             # data dir for nfdump stats

(Replace router1 with the real source that collects that router's traffic, and 192_168_1_50 with the LibreNMS device hostname/IP with . replaced by nfsen_split_char, i.e. _.)

Use the device's actual hostname as LibreNMS stores it (see the Devices list, or the poll log lines like "device:poll 192.168.1.50"). A symlink with the wrong name means the Netflow tab never appears — the name must match exactly, e.g. a device polled as 103.187.22.1 needs 103_187_22_1.rrd.

On the NfSen side, when you add a real source in nfsen.conf, name it to match (see the project README for adding sources):

'core_router_example_com' => { 'port' => '2070', 'col' => '#FF0000', 'type' => 'netflow' },

8. Verification checklist

On the VPS (NetLens/NfSen):

sudo showmount -e localhost
ls -la nfsen-data/live/ nfsen-stat/live/

On the LibreNMS server:

df -h | grep nfsen                    # mounts are up
ls /var/nfsen/profiles-data/live/     # sources + any IP symlinks
ls /var/nfsen/profiles-stat/live/     # .rrd files + any IP symlinks
/usr/local/bin/nfdump -V              # must be 1.6.25
/usr/local/bin/nfdump -M /var/nfsen/profiles-data/live/<source> -R 'nfcapd.<file1>:nfcapd.<file2>' -s record/flows | tail -5
lnms config:get nfsen_enable          # must be true
lnms config:get nfsen_suffix          # must NOT be empty
lnms config:get nfsen_subdirlayout    # must be 0 (flat file layout)
lnms config:get nfsen_rrds            # must list the profiles-stat paths
sudo -u librenms ./validate.php        # LibreNMS self-check (in its install dir)

In the browser: Device page → tab bar (at the end of it) → Netflow → Stats view shows Top-N. Direct URL test: http://<librenms>/device/device=<id>/tab=netflow/

If the tab is missing: run sudo tail -n 50 /opt/librenms/logs/librenms.log and check, in order: nfsen_enable true? nfsen_suffix non-empty? RRD file name matches the device's real hostname (section 7)? The tab only appears when all three are true.

9. Permissions & ownership (the uid story)

Inside the container the users are:

  • netflow = uid 1000 (owns profiles-data/live — writes flow files)
  • www-data = uid 33 (owns profiles-stat — writes RRDs)

Over NFS, uid 33 and uid 1000 are just numbers. Your live directories are chmod 775 with netflow:www-data ownership, so any local user (including www-data/root, which is how LibreNMS runs nfdump) can read them. That is why a read-only export works with no special uid mapping.

If you ever see "Permission denied":

  1. Check perms on the VPS: ls -la nfsen-data/live/ (expect drwxrwxr-x)
  2. Check the export flags: cat /etc/exports (ro is fine for reading)
  3. On some setups the export needs: rw,sync,no_root_squash (only needed if NfSen itself must write to the share — section 11)

10. Danger zone — things that WILL break your data

X Running two NfSen instances that write to the same live folder over NFS. NfSen uses SysV semaphores which exist per-host — the two instances cannot coordinate, so they corrupt each other's 5-minute files.
X Exporting nfsen-etc/ — it contains .htpasswd (Web UI password hashes).
X Exporting nfsen-var/ — unnecessary (logs, runtime).
X Using the default Ubuntu 24.04 nfdump package (1.7.3) on the LibreNMS host — new file format, cannot read the 1.6.17 files. Build 1.6.25 from source (section 5) and point LibreNMS at /usr/local/bin/nfdump.
X Leaving nfsen_suffix EMPTY in LibreNMS — the tab's RRD check builds an empty regex and silently fails, so the Netflow tab never appears.
X Pasting the sudo mount commands into /etc/fstab instead of the proper 6-field lines — boot fails to mount the shares ("parse error").
X A slow/unreliable network as the WRITE target for NfSen — dropped NFS = stuck nfcapd writes. For the recommended read-only setup this is a non-issue.

11. Alternative pattern (only if you change your mind later)

Pattern B — NFS as the primary storage for the NfSen data (single writer):

  • Mount the NFS share on the VPS under the project (e.g. replace the nfsen-data/ folder with an NFS mount to a NAS).
  • Docker keeps working unchanged (it's still a bind mount).
  • Requirements: export rw,sync,no_root_squash (the entrypoint runs chown/chmod as root), the NFS server must be reliable, and the mount must be up before docker compose up.
  • Pros: data survives VPS loss; easy to point multiple read-only consumers (LibreNMS) at the same NAS.
  • Cons: single point of failure (the NAS) + NFS dependency at boot.
For your current goal (LibreNMS on another server), pattern A (read-only export) is the right choice — no reason to move NfSen's primary storage.

12. Summary

  • Goal: LibreNMS (separate server) shows NetFlow graphs + top-N stats from the Dockerized NfSen.
  • How: NFS share the two data folders (nfsen-data = raw flows, nfsen-stat = RRD graphs) read-only from the NetLens VPS to the LibreNMS server. NfSen keeps writing locally (one writer rule — never two NfSen instances on the same live data).
  • On the LibreNMS server: install nfs-common, mount the shares at /var/nfsen/profiles-data and /var/nfsen/profiles-stat, and install nfdump 1.6.25 (last of the 1.6.x tree) to match the container's v1.6 file format — on Ubuntu 24.04 build it from source, do not use 1.6.17 (its range parsing crashes with "buffer overflow detected" on 24.04's toolchain). Then enable the integration with lnms config:set nfsen_enable true (+ paths + nfdump → /usr/local/bin/nfdump).
  • NfSen source names must match LibreNMS device hostnames (21-char limit, dots → _); for devices added by IP create two symlinks on the VPS (RRD .rrd + data dir) named after the device's real hostname (check the poll log, e.g. 103.187.22.1103_187_22_1.rrd). The mount is read-only, so the symlinks must be created VPS-side.
  • LibreNMS config that must be right: nfsen_enable true, nfsen_suffix non-empty (empty = no tab), nfsen_subdirlayout 0 (this NfSen stores flat nfcapd files), nfsen_rrds pointing at profiles-stat.
  • fstab entries need _netdev and must be proper 6-field lines — pasting the sudo mount commands into fstab breaks boot mounting.
  • Never export nfsen-etc (contains .htpasswd) or nfsen-var.
Verified against LibreNMS docs (docs.librenms.org/Extensions/NFSen/) and LibreNMS master source (nfdump -M <base>/profiles-data/live/<source>).