Rescue a Broken Linux Service

Repair a Linux heartbeat service and automate liveness and health checks.

Introduction

30 Second Summary

A service can look fine until a deployment refuses to start it. The useful skill is tracing that symptom to a concrete cause.

In this project, you will build a heartbeat service inside a Linux virtual machine. You will turn a failed direct launch into a repeatable health check.

What You'll Build

Your final demo shows a health check switching from PASS to FAIL when the heartbeat service stops.

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

  • A background heartbeat service whose log grows with timestamped healthy records.
  • A permission troubleshooting demo where a direct launch fails before your file mode repair makes it work.
  • A repeatable health check that connects the saved process ID to the latest service heartbeat.
  • Secret Mission: Make the check reject a live process when its newest heartbeat reports an unhealthy state.

Are there any prerequisites?

You need access to your existing Linux virtual machine from a Windows 10 or 11 computer. You do not need a cloud account or any paid service.

Before We Start

This is your moment to lock in what you are building before the hands-on work begins. You will connect the heartbeat service to a real troubleshooting goal instead of memorising isolated Linux commands.

Prepare Your Linux Operations Lab

Your heartbeat service depends on a predictable Linux command line. A missing shell or utility would turn the planned troubleshooting exercise into an environment problem.

This step confirms the POSIX shell that runs the service. It also gives the lab an empty workspace for its process files and logs.

In this step, get ready to:
  • Verify terminal access to the Linux virtual machine through /bin/sh.
  • Confirm every command required by the operations lab.
  • Create linux-ops-lab with an empty runtime directory.
Verify the VM shell

The service script later starts with #!/bin/sh. Direct execution depends on an executable interpreter at /bin/sh.

  • Connect to your existing Linux virtual machine from Windows using its configured access method.
  • Confirm that the terminal shows a shell prompt inside the Linux virtual machine.
  • Verify the shell location and executable interpreter by running these commands:
command -v sh
test -x /bin/sh

What Do These Checks Prove?

  • The first command asks the shell which path it uses for sh.
  • The second command checks whether /bin/sh has execute permission.

You should see a path for sh after the first command. The second command should return you to the prompt without reporting a failure.

Does a Shell Check Fail?

  • Reconnect to the Linux VM if the terminal session has closed.
  • Confirm that you are running the commands inside the VM instead of a Windows terminal.
  • Contact the VM administrator if /bin/sh is missing or cannot be executed.

Ask for targeted help with the shell checks: Help me diagnose why the POSIX shell checks fail inside my Linux virtual machine.

Validate the required utilities

The lab uses a small command-line toolchain for permissions, timestamps, process inspection, delays, pattern matching, and log inspection. A shell loop can verify the complete set without repeating the same check manually.

  • Validate all seven utilities by running this shell loop:
for utility in chmod date grep ls ps sleep tail
do
  command -v "$utility"
done

How Does the Loop Work?

  • The loop gives each utility name to command -v.
  • Each printed path confirms that the shell can find that utility.
  • Seven paths confirm the lab has its complete command-line toolchain.

You should see seven command paths. Each line corresponds to one utility in the loop.

Is a Utility Missing?

  • Run the loop again if the terminal connection dropped before it finished.
  • Identify the utility whose name produced no command path.
  • Ask the VM administrator to provide the missing standard utility before continuing.

Get help interpreting an incomplete result: Help me identify which required utility is missing from my Linux VM.

Build the workspace

A dedicated workspace keeps every lab artifact under one directory. The runtime directory later holds the PID file and service logs.

  • Build the workspace in your Linux home directory by running these commands:
cd
mkdir linux-ops-lab
cd linux-ops-lab
mkdir runtime

What Do These Commands Create?

  • The first command moves the shell to your Linux home directory.
  • The first mkdir command creates the linux-ops-lab directory.
  • The second cd command makes linux-ops-lab your current directory.
  • The final command creates the empty runtime directory inside the lab.
  • Inspect the workspace path and directory permissions by running:
pwd
ls -ld . runtime

What Does the Listing Show?

  • The pwd output identifies the current workspace path.
  • The long listing shows permission information for the current directory.
  • The same listing shows permission information for runtime.

The path should end with linux-ops-lab. The listing should contain separate rows for . and runtime.

Did the Workspace Check Fail?

  • Return to your Linux home directory if the lab was created in a different location.
  • Remove any incomplete empty lab directory before repeating the creation commands.
  • Confirm that your Linux user can create directories in its home directory.

Ask for help with the workspace state: Help me fix my linux-ops-lab directory layout inside my Linux VM.

Before you run the final check, what path and directory name do you expect the terminal to show?

  • Verify the completed workspace by running:
pwd && ls -ld runtime

What Confirms Success?

The first line prints the full path to linux-ops-lab. The next line is the long listing for the empty runtime directory.

You now have a verified shell toolchain inside the Linux VM. Your terminal is also positioned in the workspace that the service uses.

You have cleared the environment risk before introducing the service. Next up, you will create a heartbeat script and watch its log grow.

Run the First Heartbeat Service

You confirmed that your Linux VM has the shell tools this lab needs. The empty runtime directory gives the service a clean place to store its operational files.

A useful troubleshooting exercise starts with a visible working baseline. This baseline first proves that the script records its process ID.

It also proves that the heartbeat log grows while the process runs. You'll create this baseline with a POSIX shell script launched through sh.

In this step, get ready to:
  • Create a syntax-checked service.sh script.
  • Launch the service through sh to produce a growing heartbeat log.
  • Stop the service through its recorded process ID.
Create and validate the service script

The service needs one repeatable loop that records when it is alive. A syntax check catches shell structure problems before the loop starts.

  • Create service.sh inside linux-ops-lab by using your Linux VM's text editor to save the code below:
#!/bin/sh

RUNTIME_DIR="${1:-runtime}"
LOG_FILE="$RUNTIME_DIR/app.log"
PID_FILE="$RUNTIME_DIR/service.pid"
INTERVAL_SECONDS="${INTERVAL_SECONDS:-2}"

if test ! -d "$RUNTIME_DIR"
then
  printf 'ERROR: runtime directory not found: %s\n' "$RUNTIME_DIR"
  exit 1
fi

printf '%s\n' "$$" > "$PID_FILE"

while :
do
  printf '%s status=healthy pid=%s\n' "$(date -u)" "$$" >> "$LOG_FILE"
  sleep "$INTERVAL_SECONDS"
done

What does this script do?

  • The RUNTIME_DIR variable holds the directory supplied when the service starts.
  • The LOG_FILE variable points to the heartbeat log.
  • The PID_FILE variable points to the file that records the service process.
  • The INTERVAL_SECONDS variable sets a two-second pause between heartbeats.
  • The directory check stops the script when the requested runtime directory is missing.
  • The first formatted write stores the current shell process ID in the PID file.
  • The loop appends a healthy heartbeat with a UTC timestamp every two seconds.
  • Save service.sh.
  • Check the script's shell syntax by running:
sh -n service.sh

What should I see?

The command returns you to the terminal prompt without output when the syntax check succeeds. The heartbeat loop remains stopped during this check.

Seeing a syntax problem?

  • Compare every quote in service.sh with the script above.
  • Confirm that each if block ends with fi.
  • Confirm that the loop ends with done.

Help me diagnose my shell syntax check.

Solid start. Your service script now passes its syntax check without starting the process.

✔️ Awesome, I've got everything!

Your service.sh file is saved with the complete heartbeat loop.

ⓧ I'd like to double check the full code

#!/bin/sh

RUNTIME_DIR="${1:-runtime}"
LOG_FILE="$RUNTIME_DIR/app.log"
PID_FILE="$RUNTIME_DIR/service.pid"
INTERVAL_SECONDS="${INTERVAL_SECONDS:-2}"

if test ! -d "$RUNTIME_DIR"
then
  printf 'ERROR: runtime directory not found: %s\n' "$RUNTIME_DIR"
  exit 1
fi

printf '%s\n' "$$" > "$PID_FILE"

while :
do
  printf '%s status=healthy pid=%s\n' "$(date -u)" "$$" >> "$LOG_FILE"
  sleep "$INTERVAL_SECONDS"
done
Start and inspect the heartbeat service

A background process keeps running after the terminal prompt returns. This lets you inspect its files while the service continues writing heartbeats.

Standard output is stored in runtime/service.out. Standard error is stored in runtime/service.err.

  • Launch the heartbeat service through its interpreter by running:
sh service.sh runtime >runtime/service.out 2>runtime/service.err &

What does this command do?

  • The sh command reads and runs service.sh through the shell.
  • The runtime argument selects the directory for the PID file and heartbeat log.
  • The first redirection sends standard output to runtime/service.out.
  • The second redirection sends standard error to runtime/service.err.
  • The trailing & leaves the service running in the background.
  • Wait for at least six seconds.
  • Inspect the three most recent heartbeat records by running:
tail -n 3 runtime/app.log

What should I see?

You'll see three recent lines containing UTC timestamps. Each line contains status=healthy plus the service process ID.

Don't see heartbeat lines?

  • Confirm that you waited long enough for several two-second intervals.
  • Inspect runtime/service.err with your Linux VM's text editor for a message from the script.
  • Confirm that the empty runtime directory from the previous step still exists inside linux-ops-lab.

Help me find why my heartbeat log is missing.

There it is. Your first heartbeat service is alive and leaving a timestamped trail you can inspect.

Stop the service and confirm the log freezes

The PID file connects the stored process number to the live background service. Stopping that process gives you a clear check that the heartbeat loop has ended.

  • Stop the background service with its recorded PID by running:
kill "$(cat runtime/service.pid)"

How does this target the service?

The cat command reads the process number from runtime/service.pid. Command substitution passes that number to kill.

  • Capture the three most recent log lines for comparison by running:
tail -n 3 runtime/app.log

What does this snapshot prove?

These three lines are your comparison point after stopping the process. Their timestamps show the final recorded heartbeats.

  • Wait for at least six seconds.
  • Predict whether the three displayed heartbeat lines will change.
  • Test your prediction by rerunning the log check below:
tail -n 3 runtime/app.log

What should I see now?

You'll see the same three lines containing status=healthy plus the recorded process ID. No newer timestamps appear because the service has stopped.

Still seeing new heartbeats?

  • Confirm that runtime/service.pid contains the PID created by the latest service launch.
  • Run the stop command again if the first attempt did not return control cleanly.

Help me stop the correct heartbeat process.

That's your working baseline complete. The stopped service leaves its heartbeat evidence in runtime/app.log.

Next, you'll launch the same script the way a deployment would and use the terminal result to investigate what happens.

Reproduce the Permission Failure

Your heartbeat baseline proved that service.sh runs when the shell reads it. A deployment often launches a script directly from its file path.

Direct execution makes Linux evaluate the file's permissions before the script body can run. You will reproduce that gap before changing anything.

In this step, get ready to:
  • Reproduce the direct-launch permission failure.
  • Confirm that the failed launch writes no new heartbeat.
  • Inspect the owner permission field without changing the file.
Trigger the direct-launch failure

The baseline passed service.sh to sh as input. A direct launch makes Linux evaluate the file itself before any service code runs.

Before you run this, consider whether the script body begins or the shell stops the launch.

  • Attempt the deployment-style direct launch by running this command:
./service.sh runtime

What does this command do?

  • The ./ prefix points Linux to service.sh in your current directory.
  • Linux checks the file's execute permission before starting the interpreter named by the script.
  • The runtime argument reaches the script only when the launch succeeds.

This is the intended failure. Your terminal reports Permission denied before returning to the prompt.

The script body never runs. Your existing runtime/app.log therefore receives no new heartbeat.

Did you get a different result?

A successful launch means the file state differs from the expected baseline. Another failure can mean your terminal is in a different directory.

  • Confirm that your terminal is still connected to the Linux VM.
  • Confirm that your prompt is inside linux-ops-lab.
  • Leave service.sh unchanged before continuing.

Help me diagnose a different direct-launch result.

Inspect the file permissions

A long file listing exposes the mode used for permission checks. The owner permission field explains why direct execution stopped before the heartbeat loop.

Before you inspect the mode, predict which owner permission letter will be absent.

  • Display the long listing for service.sh by running this command:
ls -l service.sh

How do you read the result?

  • The first character identifies the filesystem entry type.
  • The next three positions show the file owner's permissions.
  • The missing x in that owner field explains the direct-launch failure.

You found the exact permission gap behind the deployment symptom. The owner field lacks x while service.sh remains unchanged.

You have turned a deployment symptom into clear permission evidence. Next, you will make the smallest repair and prove the service runs directly.

Repair and Observe the Service

The failed direct launch gave you a concrete Linux deployment symptom. Your permission listing traced it to the missing owner execute bit.

The safest repair changes only the file permissions you identified. You will then verify the live process plus its fresh heartbeats instead of assuming the repair worked.

In this step, get ready to:
  • Repair the missing owner execute permission.
  • Launch the service directly as a background process.
  • Connect the recorded process ID to fresh heartbeat records.
Repair the owner permission

The mode change can target the owner without changing group or other-user access. The symbolic mode u+x applies that narrow repair.

  • Add owner execute permission to service.sh by running this command:
chmod u+x service.sh

What does this command do?

  • The u selects the file owner.
  • The + adds the selected permission.
  • The x grants execute permission.
  • Inspect the repaired file mode by running this command:
ls -l service.sh

What does this command show?

The long listing displays the file mode alongside its owner. The owner permission field now includes x.

That focused repair closes the permission gap you reproduced. The script is now eligible for a direct launch.

Having trouble changing the mode?

  • Confirm that your terminal is still inside linux-ops-lab.
  • Check the owner column in the long listing to confirm that your current account owns service.sh.

Ask for help with the permission repair.

The permission repair changes the file mode while leaving the script contents untouched.

  • Choose the second tab if you want to compare service.sh with the unchanged target file.

✔️ Awesome, I've got everything!

Great. Your script text stays unchanged because this repair only updates its file mode.

ⓧ I'd like to double check the full code

#!/bin/sh

RUNTIME_DIR="${1:-runtime}"
LOG_FILE="$RUNTIME_DIR/app.log"
PID_FILE="$RUNTIME_DIR/service.pid"
INTERVAL_SECONDS="${INTERVAL_SECONDS:-2}"

if test ! -d "$RUNTIME_DIR"
then
  printf 'ERROR: runtime directory not found: %s\n' "$RUNTIME_DIR"
  exit 1
fi

printf '%s\n' "$$" > "$PID_FILE"

while :
do
  printf '%s status=healthy pid=%s\n' "$(date -u)" "$$" >> "$LOG_FILE"
  sleep "$INTERVAL_SECONDS"
done

Why does the code stay the same?

The file mode is metadata that controls how Linux may use the file. The chmod command updates that metadata without rewriting the shell instructions.

Launch the service directly

Execute permission lets Linux use the #!/bin/sh line to select /bin/sh as the interpreter. The service can now start through its deployment-style path.

  • Start the service as a background process by running this command:
./service.sh runtime >runtime/service.out 2>runtime/service.err &

What does this launch command do?

  • The ./service.sh runtime portion launches the repaired script directly with runtime as its directory.
  • The > redirection sends standard output to runtime/service.out.
  • The 2> redirection sends standard error to runtime/service.err.
  • The & keeps the service running after the terminal prompt returns.
  • Wait a few seconds so the service can append several heartbeat records.

Your terminal prompt returns while the service continues in the background. During startup, the script writes its current process ID to runtime/service.pid.

Did the service stop immediately?

  • Confirm that the runtime directory still exists inside linux-ops-lab.
  • Review runtime/service.err for output from the failed launch.

Ask for help diagnosing the background launch.

Connect the PID to the live service

A PID file records which process the service started. Process inspection proves that the recorded number still belongs to a running process.

  • Predict the result of both final checks.
  • Look up the process recorded in runtime/service.pid by running this command:
ps -p "$(cat runtime/service.pid)" -o pid,stat,comm

What does this process check prove?

  • The -p option selects the process whose PID comes from runtime/service.pid.
  • The -o option limits the output to pid, stat, and comm columns.

You will see a process row for the PID stored in runtime/service.pid. This confirms that the repaired service is live.

  • Inspect the three most recent heartbeat records by running this command:
tail -n 3 runtime/app.log

What does this log check prove?

The latest records connect the live process to observable application activity. Each new line contains status=healthy plus the service PID.

You will see three recent healthy heartbeats in runtime/app.log. Their timestamps show that the background service is still appending records.

Missing the process row or fresh heartbeats?

  • Confirm that runtime/service.pid contains the PID from the latest direct launch.
  • Review runtime/service.err if the process lookup returns no row.
  • Wait a few more seconds if the newest heartbeat timestamp has not advanced.

Ask for help connecting the PID to the heartbeat log.

You have now proved the complete repair. The script runs directly as a live process while fresh healthy heartbeats reach its operational log.

Your manual diagnosis now has a verified working result. Next, you will turn these process and log checks into one reusable health decision.

Automate the Health Check

Your repaired heartbeat service now runs directly in the background. Its PID file points to the live process.

Manual process checks do not scale. Manual log checks do not scale either.

A reusable health check turns both signals into one repeatable decision.

In this step, get ready to:
  • Build an executable health-check.sh script.
  • Confirm that the health check reports PASS while the heartbeat service is live.
  • Stop the service to observe FAIL. Restart it to finish with PASS.
Create the health-check script

A PID file can outlive the process it records. The script uses kill -s 0 to test process liveness without sending a signal.

  • Create health-check.sh inside linux-ops-lab by pasting this first section into your VM's existing file editor:
#!/bin/sh

RUNTIME_DIR="${1:-runtime}"
PID_FILE="$RUNTIME_DIR/service.pid"
LOG_FILE="$RUNTIME_DIR/app.log"

What does this code do?

  • The RUNTIME_DIR variable reads the runtime location from the first argument. Its default matches the existing runtime directory.
  • The PID_FILE variable points to the process ID written by service.sh.
  • The LOG_FILE variable points to the heartbeat log that proves the service is producing output.
  • Save health-check.sh.
  • Check the current file for shell syntax errors by running this command:
sh -n health-check.sh

What does this command check?

The sh -n check reads the script without executing its commands. A quiet return to the prompt means the shell found no syntax error in the current file.

Seeing a syntax problem?

Check that each variable assignment has matching double quotes. Confirm that the file starts with #!/bin/sh.

Help me inspect the opening section of my health-check shell script.

  • Add the missing PID-file guard below LOG_FILE="$RUNTIME_DIR/app.log" by pasting this code:
if test ! -f "$PID_FILE"
then
  printf 'FAIL: missing PID file: %s\n' "$PID_FILE"
  exit 1
fi

Why check the PID file first?

  • The file test prevents the script from trying to read a PID that does not exist.
  • The failure message names the missing path so an operator knows which service artifact to investigate.
  • The exit 1 line gives the failed check a nonzero exit status.
  • Save health-check.sh.
  • Validate the new guard by running the syntax check again:
sh -n health-check.sh

Why check after each section?

A syntax check after each addition keeps the test loop small. Any new problem belongs to the section you just added.

Does the PID-file guard fail validation?

Confirm that then appears after the file test. Confirm that fi closes the condition.

Help me fix the PID-file guard in my shell script.

  • Add the process-liveness check after the first fi by pasting this code:
pid="$(cat "$PID_FILE")"

if ! kill -s 0 "$pid" 2>/dev/null
then
  printf 'FAIL: process %s is not running\n' "$pid"
  exit 1
fi

How does the liveness check work?

  • The cat command reads the recorded process ID into pid.
  • The kill -s 0 probe tests whether that process exists.
  • The 2>/dev/null redirection keeps the probe's standard error out of the health-check result.
  • Save health-check.sh.
  • Validate the liveness section by running:
sh -n health-check.sh

What does a quiet result mean?

The shell returns to the prompt without reporting a syntax problem. The liveness section is ready for the next guard.

Does the liveness section have a syntax problem?

Check the nested quotes around $PID_FILE inside the command substitution. Confirm that $pid stays inside double quotes in the probe.

Help me debug the process-liveness section of my health check.

  • Add the log-file guard after the second fi by pasting this code:
if test ! -f "$LOG_FILE"
then
  printf 'FAIL: missing log file: %s\n' "$LOG_FILE"
  exit 1
fi

Why check the log file?

A live process does not guarantee that its expected log exists. This guard reports a failed health decision when the heartbeat evidence is missing.

  • Save health-check.sh.
  • Validate the log-file guard by running:
sh -n health-check.sh

What has the script proved so far?

The script now checks for both required files. It also tests whether the recorded process is alive.

Does the log-file guard fail validation?

Check that LOG_FILE is spelled the same way as its earlier definition. Confirm that this condition ends with its own fi.

Help me fix the log-file guard in my health-check script.

  • Add the successful report after the final fi by pasting this code:
latest_line="$(tail -n 1 "$LOG_FILE")"
printf 'PASS: process %s is running\n' "$pid"
printf 'Latest log: %s\n' "$latest_line"

What does the successful report include?

  • The tail -n 1 command reads the newest heartbeat into latest_line.
  • The first output line reports that the recorded process is running.
  • The second output line provides the latest log evidence for the operator.
  • Save health-check.sh.
  • Validate the complete script and add owner execute permission by running these commands:
sh -n health-check.sh
chmod u+x health-check.sh

What do these commands confirm?

The first command checks the completed file for shell syntax errors. The second command lets the file owner launch the health check directly.

Having trouble preparing the script?

If the syntax check reports a problem, compare the most recent section with the full file below. If the permission change fails, confirm that you are still inside linux-ops-lab.

Help me validate and make health-check.sh executable.

✔️ Awesome, I've got everything!

Your completed health-check.sh is saved. It also has owner execute permission.

ⓧ I'd like to double check the full code

#!/bin/sh

RUNTIME_DIR="${1:-runtime}"
PID_FILE="$RUNTIME_DIR/service.pid"
LOG_FILE="$RUNTIME_DIR/app.log"

if test ! -f "$PID_FILE"
then
  printf 'FAIL: missing PID file: %s\n' "$PID_FILE"
  exit 1
fi

pid="$(cat "$PID_FILE")"

if ! kill -s 0 "$pid" 2>/dev/null
then
  printf 'FAIL: process %s is not running\n' "$pid"
  exit 1
fi

if test ! -f "$LOG_FILE"
then
  printf 'FAIL: missing log file: %s\n' "$LOG_FILE"
  exit 1
fi

latest_line="$(tail -n 1 "$LOG_FILE")"
printf 'PASS: process %s is running\n' "$pid"
printf 'Latest log: %s\n' "$latest_line"

How to compare your file

Check each guard in order. Confirm that the successful report appears after all three checks.

Prove the live service passes

The service from the previous step is still active. Its PID file and heartbeat log give the new script everything it needs.

Before you run the check, predict whether the PID probe and latest-log report will both succeed.

  • Test the active service by running this command:
./health-check.sh runtime

What does the PASS result prove?

The line beginning with PASS: confirms that the recorded PID responds to the liveness probe.

The line beginning with Latest log: displays the newest heartbeat. You should see status=healthy in that line.

Did the live service fail the check?

  • Confirm that runtime/service.pid still contains the PID written by the running service.
  • Confirm that runtime/app.log still receives fresh heartbeat lines.

Help me diagnose why my running heartbeat service fails health-check.sh.

Test failure and recovery

A useful health check needs a known failure case. Stopping the service leaves its PID file behind.

The next check proves that the script tests the process itself.

  • Stop the live service by running this command:
kill "$(cat runtime/service.pid)"

What does this command do?

The command reads the process ID from runtime/service.pid. It asks the shell to stop that process.

The PID file remains on disk after the process stops. That stale value gives the health check a realistic failure to detect.

Before you run the check again, predict which recorded value exposes the stopped service.

  • Test the stopped service by running:
./health-check.sh runtime

This FAIL result is expected

You should see a line beginning with FAIL: because the recorded process is no longer running. The script exits before printing the latest heartbeat.

  • Restart the heartbeat service in the background by running this command:
./service.sh runtime >runtime/service.out 2>runtime/service.err &

What does the restart restore?

The service writes its new process ID to runtime/service.pid. It resumes appending healthy heartbeats to runtime/app.log.

Its regular output remains in runtime/service.out. Its errors remain in runtime/service.err.

  • Wait a few seconds for the restarted service to write fresh heartbeats.

Before your final check, predict how restarting the service changes the result.

  • Run the health check one final time:
./health-check.sh runtime

What should the final check show?

You should see PASS: followed by the restarted service's PID. The newest log line should contain status=healthy.

This final result confirms that the service is running again. It also confirms that the health check can recover after a real failure.

Does the restarted service still fail?

  • Wait a few more seconds for the service to update its PID file.
  • Confirm that you restarted service.sh from inside linux-ops-lab.

Help me restore the service to a passing health-check result.

Strong finish. Your health check now turns a PID file and heartbeat log into a repeatable operational decision.

Secret mission

Detect an Unhealthy Service

A process can stay alive while the application reports a bad state. You will add a configurable status to each heartbeat. You will enhance the health check so an unhealthy live service receives a FAIL result.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep the lab active, pause its service, or delete its files. Everything runs inside your existing Linux virtual machine with no paid resources or ongoing costs.

Resources you used:

  • The live healthy service running as a background process with its PID recorded in runtime/service.pid.
  • The owner-executable service.sh script.
  • The owner-executable health-check.sh script.
  • The runtime directory containing service.pid, app.log, service.out, and service.err.

Keep everything running

No action needed. Choose this if you want the healthy service to continue producing heartbeats for more practice.

  • The healthy service stays active inside your Linux virtual machine.
  • The runtime/app.log file keeps receiving a healthy heartbeat every 2 seconds.
  • The health-check.sh script remains ready to test process liveness plus application health.
  • Keep the Linux virtual machine available when you want to continue experimenting.

Pause - I'll come back to this later

Stop the background service to free its process slot while preserving the lab. Your scripts plus existing logs stay available for later.

  • Stop the running service by running this command:
kill "$(cat runtime/service.pid)"

What does this command do?

The command reads the recorded PID from runtime/service.pid. It sends the stop request to that process.

The service stops writing new heartbeats. Your scripts plus existing log files remain available.

  • Leave the linux-ops-lab directory in place for your next session.

Delete - I don't want to use this again

Remove the running service plus every file created for this lab. Save any heartbeat evidence you want to keep before continuing.

Check Before You Delete

Deleting the lab is permanent, so taking a moment to review its contents protects anything you still need. The sequence below stops the service before removing its directory.

  • Stop the healthy service by running this command:
kill "$(cat runtime/service.pid)"

Why Stop the Service First?

The command targets the PID stored in runtime/service.pid. Stopping that process prevents it from writing to files during deletion.

  • Review the top-level lab contents by running this command:
ls

What Should You See?

The ls command lists entries in your current directory. Confirm that you see service.sh, health-check.sh, and runtime.

  • Return to the parent directory that contains linux-ops-lab using the Linux VM terminal.
  • Remove the complete lab directory by running this command:
rm -r linux-ops-lab

What Does This Remove?

The rm -r command removes the named directory plus its contents. This deletes both shell scripts plus every PID file and log file under runtime.

  • Confirm that the lab directory is gone by running this command:
ls

Confirm the Cleanup

The directory listing should no longer include linux-ops-lab. Your Linux operations lab is now fully removed.

Nice Work!

Nice Work!

You did it! Your Linux operations lab now turns a broken-service symptom into a repeatable diagnosis.

You've learned how to:

  • Run a background heartbeat service. Capture its process ID in a PID file. Follow its progress through a growing heartbeat log.
  • Reproduce a direct-launch permission failure. Inspect the file mode to find the missing execute bit. Apply the smallest safe permission repair.
  • Automate the diagnosis with an executable health-check script. Verify process liveness through the recorded PID. Display the latest heartbeat as operational evidence.
  • Secret Mission: Distinguish a live process from a healthy application by checking the newest heartbeat status.

Ready to quiz yourself?