Automate a Server Health Monitor

Write a Bash script that monitors disk, memory, and processes on a schedule.

Introduction

30 Second Summary

Every time a website loads slowly or a service goes offline, there is usually a server running out of disk space or memory that nobody noticed in time. Monitoring your system's health is one of the most common tasks in DevOps and system administration.

In this project, you will build a Bash script that checks your system's disk space, memory, and running processes, then saves a timestamped report to a log file. You will schedule it to run automatically every hour.

What You'll Build

A server health monitoring tool that runs as a Bash script on your Linux machine, collecting system metrics and saving organized reports on a schedule using cron.

By the end of this project, you'll have:

  • A project directory with organized structure including a dedicated logs folder.
  • A working Bash script that collects disk usage, memory stats, and top processes into a single report.
  • A cron job that runs your health check every hour and saves timestamped reports automatically.
  • Secret Mission: Add disk usage threshold alerts that warn you when a partition exceeds 80% capacity.

Are there any prerequisites?

You need a Linux machine with terminal access. No prior scripting experience is required. This guide includes setup and verification for all tools you will use.

Set Up Your Terminal and Tools

Every DevOps workflow starts in the terminal. Before you write a single line of your health monitor script, you need to confirm that your Linux machine has the three tools this project depends on.

In this step, you'll verify that Bash, nano, and cron are installed. Then you'll create your project directory and preview the system commands your script will automate.

In this step, get ready to:
  • Confirm Bash, nano, and cron are installed.
  • Create your project directory structure.
  • Run system monitoring commands to preview their output.
Open your terminal and verify your tools

Your health monitor script needs three tools: Bash (the shell that interprets your script), nano (the text editor you'll write in), and cron (the scheduler that runs your script automatically).

  • Press Ctrl+Alt+T to open your terminal application.

No terminal shortcut?

If Ctrl+Alt+T does not work on your distribution, search your applications menu for "Terminal" or "Console" and open it from there.

  • Verify all three tools are available by running these commands one at a time:
bash --version
which nano
which crontab

What should I see?

The bash --version command prints a version string starting with GNU bash, version followed by a number.

The which commands print file paths like /usr/bin/nano and /usr/bin/crontab. Any path printed means the tool is installed.

✔️ All three commands produced output

You're all set. Bash printed its version, and which printed a file path for both nano and crontab.

ⓧ One or more commands said "not found"

Install the missing tools using your package manager. Choose the command that matches your distribution:

On Debian or Ubuntu:

sudo apt install nano cron

On Fedora:

sudo dnf install nano cronie

After installing, run the three verification commands again to confirm they produce output.

Navigate the terminal and create your project directory

Linux organizes everything in a file system you navigate with text commands. Here are the four commands you'll use most often in this project.

What are these navigation commands?

  • pwd prints your current location (present working directory).
  • ls lists the files and folders in your current location.
  • cd ~ moves you to your home directory.
  • mkdir creates a new directory.
  • Try the navigation commands to get comfortable:
pwd
ls
cd ~
  • Create your project directory and its logs subdirectory by running this command:
mkdir -p ~/server-monitor/logs

What does this command do?

The -p flag tells mkdir to create parent directories as needed. This single command creates both ~/server-monitor/ and ~/server-monitor/logs/ in one step.

  • Confirm the directories were created by running:
ls ~/server-monitor

You should see logs listed in the output.

Don't see the logs folder?

  • Check for typos in your mkdir command. The path must be exactly ~/server-monitor/logs.
  • Run pwd to confirm you are still in the terminal. The ~ character expands to your home directory regardless of where you currently are.

Help me troubleshoot why my mkdir command did not create the logs folder.

Preview the system monitoring commands

Your script will automate three commands that report on system health. Run each one now so you can see what they produce before you put them into a script.

  • Check disk usage by running this command:
df -h

What does this output show?

The df -h command displays filesystem disk space usage in human-readable format. Each row is a filesystem (partition) on your machine.

  • Size is the total capacity of the partition.
  • Used and Avail show how much space is consumed and free.
  • Use% is the percentage full. The / (root) filesystem is the most important one to watch.
  • Check memory usage by running this command:
free -h

What does this output show?

The free -h command shows memory in human-readable auto-scaled units. You'll see two rows: Mem (physical RAM) and Swap (overflow space on disk).

The available column is the key number. It tells you how much memory can be used by new applications without swapping to disk.

  • Check the top memory-consuming processes by running this command:
ps aux --sort=-%mem | head -6

What does this output show?

This command lists all running processes sorted by memory usage (highest first). The head -6 limits the output to 1 header line plus the top 5 processes.

  • USER is the account running the process.
  • PID is the process ID (a unique number the system assigns).
  • %CPU and %MEM show how much of each resource the process is using.
  • COMMAND shows what program is running.

Your environment is ready and you know what each monitoring command produces. Next up, you'll take a closer look at each command's output so you understand exactly what your script will capture.

Explore System Monitoring Commands

In Step 1, you confirmed that df, free, and ps all work on your machine. Now it's time to understand what each column and row in their output actually means.

Your monitoring script will rely on these exact commands, so understanding their data helps you interpret the health reports it generates later.

In this step, get ready to:
  • Study disk usage output and identify the most important column for monitoring.
  • Study memory usage output and learn which metric reflects real availability.
  • Study process listing output and identify resource-hungry processes.
Understand df -h output

The df command displays filesystem disk space usage in human-readable format. Knowing how full your disks are is one of the most common monitoring tasks in Linux.

  • Run the disk usage command by entering this in your terminal:
df -h

What do these columns mean?

You should see a table with six columns:

  • Filesystem shows the device name or partition (e.g., /dev/sda1).
  • Size is the total capacity of the partition.
  • Used is how much space is currently occupied.
  • Available is how much space remains for new data.
  • Use% tells you how full each partition is as a percentage. This is the most important column for monitoring.
  • Mounted on shows where the filesystem is accessible in the directory tree.

Watch the root filesystem

Look for the row with / in the Mounted on column. This is your root filesystem, and it's the most important one to monitor. If it fills up, your system can stop working entirely.

Understand free -h output

The free command shows memory usage in human-readable auto-scaled units. Memory problems can cause applications to crash or slow to a crawl, so this is critical to track.

  • Check your memory usage by running this command:
free -h

What do these rows and columns mean?

You should see two rows:

  • Mem is your physical RAM. This is where running applications live.
  • Swap is disk space used as overflow when RAM runs out. It's much slower than RAM.

The key columns on the Mem row are:

  • total is the total physical memory installed.
  • used is memory currently consumed by applications.
  • free is memory that is completely unused.
  • available is the memory that is actually available for new applications. This is the column you care about most.

Why is 'available' different from 'free'?

Linux uses spare memory as cache to speed things up. The free column only counts truly empty memory. The available column includes cache memory that can be reclaimed when an application needs it.

This means available gives you a more accurate picture of how much room your system actually has.

Understand ps aux --sort=-%mem | head output

The ps command lists running processes. By sorting them by memory usage (highest first) and limiting the output with head, you can quickly spot which processes are consuming the most resources.

  • List the top memory-consuming processes by running this command:
ps aux --sort=-%mem | head -6

What does this output show?

This command prints 6 lines: 1 header line plus the top 5 processes by memory usage. The minus sign in -%mem means descending order (highest first). The columns to focus on are:

  • USER shows which user account owns the process.
  • PID is the process ID. You use this to stop or manage a specific process.
  • %CPU shows what percentage of CPU the process is using.
  • %MEM shows what percentage of RAM the process is using.
  • COMMAND shows the actual program name and arguments. This tells you what the process is.

Spotting a problem process

If a single process shows a very high %MEM value (like 40% or more), that's a sign it might be misbehaving. Your monitoring script will capture this data so you can spot trends over time.

You now know exactly what df, free, and ps report and which columns matter most. Next up, you'll combine all three commands into a single Bash script that generates a complete health report with one command.

Write Your Health Monitor Script

You've explored the three key monitoring commands and understand what each one reveals about your system. Now it's time to combine them into a single script that generates a full health report automatically.

You'll write the script using nano, the terminal-based text editor. Instead of running three commands separately each time you want a health check, your script will handle everything in one go and save the results to a timestamped file.

In this step, get ready to:
  • Create a new script file using nano.
  • Write the monitoring logic that collects disk, memory, and process data.
  • Save your script to the project directory.
Create the script file

Nano is a terminal-based text editor that shows its keyboard shortcuts at the bottom of the screen. You'll use it to create and write your script from scratch.

  • Open a new file in nano by running this command:
nano ~/server-monitor/health_monitor.sh

Nano opens with an empty file. You'll see a toolbar at the bottom showing shortcuts like ^O (save) and ^X (exit).

What is nano?

Nano is a beginner-friendly text editor that runs directly in your terminal. Unlike vim, which requires learning modal editing, nano shows its keyboard shortcuts on screen so you always know how to save and exit.

Add the monitoring logic

Your script has two main parts: a setup section that defines where to save the report, and a body section that collects system data.

  • Type the following setup section into nano:
#!/bin/bash

# Server Health Monitor
# Checks disk usage, memory, and top processes
# Saves a timestamped report to the logs directory

LOGDIR="$HOME/server-monitor/logs"
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
LOGFILE="$LOGDIR/health_report_$TIMESTAMP.log"

# Create logs directory if it does not exist
mkdir -p "$LOGDIR"

What does this code do?

  • #!/bin/bash is the shebang line. It tells your system to use Bash to run this script.
  • LOGDIR stores the path to your logs folder. Using $HOME instead of a hardcoded path makes the script portable across different users.
  • TIMESTAMP captures the current date and time in a filename-safe format like 2026-06-09_14-30-00.
  • LOGFILE combines the directory and timestamp into a unique filename for each report.
  • mkdir -p ensures the logs directory exists before the script tries to write to it.
  • Below the setup section, type the report generation code:
# Header
echo "========================================" > "$LOGFILE"
echo "  SERVER HEALTH REPORT" >> "$LOGFILE"
echo "  Generated: $(date)" >> "$LOGFILE"
echo "========================================" >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Disk Usage
echo "--- DISK USAGE ---" >> "$LOGFILE"
df -h >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Memory Usage
echo "--- MEMORY USAGE ---" >> "$LOGFILE"
free -h >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Top 5 Processes by Memory
echo "--- TOP 5 PROCESSES (by memory) ---" >> "$LOGFILE"
ps aux --sort=-%mem | head -6 >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Footer
echo "========================================" >> "$LOGFILE"
echo "  End of Report" >> "$LOGFILE"
echo "========================================" >> "$LOGFILE"

echo "Health report saved to: $LOGFILE"

What does this code do?

  • The first echo uses > (single arrow) to create the log file. Every line after that uses >> (double arrow) to append without overwriting.
  • df -h >> "$LOGFILE" sends disk usage output directly into the log file instead of printing it on screen.
  • free -h >> "$LOGFILE" does the same for memory data.
  • ps aux --sort=-%mem | head -6 >> "$LOGFILE" captures 6 lines: 1 header row plus the top 5 memory-consuming processes.
  • The final echo (without >>) prints a confirmation message to the terminal so you know the script ran.

What is output redirection?

In Bash, > and >> are output redirection operators.

The > operator creates a new file (or overwrites an existing one). The >> operator appends to the end of a file without erasing what's already there. This is why the header uses > to start fresh, and everything else uses >> to keep building the report.

✔️ Awesome, I've got everything!

Great. Make sure you've typed both sections into nano with no gaps between them.

ⓧ I'd like to double check the full code

Here's the complete script. Compare what you've typed in nano against this:

#!/bin/bash

# Server Health Monitor
# Checks disk usage, memory, and top processes
# Saves a timestamped report to the logs directory

LOGDIR="$HOME/server-monitor/logs"
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
LOGFILE="$LOGDIR/health_report_$TIMESTAMP.log"

# Create logs directory if it does not exist
mkdir -p "$LOGDIR"

# Header
echo "========================================" > "$LOGFILE"
echo "  SERVER HEALTH REPORT" >> "$LOGFILE"
echo "  Generated: $(date)" >> "$LOGFILE"
echo "========================================" >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Disk Usage
echo "--- DISK USAGE ---" >> "$LOGFILE"
df -h >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Memory Usage
echo "--- MEMORY USAGE ---" >> "$LOGFILE"
free -h >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Top 5 Processes by Memory
echo "--- TOP 5 PROCESSES (by memory) ---" >> "$LOGFILE"
ps aux --sort=-%mem | head -6 >> "$LOGFILE"
echo "" >> "$LOGFILE"

# Footer
echo "========================================" >> "$LOGFILE"
echo "  End of Report" >> "$LOGFILE"
echo "========================================" >> "$LOGFILE"

echo "Health report saved to: $LOGFILE"
Save and exit nano

Now that your script is complete, you need to save the file and return to the terminal.

  • Press Ctrl+O to save (write out) the file.
  • Press Enter to confirm the filename.
  • Press Ctrl+X to exit nano and return to the terminal.
  • Verify the file was created by running:
ls -l ~/server-monitor/health_monitor.sh

You should see a line showing health_monitor.sh with its file size and creation date.

Don't see the file?

  • If you get No such file or directory, you may have exited nano without saving. Reopen the file with nano ~/server-monitor/health_monitor.sh and make sure to press Ctrl+O then Enter before exiting.
  • Double check the path in your ls command matches exactly: ~/server-monitor/health_monitor.sh.

Why can't I see my script file?

Your health monitor script is written and saved. Next up, you'll make it executable and run it to generate your first health report.

Make It Executable and Run It

Your health monitor script is written, but Linux won't let you run it yet. By default, new files are created without execute permission.

In this step, you will change the script's file permissions to make it executable, run it for the first time, and confirm it produces a proper health report.

In this step, get ready to:
  • Make your script executable with chmod.
  • Run the script manually and generate your first log file.
  • Read the log file and confirm it contains disk, memory, and process data.
Set file permissions

Linux uses a permission system to control who can read, write, or execute a file. Your script currently has read and write permissions, but no execute permission.

  • Make your script executable by running this command:
chmod 755 ~/server-monitor/health_monitor.sh

What does this command do?

chmod changes file permissions. The number 755 sets three levels of access:

  • 7 (owner): read + write + execute.
  • 5 (group): read + execute.
  • 5 (others): read + execute.
  • Verify the permissions changed by running:
ls -l ~/server-monitor/health_monitor.sh

You should see -rwxr-xr-x at the start of the output. The x in each group confirms execute permission is set.

Still seeing no x in the permissions?

  • Double-check you typed 755 and not 644 or another number.
  • Make sure the file path is correct. Run ls ~/server-monitor/ to confirm health_monitor.sh exists there.

Why can't I make my script executable?

Run the script manually

Now that the script is executable, you can run it like any other program on your system.

  • Execute your health monitor by running this command:
~/server-monitor/health_monitor.sh

You should see a message like Health report saved to: followed by the path to your new log file.

  • Confirm the log file was created by running:
ls ~/server-monitor/logs/

You should see a file named something like health_report_2026-06-09_14-30-00.log with today's date and time.

Seeing "Permission denied" or no log file?

  • If you see a permission error, re-run the chmod 755 command from the previous substep.
  • If the logs directory is empty, check for error messages in the terminal output. A typo in the script path will produce a "No such file or directory" message.
  • Make sure you saved the file correctly in nano during the previous step. Run cat ~/server-monitor/health_monitor.sh to verify the script contents.

Why is my script not running correctly?

Read the log file

The whole point of your monitor is the report it produces. Let's open the log file and make sure it captured all three sections of system data.

  • Display the contents of your log file by running:
cat ~/server-monitor/logs/health_report_*.log

What does this command do?

cat prints a file's contents to the terminal. The * wildcard matches any characters, so this displays whichever timestamped log file exists in the directory.

You should see your complete health report with the header, disk usage table, memory usage table, top 5 processes, and footer.

Log file looks empty or incomplete?

  • If the file is empty, the script may have failed silently. Re-run ~/server-monitor/health_monitor.sh and watch for error messages.
  • If you see only the header and no data, check that df, free, and ps commands work when you run them manually in the terminal.

My log file doesn't have all the sections I expected.

Your script works. You've proven it can collect system data and save a clean, timestamped report. Next up, you'll automate this so the script runs itself every hour without you lifting a finger.

Schedule It with Cron

Your script runs perfectly when you execute it by hand. It produces a clean timestamped health report every time.

But a monitoring tool is only useful if it runs consistently without you remembering to trigger it. Cron is Linux's built-in job scheduler that runs commands on a repeating schedule. You'll configure it to execute your health monitor automatically every hour.

In this step, get ready to:
  • Open and edit your personal crontab file.
  • Schedule your health monitor script to run every hour.
  • Verify the cron job is installed and working.
Open your crontab

A crontab is a personal schedule file where you list commands and the times they should run. Each Linux user has their own crontab managed by the cron daemon.

  • Find your username by running this command:
whoami

Note the output. This is the username you'll need in a moment.

  • Open your crontab for editing by running:
crontab -e

What does this command do?

`crontab -e` opens your personal cron schedule file in a text editor. If you've never edited your crontab before, you'll see a message saying no crontab for user - using an empty one. This is completely normal.

Prompted to choose an editor?

If you see a list of editors to choose from, select the option for nano (it is usually marked with "easiest" next to it). This opens your crontab in nano, the same editor you used to write your script.

Seeing an error about the cron service?

On some minimal Linux installs or WSL, the cron daemon may not be running. Check its status by running systemctl status cron (or systemctl status crond on Fedora/RHEL). If it's inactive, start it with sudo systemctl start cron.

Help me troubleshoot cron not running on my system

Add the hourly schedule

Now that your crontab is open in nano, you'll add a single line that tells cron what to run and when.

  • Scroll to the bottom of the file (use the arrow keys to move past any comment lines that start with #).
  • Add this line at the bottom:
0 * * * * /home/[[USERNAME="your username from whoami"]]/server-monitor/health_monitor.sh

What does this cron expression mean?

The five fields before the command define the schedule. They are: minute (0-59), hour (0-23), day of month (1-31), month (1-12), day of week (0-7).

`0 * * * *` means "at minute 0 of every hour, every day." The asterisks (*) mean "any value" for that field. So your script runs at the top of every hour automatically.

  • Press Ctrl+O to save the file.
  • Press Enter to confirm the filename.
  • Press Ctrl+X to exit nano.

You should see a message confirming the new crontab has been installed.

Seeing an error about the path?

Make sure you replaced the username placeholder with the exact output from whoami. The full path must match your actual home directory. You can double-check by running echo $HOME in a separate terminal.

Help me fix the path in my crontab entry

Verify the cron job is installed

Saving and exiting the crontab editor automatically registers the job with the cron daemon. You can confirm it's in place by listing your scheduled jobs.

  • List your active cron jobs by running:
crontab -l

You should see the line you just added: 0 * * * * followed by the full path to your script.

What happens next?

The cron daemon checks your crontab every minute. At minute 0 of the next hour (and every hour after that), it will run your script automatically. New log files will appear in ~/server-monitor/logs/ without you lifting a finger.

Test it without waiting an hour

To see cron in action right away, temporarily change the schedule to * * * * * (every minute) by running crontab -e and editing the first field. Wait one minute, then check the logs directory. Remember to change it back to 0 * * * * afterwards so you don't flood your logs folder.

  • Confirm that new log files are appearing by running:
ls ~/server-monitor/logs/

After the scheduled time passes, you should see a new log file with a more recent timestamp alongside your earlier manual test report.

No new log file appearing?

Check that the cron daemon is running with systemctl status cron. If it shows inactive, start it with sudo systemctl start cron.

Also verify that the path in your crontab is the full absolute path (starting with /home/), not a relative path or one using ~. Cron runs in a minimal environment and does not expand ~ to your home directory.

Help me debug why my cron job isn't producing log files

Secret mission

Add Disk Usage Threshold Alerts

Your health monitor collects data, but it doesn't warn you when something is wrong. Real monitoring tools alert you before a disk fills up and crashes your system. Can you add conditional logic that flags any partition exceeding 80% capacity?

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing costs. The only active resource is the cron job that runs your script every hour.

Resources you used:

  • Project directory at ~/server-monitor/ (script and logs).
  • Crontab entry running health_monitor.sh every hour.

Keep everything running

No action needed. Choose this if you want your health monitor to keep running and collecting reports every hour.

  • Your cron job will continue generating new log files in ~/server-monitor/logs/ every hour.
  • Over time, log files will accumulate. You may want to periodically delete older logs to save disk space.

Pause - I'll come back to this later

Remove the cron job to stop automatic runs. Your script and existing logs stay on disk so you can resume later.

  • Open your crontab for editing by running:
crontab -e
  • Find the line that starts with 0 * * * * and references health_monitor.sh.
  • Delete that entire line, then save and exit (Ctrl+O, Enter, Ctrl+X).
  • Verify it is removed by running:
crontab -l

You should no longer see the health monitor entry. Your script and logs remain at ~/server-monitor/ for when you return.

Delete - I don't want to use this again

Remove all project resources and start fresh. This deletes the cron job, your script, and all saved log files.

  • First, remove the cron job by opening your crontab:
crontab -e
  • Find the line that starts with 0 * * * * and references health_monitor.sh.
  • Delete that entire line, then save and exit (Ctrl+O, Enter, Ctrl+X).
  • Next, delete the entire project directory by running:
rm -rf ~/server-monitor
  • Verify both are gone by running:
crontab -l
ls ~/server-monitor

You should see no crontab entries referencing your script. The ls command should return an error confirming the directory no longer exists.

Nice Work!

Nice Work!

You just built a real server health monitoring tool from scratch using nothing but Linux commands and Bash scripting. This is exactly the kind of automation that DevOps engineers rely on every day to keep systems healthy.

You've learned how to:

  • Write a Bash script that collects system metrics using df, free, and ps with output redirection to log files.
  • Set file permissions with chmod to make scripts executable on a Linux system.
  • Schedule automated tasks with cron to run your health monitor every hour without manual intervention.
  • Secret Mission: Added disk threshold alerting with conditionals and text parsing using awk and Bash loops.

Ready to quiz yourself?