Netdata is an open source monitoring agent that collects thousands of per-second metrics (CPU, memory, disks, network, processes, containers and services such as Nginx or MySQL) with almost no configuration and shows them on a live web dashboard. In this tutorial you will install Netdata on Ubuntu 24.04, restrict access to its dashboard, enable an Nginx collector, create a custom health alert that notifies a Slack channel, and optionally stream metrics from several servers to one parent node.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 1 GB of RAM.
- A non-root user with
sudoprivileges. - UFW enabled with SSH allowed (
sudo ufw allow OpenSSHandsudo ufw enable). - The public IP address of the computer you will use to open the dashboard, referred to as
your_ip. - Optional: Nginx installed (
sudo apt install nginx) to follow the collector step, and a Slack incoming webhook URL for the notification step.
Step 1 - Installing Netdata
Netdata's supported installation method is its kickstart.sh script. On Ubuntu it detects the release and installs Netdata's native .deb packages from the official repository, so later updates arrive through apt. Download the script first so you can review it:
wget -O /tmp/netdata-kickstart.sh https://get.netdata.cloud/kickstart.sh
less /tmp/netdata-kickstart.sh
Run it with the stable release channel and anonymous telemetry disabled:
sh /tmp/netdata-kickstart.sh --stable-channel --disable-telemetry
The script asks for your sudo password and confirmation before it adds the repository and installs the netdata package. When it finishes, the service is already enabled and running. Check it:
sudo systemctl status netdata --no-pager
● netdata.service - Netdata, X-Ray Vision for your infrastructure!
Loaded: loaded (/usr/lib/systemd/system/netdata.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-09-24 10:12:41 UTC; 25s ago
Netdata serves its dashboard and API on TCP port 19999. Query the API locally to confirm the agent answers:
curl -s http://localhost:19999/api/v1/info | grep -m1 '"version"'
"version": "v2.6.3",
Your version number will differ.
Step 2 - Restricting access to the dashboard
By default Netdata listens on all interfaces and the dashboard has no password. Anyone who can reach port 19999 can see process names, users and service details, so only allow your own IP address through the firewall:
sudo ufw allow from your_ip to any port 19999 proto tcp
Check the rule:
sudo ufw status
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
19999/tcp ALLOW your_ip
OpenSSH (v6) ALLOW Anywhere (v6)
Now open http://your_server_ip:19999 in your browser. The dashboard may offer to sign in to Netdata Cloud; you can skip that and keep using the local agent dashboard. You should see charts for CPU, load, memory, disks and network updating every second.
TipIf your IP address changes often, do not open the port at all. Instead, create an SSH tunnel with
ssh -L 19999:localhost:19999 your_user@your_server_ipand browse tohttp://localhost:19999on your own machine.
Step 3 - Understanding the configuration layout
Netdata keeps its stock configuration under /usr/lib/netdata/conf.d/ and reads your overrides from /etc/netdata/. Never edit the stock files: use the edit-config helper, which copies the stock file into /etc/netdata/ the first time and opens it in your editor.
cd /etc/netdata
sudo ./edit-config netdata.conf
Most settings work out of the box, so close the file without changes for now. The paths you will use in this guide are:
| Path | Purpose |
|---|---|
/etc/netdata/netdata.conf | Main agent settings (web server, database, plugins) |
/etc/netdata/go.d/<module>.conf | Collector jobs for services (Nginx, MySQL, Redis...) |
/etc/netdata/health.d/*.conf | Health alert definitions |
/etc/netdata/health_alarm_notify.conf | Notification methods (email, Slack, Discord...) |
/etc/netdata/stream.conf | Parent and child streaming |
Logs go to the systemd journal, so sudo journalctl -u netdata is the first place to look when something fails.
Step 4 - Monitoring Nginx with a collector
Netdata's go.d plugin auto-detects many local services by probing their usual endpoints. For Nginx it needs the stub_status page, which is not enabled by default. Create a small server block that exposes it only on localhost:
sudo nano /etc/nginx/conf.d/stub_status.conf
server {
listen 127.0.0.1:80;
server_name 127.0.0.1;
location = /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
Test the configuration and reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
curl -s http://127.0.0.1/nginx_status
Active connections: 1
server accepts handled requests
3 3 3
Reading: 0 Writing: 1 Waiting: 0
Now tell Netdata where the page is. Open the Nginx collector configuration:
cd /etc/netdata
sudo ./edit-config go.d/nginx.conf
Replace the jobs section at the end of the file with:
jobs:
- name: local
url: http://127.0.0.1/nginx_status
Restart Netdata so the collector picks up the job:
sudo systemctl restart netdata
After a few seconds, check that Nginx charts exist:
curl -s http://localhost:19999/api/v1/charts | grep -o '"nginx_local[^"]*"' | sort -u | head -n 3
"nginx_local.connections"
"nginx_local.connections_status"
"nginx_local.requests"
The dashboard now shows an Nginx section with active connections and requests per second. The same pattern (enable the service's status endpoint, then add a job in go.d/<module>.conf) applies to MySQL, PostgreSQL, Redis and the other supported collectors.
Step 5 - Creating a custom health alert
Netdata ships with hundreds of preconfigured alerts (disk space, RAM, network errors and more). You can add your own in a new file under health.d. This one raises a warning when average CPU utilization over five minutes exceeds 80% and a critical alert above 95%:
sudo nano /etc/netdata/health.d/cpu_custom.conf
alarm: cpu_usage_high
on: system.cpu
lookup: average -5m unaligned of user,system,softirq,irq,guest
units: %
every: 1m
warn: $this > 80
crit: $this > 95
info: average CPU utilization over the last 5 minutes
to: sysadmin
Here on is the chart the alert watches, lookup computes the value ($this) from the chosen dimensions, and to is the recipient role used by the notification settings. Reload the health configuration without restarting the agent:
sudo netdatacli reload-health
Verify that the new alert is loaded:
curl -s 'http://localhost:19999/api/v1/alarms?all' | grep -o '"cpu_usage_high[^"]*"' | head -n 1
"cpu_usage_high"
The alert also appears in the Alerts tab of the dashboard, with its current status (normally CLEAR).
Step 6 - Sending notifications to Slack
Alert notifications are handled by the alarm-notify.sh script and configured in health_alarm_notify.conf. Open it:
cd /etc/netdata
sudo ./edit-config health_alarm_notify.conf
Find the Slack section and set these three values, using your own webhook URL and channel:
SEND_SLACK="YES"
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/XXXXXXXX/XXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX"
DEFAULT_RECIPIENT_SLACK="#alerts"
Save the file and send a test notification as the netdata user:
sudo -u netdata /usr/libexec/netdata/plugins.d/alarm-notify.sh test
The script sends a WARNING, a CRITICAL and a CLEAR test message, and prints OK for each method that succeeded:
# SENDING TEST WARNING ALARM TO ROLE: sysadmin
2026-09-24 10:31:02: alarm-notify.sh: INFO: sent slack notification to '#alerts' for notification to 'sysadmin'
# OK
Three messages should arrive in your Slack channel. Email works the same way (SEND_EMAIL="YES" and DEFAULT_RECIPIENT_EMAIL), but it requires a working mail transfer agent on the server, such as Postfix configured to relay through your SMTP provider.
Step 7 - Streaming metrics to a parent node (optional)
With several servers you can stream every agent (child) to one Netdata parent, which stores all the metrics and shows them from a single dashboard. Streaming is authenticated with an API key, which is simply a UUID. Generate one on the parent:
cat /proc/sys/kernel/random/uuid
3c8f5e0a-7a39-4b8e-9d1c-2f6a7b8c9d10
On the parent, open stream.conf:
cd /etc/netdata
sudo ./edit-config stream.conf
Add a section named after the key at the end of the file, allowing only your child servers' addresses:
[3c8f5e0a-7a39-4b8e-9d1c-2f6a7b8c9d10]
enabled = yes
allow from = child_ip_1 child_ip_2
Open port 19999 on the parent for each child and restart Netdata:
sudo ufw allow from child_ip_1 to any port 19999 proto tcp
sudo systemctl restart netdata
On each child, edit its own stream.conf and fill in the [stream] section at the top:
[stream]
enabled = yes
destination = parent_ip:19999
api key = 3c8f5e0a-7a39-4b8e-9d1c-2f6a7b8c9d10
Restart Netdata on the child:
sudo systemctl restart netdata
Back on the parent, the child should appear in the list of mirrored hosts:
curl -s http://localhost:19999/api/v1/info | grep -A3 '"mirrored_hosts"'
"mirrored_hosts": [
"parent-hostname",
"child-hostname"
],
In the parent dashboard you can now switch between nodes. The traffic between child and parent is unencrypted, so use it over a private network or a VPN.
Troubleshooting
- The dashboard does not load from your browser: check
sudo ss -tlnp | grep 19999to confirm Netdata is listening, andsudo ufw statusto confirm your current public IP is the one allowed. - A collector shows no charts: look for errors from the plugin with
sudo journalctl -u netdata | grep -i nginx. The most common cause is a URL that returns 404 or 403 to Netdata. - The test notification fails: run the test command again and read the error line; a
403or404from Slack means the webhook URL is wrong or was revoked. - The child does not connect: on the child,
sudo journalctl -u netdata | grep -i streamshows whether the connection is refused (firewall) or the key is rejected (allow fromor API key mismatch).
Conclusion
You now have Netdata collecting per-second metrics on Ubuntu 24.04, with a dashboard limited to your IP, an Nginx collector, a custom CPU alert delivered to Slack and, optionally, a parent node that centralizes several servers. From here you can enable more go.d collectors for your databases, tune the stock alerts in health.d to your workloads, or put the dashboard behind an Nginx reverse proxy with HTTPS and basic authentication.
