NAME

nfsdiag — diagnose NFS from both sides of the wire.

SYNOPSIS

nfsdiag client [OPTIONS] <server-ip-or-hostname>
nfsdiag server [OPTIONS]
nfsdiag diff <before.json> <after.json>

DESCRIPTION

client tests an NFS server from a client machine. It walks the stack from the wire up: TCP reachability, rpcbind, NFS v2/v3/v4/v4.1/v4.2 probes, mountd, exports, mount cascade, permissions, root squash, ACLs, locking, stale handles, performance.

server runs on the NFS server itself and audits its configuration, starting with the exports file: syntax errors, exports without a client list, no_root_squash, insecure, world-writable wildcards.

Both modes share the report engine — compact text by default, JSON and standalone HTML when you need it — and the same exit codes. Safe by default: validated inputs, trusted helper execution, automatic mount namespace, O_NOFOLLOW reports, and opt-in dangerous probes.

Written in C99 against libtirpc. MIT. Current version: 0.22.0.

# two modes

NFS problems have two possible homes: the path between the machines, or the server's own configuration. nfsdiag covers both with one binary.

client runs on any machine that can reach the server · discovers and mounts the exports, then exercises them: reads, writes, locks, ACLs, identity simulation, benchmarks · answers "what does this server look like from where my users are?" · client documentation
server runs on the NFS server itself, no second machine involved · audits the configuration, starting with /etc/exports: syntax errors, missing client lists, no_root_squash, insecure · answers "is this server configured the way I think it is?" · server documentation

The server namespace runs on the NFS server itself and covers the whole checks — exports audit, security, live state, a Prometheus exporter, eBPF latency profiling, HA and nfs-ganesha checks — up to paired mode, correlating a client run and a server run to tell which side of the wire the problem is on.

# install

# Debian / Ubuntu
sudo apt-get install -y \
  build-essential \
  pkg-config \
  libtirpc-dev \
  nfs-common

git clone https://github.com/lsferreira42/nfsdiag
cd nfsdiag && make
sudo make install
# Fedora / RHEL
sudo dnf install -y \
  gcc make \
  pkgconf-pkg-config \
  libtirpc-devel \
  nfs-utils

git clone https://github.com/lsferreira42/nfsdiag
cd nfsdiag && make
sudo make install
# OCI image — no build required
docker run --rm --privileged \
  ghcr.io/lsferreira42/nfsdiag \
  client 192.168.1.10

Pre-built binaries (amd64 & arm64), .deb, .rpm, and .apk on the latest GitHub release ↗. Releases also include checksums, SBOM, provenance, and an OCI image. Packaging templates for Homebrew, AUR, Nix, Docker, DEB, RPM and APK live under packaging/.

# what it checks

network rpcbind tcp/111 · NFS tcp/2049 · IPv4/IPv6 with fallback · optional UDP probe
rpc service map from rpcbind · mountd v1/v2/v3 · NFS v2/v3/v4/v4.1/v4.2 NULLPROC probes · lockd/NLM · statd/NSM
mount v4.2 → v4.1 → v4 → v3 cascade · effective options parsed from /proc/self/mountinfo
fs close-to-open consistency · read · write · fsync · directory listing · copy_file_range · fallocate · O_DIRECT
acl POSIX ACLs · NFSv4 ACLs · generic xattrs · SELinux contexts
perm UID/GID/supplemental groups simulation · practical root_squash detection
lock fcntl advisory locks · NLM · NSM
perf throughput smoke test · metadata latency · external fio backend · deep metrics from /proc/self/mountstats
stale ESTALE loop · pNFS layouts · NFSoRDMA hints
filenames 255-byte names · spaces · colons · UTF-8 multibyte · per-rejection errno
delegation NFSv4 delegation activity via /proc/self/mountstats (DELEGRETURN operations)
report tagged text · UTF-8 table · NDJSON · Prometheus · JSON · HTML · evidence bundle · stable check IDs · remediation text

# usage

client: full diagnostic — needs root for mount

sudo nfsdiag client 192.168.1.10

client: network and RPC only — no mount, no root

nfsdiag client --no-mount 192.168.1.10

simulate a specific identity (UID/GID + groups)

sudo nfsdiag client --uid 1000 --gid 1000 --groups 10,20 192.168.1.10

machine-readable report for CI / scripts

nfsdiag client --json=report.json 192.168.1.10

production audit — read-only, dry run, rate-limited

nfsdiag client --dry-run --read-only --delay-ms 500 prod-nfs.example.com

shareable HTML for a support ticket

sudo nfsdiag client --html=report.html 192.168.1.10

continuous monitoring — re-run every 60 s

sudo nfsdiag client --watch 60 192.168.1.10

stream failures with jq

sudo nfsdiag client --output-format=ndjson \
  192.168.1.10 | jq 'select(.level=="fail")'

safe preset — read-only diagnostics

sudo nfsdiag client --profile safe 192.168.1.10

evidence bundle for tickets

sudo nfsdiag client --output-dir ./nfsdiag-report 192.168.1.10

server: audit /etc/exports on the NFS server

sudo nfsdiag server --exports-audit

server: audit a staged exports file before applying

nfsdiag server --exports-audit --exports-file /tmp/exports.new

compare before / after reports

nfsdiag diff before.json after.json

audit a fleet from a hosts file

sudo nfsdiag client \
  --hosts-file /etc/nfs-servers.txt \
  --json=audit.json

Full CLI reference with all flags, defaults, and advanced recipes in the documentation.

# documentation

The documentation is split by namespace. The client reference covers every CLI flag, all 14 Docker test fixtures, all output formats (text, table, NDJSON, Prometheus, JSON, HTML), evidence bundles, report diffing, packaging (deb/rpm/apk/OCI/Homebrew/AUR/Nix), security notes, architecture, limitations, and the changelog. The server reference covers the server-side checks.

→ client documentation
→ server documentation