Netdata, No Cloud: Local Parent/Child Streaming for a Homelab

You don’t need Netdata Cloud to get a single, local dashboard for multiple servers. This guide shows how I run a parent/collector on demoparent1.int.domain.com
, stream three+ child nodes (like demochild1.int.domain.com
) to it, keep the Web UI behind Nginx Proxy Manager at https://netdata.int.domain.com
, and set sane resource limits on the children.
We’ll keep apps and cgroups metrics on every host (useful when you run Docker), cap each child at 0.5 CPU and 512 MB RAM, and store long-term history on the parent with tiered retention.
What you get
- A local single-pane dashboard on your parent (no external SaaS).
- Each child uses minimal resources (0.5 CPU, 512 MB RAM, no local DB).
- Tiered retention on the parent:
- 1s resolution for 7 days
- 1m resolution for 1 month
- 1h resolution for 1 year
- Daily resolution for 3 years
Netdata’s built-in tiers are per-second, per-minute, per-hour, and then daily/weekly. A “2-hour” tier isn’t standard; daily is the efficient long-term tier. You can keep hourly for longer by allocating more disk to Tier 2, but daily is the recommended long tail. learn.netdata.cloud+1
Prereqs
- Ubuntu hosts with Docker Engine + Compose (v2+).
- Internal DNS for:
demoparent1.int.domain.com
→ parent host IPdemochildX.int.domain.com
→ child host IPsnetdata.int.domain.com
→ your Nginx Proxy Manager frontend for the Web UI only
Note: streaming is raw TCP to the parent, not HTTP through NPM. Keep the stream destination set todemoparent1.int.domain.com:19999
(or VPN/CF TCP tunnel if you’re crossing networks). learn.netdata.cloud+1
1) Parent / Collector on demoparent1.int.domain.com
Folder layout
mkdir
-p ~/netdata-parent/{config,lib,cache}cd
~/netdata-parentuuidgen # copy this API key; used by children and parent ACL
docker-compose.yml
(parent)
Bind mounts for easy backups and edits.
services:
]
netdata:
image: netdata/netdata:stable
container_name: netdata-parent
hostname: demoparent1.int.domain.com
network_mode: host
pid: host
cap_add: [ "SYS_PTRACE" security_opt: [ "apparmor:unconfined"
] environment:
- DO_NOT_TRACK=1
volumes:
- ./config:/etc/netdata
- ./lib:/var/lib/netdata
- ./cache:/var/cache/netdata
# Host introspection
- /etc/passwd:/host/etc/passwd:ro
- /etc/group:/host/etc/group:ro
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /etc/os-release:/host/etc/os-release:ro
# Container metrics on the parent
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
config/stream.conf
(parent)
The section name is the API key. Allow only your LAN while testing, then tighten.
[YOUR-UUID-API-KEY-HERE]
enabled = yes
allow from = 10.0.0.0/8 192.168.0.0/16
Netdata expects the literal UUID in brackets, not [API_KEY = …]
. Netdata Community Forums
config/netdata.conf
(parent)
Enable dbengine with 4 tiers and time-based retention. Netdata 1.46+ supports explicit retention time per tier; you can optionally add size caps per tier if you want to bound disk usage. learn.netdata.cloud
[global]
= netdata
run as user[db]
= dbengine
mode storage tiers = 4
d
# Tier 0: per-second
dbengine tier 0 retention time = 7 # Tier 1: per-minute
d
dbengine tier 1 retention time = 31 # Tier 2: per-hour
y
dbengine tier 2 retention time = 1 # Tier 3: daily (Netdata’s next built-in tier)
y
dbengine tier 3 retention time = 3 # Optional size caps (tune to your disk):
# dbengine tier 0 retention size = 8GiB
# dbengine tier 1 retention size = 16GiB
# dbengine tier 2 retention size = 32GiB
# dbengine tier 3 retention size = 16GiB
Start it:
docker compose up -d# UI: http://demoparent1.int.domain.com:19999 (or via NPM: https://netdata.int.domain.com)
Tip: You can see retention/time vs space charts under Netdata → dbengine retention on the dashboard to confirm your policy. learn.netdata.cloud
2) Children on demochild1.int.domain.com
(repeat per node)
Each child has no local DB, but still collects apps and cgroups for useful per-process and container stats. We cap the container at 0.5 CPU and 512 MB RAM.
Folder layout
mkdir
-p ~/netdata-child/{config,lib,cache}cd
~/netdata-child
docker-compose.yml
(child)
version: "3.8"
]
services:
netdata:
image: netdata/netdata:stable
container_name: netdata-child
hostname: ${HOSTNAME:-demochild1.int.domain.com}
network_mode: host
pid: host
cap_add: [ "SYS_PTRACE" security_opt: [ "apparmor:unconfined"
] # Resource limits: minimal but healthy for Docker hosts
cpus: "0.5"
mem_limit: 512m
pids_limit: 256
cpu_shares: 128
environment:
- DO_NOT_TRACK=1
volumes:
- ./config:/etc/netdata
- ./lib:/var/lib/netdata
- ./cache:/var/cache/netdata
- /etc/passwd:/host/etc/passwd:ro
- /etc/group:/host/etc/group:ro
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /etc/os-release:/host/etc/os-release:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
config/netdata.conf
(child)
Keep collectors you care about; disable local persistence.
[global]
# 1-second collection keeps high-res data flowing to the parent
update every = 1
[db]
mode = none # no local TSDB on children
[plugins]
cgroups = yes
apps = yes
# Optional: enable/disable others as needed (python.d, go.d, charts.d, etc.)
config/stream.conf
(child)
Stream directly to the parent, not the NPM hostname.
[stream]
= YOUR-UUID-API-KEY-HERE
enabled = yes
destination = demoparent1.int.domain.com:19999
api key sending compress = yes
timeout seconds = 60
Restart and check logs:
docker compose up -d
docker logs -f netdata-child

Parent-child streaming reference and exact keys/filenames are documented here. learn.netdata.cloud+1
3) Putting the Web UI behind Nginx Proxy Manager

Point netdata.int.domain.com
at your parent’s Netdata on :19999
. Leave the child→parent stream going to demoparent1.int.domain.com:19999
directly (LAN/VPN). If you must traverse the internet, prefer VPN or a Cloudflare TCP tunnel for the stream; the HTTP tunnel is for the Web UI only. learn.netdata.cloud
4) Sizing and retention notes

- With Netdata 1.46+ you can set time-based retention per tier (
dbengine tier N retention time = …
). You can also combine a time limit with a size cap per tier to prevent runaway disk usage. Start time-based, then add size caps once you see actual usage. learn.netdata.cloud - Tiers are fixed resolutions: per-second (T0), per-minute (T1), per-hour (T2), then daily/weekly. There isn’t a native 2-hour tier. To keep more hourly history, raise T2’s time and, if needed, size. For a very long tail, daily is far more storage-efficient. netdata.cloud+1
- More tiers = slightly more memory. Three or four tiers are typical. learn.netdata.cloud
5) Quick troubleshooting
- On the parent, verify it’s listening and showing stream info:curl -fsS http://127.0.0.1:19999/api/v1/stream/info | jq .
- If a child shows
403 denied
or the parent returns404
for stream info, check:- Parent
config/stream.conf
section header is the literal UUID. - Parent has your LAN in
allow from
. - Children use the parent’s real host/IP, not the NPM hostname. Netdata Community Forums
- Parent
Useful links
- Retention & tiers (time-based settings, tiers, cache): Netdata Database Configuration Reference. learn.netdata.cloud
- Long-term storage & multi-tier overview: Netdata blog: Long-Term Data Storage and Retention. netdata.cloud+1
- Parent/child streaming reference & examples: Learn Netdata. learn.netdata.cloud+1
- Cloudflare Tunnels for UI + TCP for streams: Netdata guide. learn.netdata.cloud
- Netdata Community Edition (Open Source): project page. netdata.cloud+1