Tools: How to Set Up Linux Server Monitoring in 10 Minutes (Free) (2026)

Tools: How to Set Up Linux Server Monitoring in 10 Minutes (Free) (2026)

How to Set Up Linux Server Monitoring in 10 Minutes (Free)

What We're Monitoring

Step 1: Install netdata (2 minutes)

Step 2: Basic Cron-Based Alerting (3 minutes)

Step 3: PM2 Monitoring (if using Node.js)

Step 4: Quick Health Endpoint

The 10-Minute Summary If you're running a production app on a VPS and you're relying on "it seems fine" as your monitoring strategy — this post is for you. Here's a minimal, free monitoring setup that covers the basics in under 10 minutes. Netdata is free, open source, and installs with one command: It auto-discovers services, requires no config, and gives you a real-time dashboard on port 19999. For dead-simple email alerts without a third-party service: Add this to your Node.js app: Then add to your cron monitor: I built ARIA to solve exactly this.

Try it free at step2dev.com — no credit card needed. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Code Block

Copy

bash <(curl -Ss https://my-netdata.io/kickstart.sh) bash <(curl -Ss https://my-netdata.io/kickstart.sh) bash <(curl -Ss https://my-netdata.io/kickstart.sh) # Access it (from your server) http://your-server-ip:19999 # Or tunnel it securely ssh -L 19999:localhost:19999 user@your-server # Then visit http://localhost:19999 in your browser # Access it (from your server) http://your-server-ip:19999 # Or tunnel it securely ssh -L 19999:localhost:19999 user@your-server # Then visit http://localhost:19999 in your browser # Access it (from your server) http://your-server-ip:19999 # Or tunnel it securely ssh -L 19999:localhost:19999 user@your-server # Then visit http://localhost:19999 in your browser # Install mailutils sudo apt install mailutils -y # Create a monitoring script sudo nano /usr/local/bin/server-check.sh # Install mailutils sudo apt install mailutils -y # Create a monitoring script sudo nano /usr/local/bin/server-check.sh # Install mailutils sudo apt install mailutils -y # Create a monitoring script sudo nano /usr/local/bin/server-check.sh #!/bin/bash ALERT_EMAIL="[email protected]" THRESHOLD_DISK=85 THRESHOLD_RAM=90 # Disk check DISK_USAGE=$(df -h / | awk 'NR==2{print $5}' | tr -d '%') if [ "$DISK_USAGE" -gt "$THRESHOLD_DISK" ]; then echo "ALERT: Disk usage is ${DISK_USAGE}% on $(hostname)" | mail -s "Disk Alert - $(hostname)" $ALERT_EMAIL fi # RAM check RAM_AVAILABLE=$(free | awk '/^Mem/{print int($7/$2*100)}') if [ "$RAM_AVAILABLE" -lt $((100 - THRESHOLD_RAM)) ]; then echo "ALERT: RAM available is ${RAM_AVAILABLE}% on $(hostname)" | mail -s "RAM Alert - $(hostname)" $ALERT_EMAIL fi # Service check (change 'node' to your process name) if ! pgrep -x "node" > /dev/null; then echo "ALERT: node process is DOWN on $(hostname)" | mail -s "Service DOWN - $(hostname)" $ALERT_EMAIL fi #!/bin/bash ALERT_EMAIL="[email protected]" THRESHOLD_DISK=85 THRESHOLD_RAM=90 # Disk check DISK_USAGE=$(df -h / | awk 'NR==2{print $5}' | tr -d '%') if [ "$DISK_USAGE" -gt "$THRESHOLD_DISK" ]; then echo "ALERT: Disk usage is ${DISK_USAGE}% on $(hostname)" | mail -s "Disk Alert - $(hostname)" $ALERT_EMAIL fi # RAM check RAM_AVAILABLE=$(free | awk '/^Mem/{print int($7/$2*100)}') if [ "$RAM_AVAILABLE" -lt $((100 - THRESHOLD_RAM)) ]; then echo "ALERT: RAM available is ${RAM_AVAILABLE}% on $(hostname)" | mail -s "RAM Alert - $(hostname)" $ALERT_EMAIL fi # Service check (change 'node' to your process name) if ! pgrep -x "node" > /dev/null; then echo "ALERT: node process is DOWN on $(hostname)" | mail -s "Service DOWN - $(hostname)" $ALERT_EMAIL fi #!/bin/bash ALERT_EMAIL="[email protected]" THRESHOLD_DISK=85 THRESHOLD_RAM=90 # Disk check DISK_USAGE=$(df -h / | awk 'NR==2{print $5}' | tr -d '%') if [ "$DISK_USAGE" -gt "$THRESHOLD_DISK" ]; then echo "ALERT: Disk usage is ${DISK_USAGE}% on $(hostname)" | mail -s "Disk Alert - $(hostname)" $ALERT_EMAIL fi # RAM check RAM_AVAILABLE=$(free | awk '/^Mem/{print int($7/$2*100)}') if [ "$RAM_AVAILABLE" -lt $((100 - THRESHOLD_RAM)) ]; then echo "ALERT: RAM available is ${RAM_AVAILABLE}% on $(hostname)" | mail -s "RAM Alert - $(hostname)" $ALERT_EMAIL fi # Service check (change 'node' to your process name) if ! pgrep -x "node" > /dev/null; then echo "ALERT: node process is DOWN on $(hostname)" | mail -s "Service DOWN - $(hostname)" $ALERT_EMAIL fi chmod +x /usr/local/bin/server-check.sh # Add to cron (run every 5 minutes) crontab -e # Add: */5 * * * * /usr/local/bin/server-check.sh chmod +x /usr/local/bin/server-check.sh # Add to cron (run every 5 minutes) crontab -e # Add: */5 * * * * /usr/local/bin/server-check.sh chmod +x /usr/local/bin/server-check.sh # Add to cron (run every 5 minutes) crontab -e # Add: */5 * * * * /usr/local/bin/server-check.sh # Install PM2 globally npm install -g pm2 # Start your app with PM2 pm2 start server.js --name your-app # Set up startup script (survive reboots) pm2 startup pm2 save # Monitor in terminal pm2 monit # Install PM2 globally npm install -g pm2 # Start your app with PM2 pm2 start server.js --name your-app # Set up startup script (survive reboots) pm2 startup pm2 save # Monitor in terminal pm2 monit # Install PM2 globally npm install -g pm2 # Start your app with PM2 pm2 start server.js --name your-app # Set up startup script (survive reboots) pm2 startup pm2 save # Monitor in terminal pm2 monit app.get('/health', (req, res) => { const healthCheck = { uptime: process.uptime(), message: 'OK', timestamp: Date.now(), memoryUsage: process.memoryUsage(), }; res.status(200).json(healthCheck); }); app.get('/health', (req, res) => { const healthCheck = { uptime: process.uptime(), message: 'OK', timestamp: Date.now(), memoryUsage: process.memoryUsage(), }; res.status(200).json(healthCheck); }); app.get('/health', (req, res) => { const healthCheck = { uptime: process.uptime(), message: 'OK', timestamp: Date.now(), memoryUsage: process.memoryUsage(), }; res.status(200).json(healthCheck); }); # Health endpoint check HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health) if [ "$HTTP_STATUS" != "200" ]; then echo "ALERT: Health check failed with status $HTTP_STATUS" | mail -s "App Health Fail" $ALERT_EMAIL fi # Health endpoint check HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health) if [ "$HTTP_STATUS" != "200" ]; then echo "ALERT: Health check failed with status $HTTP_STATUS" | mail -s "App Health Fail" $ALERT_EMAIL fi # Health endpoint check HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health) if [ "$HTTP_STATUS" != "200" ]; then echo "ALERT: Health check failed with status $HTTP_STATUS" | mail -s "App Health Fail" $ALERT_EMAIL fi # 1. Install netdata for visual monitoring bash <(curl -Ss https://my-netdata.io/kickstart.sh) # 2. Add cron monitoring script # (copy from above) # 3. Set up PM2 if Node.js pm2 startup && pm2 save # 4. Add /health endpoint to your app # 5. Test your alerts # ./server-check.sh (run manually, check email) # 1. Install netdata for visual monitoring bash <(curl -Ss https://my-netdata.io/kickstart.sh) # 2. Add cron monitoring script # (copy from above) # 3. Set up PM2 if Node.js pm2 startup && pm2 save # 4. Add /health endpoint to your app # 5. Test your alerts # ./server-check.sh (run manually, check email) # 1. Install netdata for visual monitoring bash <(curl -Ss https://my-netdata.io/kickstart.sh) # 2. Add cron monitoring script # (copy from above) # 3. Set up PM2 if Node.js pm2 startup && pm2 save # 4. Add /health endpoint to your app # 5. Test your alerts # ./server-check.sh (run manually, check email) - Service health (is your app actually running?) - Basic alerting when things go wrong