Most monitoring tools sample every 10 or 30 seconds. That's fine for a graph you check once a day, but useless when you're staring at a server that spiked, thrashed, and recovered inside a five-second window. By the time the next scrape lands, the evidence is gone.
Netdata collects everything per second and renders it live in the browser with essentially zero configuration. Install it and within a minute you have hundreds of charts - CPU per core, disk I/O per device, every network interface, memory, running services, Docker containers, and any database or web server it detects - all updating in real time. It's the closest thing to htop for your whole machine, with history and alerts bolted on.
The catch is that Netdata's dashboard listens on 0.0.0.0:19999 out of the box. That's a public, unauthenticated window into your server, and it needs to be closed before you do anything else. This guide installs Netdata, locks the dashboard down properly, tunes it so it doesn't eat a small VPS alive, wires up alerts, and streams several servers into one place.
127.0.0.1 so it's not exposed to the internetTotal time: around 20 minutes.
80 and 443 open (Let's Encrypt needs them)Netdata is heavier than a hub-and-agent tool like Beszel - it collects far more, far faster. On a 1 GB box it's comfortable once tuned. On 512 MB it works but you'll want to trim collectors aggressively.
The official kickstart script detects your distro, adds the repository, installs the native package, and starts the service. It's the recommended path and handles updates cleanly:
wget -O /tmp/netdata-kickstart.sh https://get.netdata.cloud/kickstart.sh
sh /tmp/netdata-kickstart.sh --stable-channel --disable-telemetry
The --stable-channel flag pins you to stable releases instead of nightlies, and --disable-telemetry opts out of anonymous usage statistics. The installer asks nothing else once those flags are set.
When it finishes, confirm the service is up:
sudo systemctl status netdata
At this point Netdata is already collecting. If your firewall allowed it, http://YOUR_VPS_IP:19999 would show the full dashboard right now - which is exactly the problem we fix next.
19999 open to the internet. The default dashboard has no authentication and exposes detailed system internals - running processes, open ports, mounted filesystems, and more - to anyone who finds it. Close it before you do anything else.
Netdata ships an edit-config helper that copies the stock config into place before you edit it, so you never lose the defaults. Open the main config:
cd /etc/netdata
sudo ./edit-config netdata.conf
Find the [web] section (or add it) and set the bind address to loopback only:
[web]
bind to = 127.0.0.1
default port = 19999
Save and restart:
sudo systemctl restart netdata
Now the dashboard only answers on the machine itself. If UFW is your firewall, make sure 19999 is not open, and lock it down to the essentials:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Verify Netdata is no longer listening on the public interface:
sudo ss -tlnp | grep 19999
You should see 127.0.0.1:19999, not 0.0.0.0:19999.
To reach the dashboard from a browser with HTTPS, put Caddy in front of it. First point a subdomain at your VPS. In your DNS provider, add an A record (and AAAA if you use IPv6):
netdata.example.com → YOUR_VPS_IPV4
Install Caddy from its official repository:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy
Generate a bcrypt hash for the password you want to protect the dashboard with:
caddy hash-password --plaintext 'your-strong-password-here'
Copy the resulting hash. Then edit /etc/caddy/Caddyfile:
netdata.example.com {
encode zstd gzip
basic_auth {
admin <paste-the-bcrypt-hash-here>
}
reverse_proxy 127.0.0.1:19999
}
Reload Caddy:
sudo systemctl reload caddy
Open https://netdata.example.com, log in as admin with your password, and the full real-time dashboard loads over HTTPS. Caddy fetches the Let's Encrypt certificate automatically on first request.
127.0.0.1:19999 over a private network. Our Tailscale guide and WireGuard guide both work well for this - bind Netdata to the VPN interface instead of loopback and it's never on the public internet at all.
Out of the box Netdata is generous with resources. On a big server that's fine; on a 1 GB VPS you'll want to rein it in. The three biggest levers are the collection interval, the database size, and machine learning.
Reopen the main config:
cd /etc/netdata
sudo ./edit-config netdata.conf
Set a slower base interval and cap the on-disk database:
[db]
mode = dbengine
update every = 2
dbengine tier 0 disk space MB = 256
[ml]
enabled = no
What each does:
update every = 2 collects every two seconds instead of one. You lose a little granularity and roughly halve CPU use. On a busy box, 5 is also reasonable.dbengine tier 0 disk space MB = 256 caps the metrics database at 256 MB. Netdata compresses aggressively, so that still holds days of history for a typical VPS.[ml] enabled = no turns off the anomaly-detection engine. It's clever, but it trains models continuously and is the single biggest CPU consumer on a small machine. Disable it unless you specifically want anomaly bands.You can also disable collectors you don't need. List what's running under the Netdata Monitoring section of the dashboard, then turn off individual plugins in /etc/netdata/edit-config python.d.conf or the relevant *.conf. Restart after any change:
sudo systemctl restart netdata
Check the effect with Netdata's own metrics - it monitors itself under the "Netdata Monitoring" charts, so you can watch its RAM and CPU footprint shrink live.
Netdata ships with hundreds of preconfigured alarms - disk filling up, RAM pressure, a service going down, TCP resets climbing. They're on by default; you just need to point them at a notification channel.
Edit the notification config:
cd /etc/netdata
sudo ./edit-config health_alarm_notify.conf
For Discord, find and set these lines:
SEND_DISCORD="YES"
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/XXX/YYY"
DEFAULT_RECIPIENT_DISCORD="alerts"
For ntfy, Slack, Telegram, or email the pattern is identical - flip the SEND_* switch to YES and fill in the webhook or credentials. The file is heavily commented with the exact variable names for each channel.
Restart Netdata, then send a test notification to confirm the pipe works end to end:
sudo systemctl restart netdata
sudo -u netdata /usr/libexec/netdata/plugins.d/alarm-notify.sh test
You should get a batch of test messages (warning, critical, clear) in your channel within a few seconds. If nothing arrives, the webhook URL or a SEND_* flag is wrong.
To tweak a threshold, alarms live in /etc/netdata/health.d/. For example, to change when the disk-space warning fires, edit disks.conf and adjust the warn and crit lines, then run sudo netdatacli reload-health to apply without a full restart.
Netdata's best-kept feature is streaming: child nodes ship their metrics to a parent node in real time, so you get one dashboard for your whole fleet without exposing every box. The parent stores the history; the children can run nearly stateless.
First, generate an API key on the parent - any UUID works:
uuidgen
On the parent VPS, open the streaming config and register the key:
cd /etc/netdata
sudo ./edit-config stream.conf
[<paste-the-uuid-here>]
enabled = yes
default memory mode = dbengine
health enabled by default = auto
On each child server (install Netdata there first with the same kickstart command), edit its stream.conf and point it at the parent:
[stream]
enabled = yes
destination = tcp:PARENT_IP:19999
api key = <the-same-uuid>
Restart Netdata on both ends:
sudo systemctl restart netdata
Within a few seconds the child appears in the parent's dashboard node picker (top-left dropdown), streaming live. Because the parent holds the data, you can set the children to [db] mode = ram in their own netdata.conf to keep them tiny.
19999 - the same one you just closed. Run the traffic across Tailscale or WireGuard and set destination = tcp:PARENT_TAILSCALE_IP:19999, or open the port only from the child's IP with ufw allow from CHILD_IP to any port 19999. Never expose it broadly.
If you'd rather not manage a public dashboard or a parent node at all, Netdata Cloud gives you a hosted, authenticated view of every node - free for the core features. Your metrics still live on your servers; the Cloud only proxies queries to them on demand.
Claim a node from its command line:
sudo netdata-claim.sh -token=YOUR_TOKEN -rooms=YOUR_ROOM_ID -url=https://app.netdata.cloud
You get the token and room ID from the "Connect Nodes" screen in the Netdata Cloud UI. Once claimed, you can keep the local dashboard bound to 127.0.0.1 and never expose port 19999 publicly - the Cloud handles access and authentication for you. It's the lowest-maintenance option for a multi-server setup.
Caddy can't get a certificate. DNS hasn't propagated or ports 80/443 are blocked. Confirm with dig +short netdata.example.com and check your provider's firewall.
Dashboard shows "no data" behind the proxy. Netdata is bound to loopback but Caddy is proxying to the wrong address. Confirm reverse_proxy 127.0.0.1:19999 matches the bind to value in netdata.conf.
Netdata is eating CPU on a small box. Machine learning is the usual culprit. Set [ml] enabled = no and raise update every to 2 or 5, then restart.
A child won't stream to the parent. The API key must match exactly on both ends, and the parent must be reachable on port 19999 from the child. Check journalctl -u netdata -n 50 on the child for a STREAM connection error.
Alert test sends nothing. A SEND_* flag is still NO or the webhook URL is malformed. Re-run alarm-notify.sh test after fixing and watch for errors in the output.
/api/v1/allmetrics?format=prometheus. If you outgrow it, our Grafana and Prometheus on a VPS guide picks up from there.That's it. One command to install, one config change to secure it, and a real-time window into every server you run.
Need a VPS with the headroom to run real-time monitoring? Our Linux plans include fast NVMe storage, IPv6, and a generous network allowance. See the options.