Run ncdu against TrueNAS SCALE datasets from a small Docker container https://hub.docker.com/r/joanmarcriera/truenas-ncdu
  • Shell 85.3%
  • Makefile 8.3%
  • Dockerfile 6.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-05-12 12:24:30 +01:00
.github/workflows Make Docker publish workflow manual 2026-05-11 20:50:42 +01:00
docs Document Time Machine ZFS snapshot scans 2026-05-12 12:24:30 +01:00
examples Document Time Machine ZFS snapshot scans 2026-05-12 12:24:30 +01:00
scripts Start web mode by default 2026-05-11 21:05:18 +01:00
tests Document Time Machine ZFS snapshot scans 2026-05-12 12:24:30 +01:00
.dockerignore Initial TrueNAS ncdu container repo 2026-05-11 19:55:10 +01:00
.gitignore Initial TrueNAS ncdu container repo 2026-05-11 19:55:10 +01:00
CONTRIBUTING.md Initial TrueNAS ncdu container repo 2026-05-11 19:55:10 +01:00
Dockerfile Document Time Machine ZFS snapshot scans 2026-05-12 12:24:30 +01:00
entrypoint.sh Document Time Machine ZFS snapshot scans 2026-05-12 12:24:30 +01:00
LICENSE Initial TrueNAS ncdu container repo 2026-05-11 19:55:10 +01:00
Makefile Start web mode by default 2026-05-11 21:05:18 +01:00
README.md Document Time Machine ZFS snapshot scans 2026-05-12 12:24:30 +01:00
SECURITY.md Initial TrueNAS ncdu container repo 2026-05-11 19:55:10 +01:00

truenas-ncdu

Run ncdu against TrueNAS SCALE datasets from a small container.

TrueNAS SCALE does not ship ncdu on the host appliance. This repository packages ncdu in a container so you can inspect dataset usage without installing packages on TrueNAS itself.

What This Provides

  • Alpine-based container with ncdu and tini.
  • Safe default scan path: /mnt.
  • ncdu -x enabled by default to avoid crossing filesystem boundaries.
  • .zfs snapshot directories excluded by default so ZFS snapshots do not inflate normal folder totals.
  • Browser terminal mode through ttyd, backed by a persistent tmux session.
  • Read-only mount examples for TrueNAS datasets.
  • GitHub Actions CI and Docker Hub publishing workflow.
  • TrueNAS SCALE direct Docker and Custom App/YAML instructions.

Quick Use

Run this from a TrueNAS SCALE shell:

docker run --rm -it \
  --network none \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  -v /mnt:/mnt:ro \
  docker.io/joanmarcriera/truenas-ncdu:latest \
  /mnt

Scan one dataset:

docker run --rm -it \
  --network none \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  -v /mnt:/mnt:ro \
  docker.io/joanmarcriera/truenas-ncdu:latest \
  /mnt/tank/media

The /mnt host mount is read-only, so this mode is for inspection rather than deletion.

Build Locally

make build
make run SCAN_PATH=/mnt

Or without make:

docker build -t truenas-ncdu:dev .
docker run --rm -it -v /mnt:/mnt:ro truenas-ncdu:dev

TrueNAS SCALE Web App Setup

Use this path when you want ncdu available in a browser as a TrueNAS app. The container starts a detached tmux session running ncdu, then serves that TUI through ttyd on port 7681.

In the TrueNAS SCALE web UI:

  1. Open Apps.
  2. Click Discover Apps.
  3. Click Custom App.
  4. Set Application Name to truenas-ncdu.
  5. In Image Configuration, set:
Repository: joanmarcriera/truenas-ncdu
Tag: 0.2.2
Pull Policy: Always pull an image even if it is present on the host
  1. In Container Configuration, leave Entrypoint empty and leave Command empty.

The image defaults to web mode, so the browser terminal server starts when the app boots.

  1. Set:
Restart Policy: Unless Stopped

TTY and Stdin are not required for web mode.

  1. Add environment variables. Choose your own TTYD_PASSWORD before saving the app:
NCDU_PATH=/mnt/BigDisk
NCDU_ONE_FILESYSTEM=true
NCDU_EXCLUDE_ZFS=true
TTYD_USER=admin
TTYD_PASSWORD=<choose-a-password>

Change NCDU_PATH if you mount a different dataset path. Keep NCDU_EXCLUDE_ZFS=true for normal scans; set it to false only when you deliberately want to inspect ZFS snapshot contents under .zfs/snapshot.

  1. In Network Configuration, add a TCP port:
Container Port: 7681
Host Port: 7681
Protocol: TCP

If host port 7681 is already in use, choose another host port and keep the container port as 7681.

  1. Optional: in Portal Configuration, add an HTTP portal pointing at host port 7681.
  2. In Storage Configuration, click Add and choose Host Path.
  3. Select only the dataset or pool path you want ncdu to read. For the BigDisk scenario:
Type: Host Path
Host Path: /mnt/BigDisk
Mount Path: /mnt/BigDisk
Read Only: enabled

Use read-only mounts for normal inspection. If you want to scan multiple datasets, add one Host Path entry per dataset, or mount /mnt to /mnt read-only if you deliberately want broad visibility.

  1. Save the app.
  2. Open the browser terminal:
http://<truenas-ip>:7681

Log in with TTYD_USER and TTYD_PASSWORD. The browser attaches to the running ncdu TUI. To restart the scan from inside the browser terminal, press q to quit ncdu, then run:

truenas-ncdu

If the app shell shows permission errors, check the dataset ACL for the mounted path and make sure the app user can read and traverse the dataset. The mount should still stay read-only unless you intentionally want delete support from inside ncdu.

TrueNAS YAML for BigDisk

TrueNAS also supports installing custom apps from YAML. Go to Apps > Discover Apps, open the menu at the top right, choose Install via YAML, name the app truenas-ncdu, and paste this Compose YAML:

services:
  truenas-ncdu:
    image: docker.io/joanmarcriera/truenas-ncdu:0.2.2
    container_name: truenas-ncdu
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=64m
    environment:
      NCDU_PATH: /mnt/BigDisk
      NCDU_ONE_FILESYSTEM: "true"
      NCDU_EXCLUDE_ZFS: "true"
      TTYD_USER: admin
      TTYD_PASSWORD: change-this-password
    ports:
      - "7681:7681"
    volumes:
      - type: bind
        source: /mnt/BigDisk
        target: /mnt/BigDisk
        read_only: true

This same YAML is available at examples/compose.bigdisk.yaml. The generic /mnt example remains at examples/compose.truenas.yaml.

After the app starts, open http://<truenas-ip>:7681 and log in with admin plus the password you configured.

See docs/truenas-scale.md for extra TrueNAS notes, including permissions and interactive terminal trade-offs.

If Time Machine or other ZFS-backed datasets look impossibly large, see docs/time-machine-zfs-snapshots.md. The usual cause is ncdu counting visible .zfs/snapshot trees, not live files.

Publish to Docker Hub

The repository includes .github/workflows/docker-publish.yml.

Add this GitHub repository secret:

  • DOCKERHUB_TOKEN

Then run the workflow manually. To tag a release in git:

git tag v0.1.0
git push origin v0.1.0

More detail is in docs/dockerhub-publish.md.

Container Interface

truenas-ncdu [SCAN_PATH] [NCDU_OPTIONS...]

Environment variables:

  • NCDU_PATH: default scan path. Defaults to /mnt.
  • NCDU_ONE_FILESYSTEM: true or false. Defaults to true.
  • NCDU_EXCLUDE_ZFS: true or false. Defaults to true; excludes .zfs snapshot directories.
  • NCDU_BIN: override the binary, mainly for tests.

Examples:

docker run --rm -it -v /mnt:/mnt:ro docker.io/joanmarcriera/truenas-ncdu:latest /mnt/tank/media
docker run --rm -it -v /mnt:/mnt:ro -e NCDU_ONE_FILESYSTEM=false docker.io/joanmarcriera/truenas-ncdu:latest /mnt
docker run --rm -it -v /mnt:/mnt:ro -e NCDU_EXCLUDE_ZFS=false docker.io/joanmarcriera/truenas-ncdu:latest /mnt/tank/media
docker run --rm -it -v /mnt:/mnt:ro docker.io/joanmarcriera/truenas-ncdu:latest sh
docker run --rm docker.io/joanmarcriera/truenas-ncdu:latest --version
docker run --rm -p 7681:7681 -v /mnt:/mnt:ro -e TTYD_PASSWORD=change-me docker.io/joanmarcriera/truenas-ncdu:latest

Development

sh scripts/test.sh

The tests cover the shell entrypoint and build the Docker image when Docker is available.

References