How to Automatically Shut Down Your EC2 Instance When It Is Idle

Learn how to automatically stop your EC2 instance after a period of low CPU activity. This guide includes a simple cron-based script, Linux setup instructions, testing steps and an optional GPU-aware version.

How to Automatically Shut Down Your EC2 Instance When It Is Idle

Cloud computing gives you the flexibility to access powerful computing resources whenever you need them. However, it is easy to finish working, close your terminal and accidentally leave a machine running.

For larger EC2 instances, even a few unnecessary hours can add significantly to your cloud costs.

In this tutorial, we will create a simple script that monitors the CPU usage of an EC2 instance. If the machine remains idle for approximately one hour, the script will automatically shut it down.

Before you begin

This script is intended for Linux EC2 instances that use systemd, Bash and cron.

It will work with commonly used Linux distributions, including:

  • Ubuntu 20.04, 22.04 and 24.04
  • Debian 11 and 12
  • Rocky Linux 8 and 9
  • AlmaLinux 8 and 9
  • Red Hat Enterprise Linux 8 and 9
  • Amazon Linux 2
  • Amazon Linux 2023, after installing cron

It is not designed for Windows instances, macOS machines or older Linux systems that do not use systemd.

The script uses the sar command from the sysstat package to measure CPU activity. The sysstat package is available on both Ubuntu-based and Red Hat-based Linux distributions.

Important: This script defines an idle machine based on its total CPU usage. This is suitable for many general-purpose development and analysis machines, but it may not be appropriate for every workload. Read the considerations at the end of this article.

How the idle check works

The script will run once every five minutes using cron.

Each time it runs, it will:

  1. Measure average CPU usage over 60 seconds.
  2. Check whether CPU usage is below 2 per cent.
  3. Record another idle check if CPU usage remains below the threshold.
  4. Reset the idle counter if the machine becomes active.
  5. Shut down the machine after 12 consecutive idle checks.

Twelve checks performed five minutes apart represents approximately one hour of sustained low CPU activity.

💡
Requiring multiple consecutive checks is safer than shutting down the machine following a single low CPU measurement.

Step 1: Install the required packages

The script requires the sysstat package, which provides the sar command. You will also need cron to run the script automatically.

Ubuntu or Debian

Run:

sudo apt update && sudo apt install -y sysstat cron

Make sure cron is running:

sudo systemctl enable --now cron

Rocky Linux, AlmaLinux or Red Hat Enterprise Linux

Run:

sudo dnf install -y sysstat cronie

Make sure cron is running:

sudo systemctl enable --now crond

Amazon Linux 2

Run:

sudo yum install -y sysstat cronie

Make sure cron is running:

sudo systemctl enable --now crond

Amazon Linux 2023

Run:

sudo dnf install -y sysstat cronie

Make sure cron is running:

sudo systemctl enable --now crond
💡
Amazon Linux 2023 does not include traditional cron support by default, so the cronie package must be installed before using a crontab. AWS recommends systemd timers for Amazon Linux 2023, but cron remains available as an optional package and keeps this example simple and portable across distributions.

Step 2: Create the idle shutdown script

Create a new script:

sudo nano /usr/local/sbin/ec2-idle-shutdown.sh

Paste the following code into the file:

#!/bin/bash

# CPU usage below this percentage is considered idle.
CPU_THRESHOLD=2

# The script runs every five minutes.
# Twelve consecutive idle checks represents approximately one hour.
REQUIRED_IDLE_CHECKS=12

# This file stores the number of consecutive idle checks.
STATE_FILE="/tmp/ec2-idle-count"

# Measure the machine's average CPU idle percentage over 60 seconds.
# LC_ALL=C ensures that sar returns consistent English output.
CPU_IDLE=$(LC_ALL=C sar -u 60 1 | awk '/Average:/ && $2 == "all" {print $NF}')

# Exit without shutting down if CPU usage could not be measured.
if [ -z "$CPU_IDLE" ]; then
    logger -t ec2-idle-shutdown "Could not determine CPU usage."
    exit 1
fi

# Convert the CPU idle percentage into CPU usage.
CPU_USAGE=$(awk -v idle="$CPU_IDLE" 'BEGIN {print 100 - idle}')

# Check whether CPU usage is below the configured threshold.
IS_IDLE=$(awk -v usage="$CPU_USAGE" -v threshold="$CPU_THRESHOLD" \
    'BEGIN {print usage < threshold}')

if [ "$IS_IDLE" -eq 1 ]; then

    # Start the idle counter at zero if no previous count exists.
    IDLE_COUNT=0

    # Read the previous idle count from the state file.
    if [ -f "$STATE_FILE" ]; then
        IDLE_COUNT=$(cat "$STATE_FILE")
    fi

    # Add one to the number of consecutive idle checks.
    IDLE_COUNT=$((IDLE_COUNT + 1))
    echo "$IDLE_COUNT" > "$STATE_FILE"

    # Record the result in the system log.
    logger -t ec2-idle-shutdown \
        "CPU usage is ${CPU_USAGE}%. Idle check ${IDLE_COUNT}/${REQUIRED_IDLE_CHECKS}."

    # Shut down after approximately one hour of continuous low CPU usage.
    if [ "$IDLE_COUNT" -ge "$REQUIRED_IDLE_CHECKS" ]; then
        logger -t ec2-idle-shutdown \
            "Machine has been idle for approximately one hour. Shutting down."

        rm -f "$STATE_FILE"
        systemctl poweroff
    fi

else

    # The machine is active, so reset the idle counter.
    echo 0 > "$STATE_FILE"

    logger -t ec2-idle-shutdown \
        "CPU usage is ${CPU_USAGE}%. Idle counter reset."
fi

Save the file and exit the editor.

In Nano, press Ctrl+X, followed by Y and Enter, to save the file and exit.

💡
If you are using GPUs, please see our GPU-aware version of this script in the important considerations section below.

Step 3: Make the script executable

Run:

sudo chmod 700 /usr/local/sbin/ec2-idle-shutdown.sh
💡
The script must run as the root user because shutting down the operating system requires administrative permissions.

Step 4: Test the script manually

Before configuring the automatic schedule, run the script manually:

sudo /usr/local/sbin/ec2-idle-shutdown.sh

The script waits for 60 seconds while it measures CPU usage. It then writes the result to the Linux system journal.

You can then view its most recent log entries with:

sudo journalctl -t ec2-idle-shutdown

You should see a message similar to:

CPU usage is 0.75%. Idle check 1/12.

If the machine was busy during the test, you may instead see:

CPU usage is 8.25%. Idle counter reset.

You can view the current idle count by running:

cat /tmp/ec2-idle-count

Step 5: Run the script automatically

Open the root user’s crontab:

sudo crontab -e

Add the following line to the bottom of the file:

*/5 * * * * /usr/local/sbin/ec2-idle-shutdown.sh

This tells cron to run the script every five minutes.

Because each execution also spends 60 seconds measuring CPU activity, the exact shutdown time will vary slightly. The machine will normally shut down after approximately one hour of sustained inactivity.

Changing the idle period

The default configuration runs every five minutes and requires 12 idle checks:

REQUIRED_IDLE_CHECKS=12

You can adjust this value to change how long the machine must remain idle.

For example:

Idle period Required checks
30 minutes 6
1 hour 12
2 hours 24
4 hours 48
8 hours 96

These examples assume the cron job continues to run every five minutes.

For example, to shut down after approximately two hours, change the script to:

REQUIRED_IDLE_CHECKS=24

Changing the CPU threshold

The following setting defines how much CPU activity is allowed before the machine is considered active:

CPU_THRESHOLD=2

The default value means that total CPU usage below 2 per cent is considered idle.

💡
A 2% threshold is generally suitable for small and medium general-purpose machines with up to around 16 vCPUs. For instances with 32 vCPUs or more, consider using a lower threshold such as 1%, as a single active process may represent only a small percentage of total CPU capacity.

To use a 5 per cent threshold instead, change it to:

CPU_THRESHOLD=5

Be cautious when changing this value. A higher threshold increases the chance that the machine will be shut down while a low-intensity process is still running.

Cancelling the idle countdown

To reset the idle counter manually, run:

sudo rm -f /tmp/ec2-idle-count

The next execution will begin counting from zero again.

To disable the automatic shutdown completely, open the root crontab:

sudo crontab -e

Remove or comment out the following line:

*/5 * * * * /usr/local/sbin/ec2-idle-shutdown.sh

You can comment it out by adding a # to the beginning:

# */5 * * * * /usr/local/sbin/ec2-idle-shutdown.sh

Important considerations

CPU usage does not represent every type of activity

This script only monitors aggregate CPU usage. It does not directly check:

  • GPU utilisation
  • Disk activity
  • Network transfers
  • Logged-in users
  • Jupyter notebook sessions
  • Queued or paused jobs
  • Applications waiting for user input
  • Unsaved files or editor sessions

A machine can therefore appear CPU-idle while it is still performing useful work.

Be careful with large instances

Aggregate CPU usage is calculated across all available virtual CPUs.

For example, a process fully using one CPU on a 96-vCPU instance may represent only slightly more than 1 per cent of the machine’s total CPU capacity. With the default 2 per cent threshold, that instance could still be classified as idle.

For machines with a large number of CPUs, consider reducing the threshold:

CPU_THRESHOLD=1

You should test the threshold against representative workloads before relying on the script.

GPU instances need additional monitoring

A GPU workload may use the GPU heavily while recording very little CPU activity. For this reason, the CPU-only script should not be used on NVIDIA GPU instances unless GPU utilisation is also checked.

You can use nvidia-smi, which is installed with the NVIDIA GPU driver, to measure GPU activity.

First, confirm that it is available:

nvidia-smi

If this command displays information about the GPU, driver and utilisation, you can use the following GPU-aware version of the script.

#!/bin/bash

# CPU usage below this percentage is considered idle.
CPU_THRESHOLD=2

# GPU usage below this percentage is considered idle.
GPU_THRESHOLD=2

# Twelve checks, five minutes apart, represents approximately one hour.
REQUIRED_IDLE_CHECKS=12

# Stores the number of consecutive idle checks.
STATE_FILE="/tmp/ec2-idle-count"

# Measure average CPU idle percentage over 60 seconds.
CPU_IDLE=$(LC_ALL=C sar -u 60 1 | awk '/Average:/ && $2 == "all" {print $NF}')

# Exit if CPU usage could not be measured.
if [ -z "$CPU_IDLE" ]; then
    logger -t ec2-idle-shutdown "Could not determine CPU usage."
    exit 1
fi

# Convert CPU idle percentage into CPU usage.
CPU_USAGE=$(awk -v idle="$CPU_IDLE" 'BEGIN {print 100 - idle}')

# Exit safely if NVIDIA GPU monitoring is not available.
if ! command -v nvidia-smi >/dev/null 2>&1; then
    logger -t ec2-idle-shutdown \
        "nvidia-smi is not available. GPU usage cannot be checked."
    exit 1
fi

# Measure the highest utilisation reported by any NVIDIA GPU.
GPU_USAGE=$(nvidia-smi \
    --query-gpu=utilization.gpu \
    --format=csv,noheader,nounits |
    awk 'BEGIN {max=0} {if ($1 > max) max=$1} END {print max}')

# Exit safely if GPU usage could not be measured.
if [ -z "$GPU_USAGE" ]; then
    logger -t ec2-idle-shutdown "Could not determine GPU usage."
    exit 1
fi

# The machine is idle only when both CPU and GPU usage are below
# their configured thresholds.
IS_IDLE=$(awk \
    -v cpu="$CPU_USAGE" \
    -v cpu_threshold="$CPU_THRESHOLD" \
    -v gpu="$GPU_USAGE" \
    -v gpu_threshold="$GPU_THRESHOLD" \
    'BEGIN {
        print (cpu < cpu_threshold && gpu < gpu_threshold)
    }')

if [ "$IS_IDLE" -eq 1 ]; then

    # Read the previous idle count, or start at zero.
    IDLE_COUNT=0

    if [ -f "$STATE_FILE" ]; then
        IDLE_COUNT=$(cat "$STATE_FILE")
    fi

    # Add one consecutive idle check.
    IDLE_COUNT=$((IDLE_COUNT + 1))
    echo "$IDLE_COUNT" > "$STATE_FILE"

    logger -t ec2-idle-shutdown \
        "CPU usage is ${CPU_USAGE}%. GPU usage is ${GPU_USAGE}%. Idle check ${IDLE_COUNT}/${REQUIRED_IDLE_CHECKS}."

    # Shut down after approximately one hour of continuous inactivity.
    if [ "$IDLE_COUNT" -ge "$REQUIRED_IDLE_CHECKS" ]; then
        logger -t ec2-idle-shutdown \
            "Machine has been idle for approximately one hour. Shutting down."

        rm -f "$STATE_FILE"
        systemctl poweroff
    fi

else

    # Reset the idle counter whenever CPU or GPU activity is detected.
    echo 0 > "$STATE_FILE"

    logger -t ec2-idle-shutdown \
        "CPU usage is ${CPU_USAGE}%. GPU usage is ${GPU_USAGE}%. Idle counter reset."
fi

This version checks the highest utilisation across all NVIDIA GPUs on the instance. The machine is considered idle only when both CPU and GPU utilisation remain below their configured thresholds.

If nvidia-smi is unavailable or GPU usage cannot be measured, the script exits without shutting down the machine. This is safer than assuming GPU usage is zero.

You should still use caution with GPU workloads. GPU utilisation can briefly fall to zero between training stages, data-loading steps or interactive notebook activity. Requiring several consecutive idle checks reduces this risk, but it does not eliminate it completely.

GPU memory usage can also remain allocated while compute utilisation is low. For long-running training, rendering or research workloads, consider adding workload-specific checks before enabling automatic shutdown.

Save your work to persistent storage

A graceful shutdown does not protect unsaved data held only in memory.

Data stored on attached EBS drives is retained when an EBS-backed instance stops. However, data stored on instance-store volumes is erased when the instance stops. Make sure you copy anything you need to retain to persistent storage such as an attached EBS drive or an S3 bucket.

Summary

An automatic idle-shutdown script provides a useful safety net for machines that users may occasionally forget to stop.

Once configured, the script:

  • monitors CPU activity automatically;
  • requires sustained inactivity rather than reacting to one measurement;
  • resets its countdown whenever the machine becomes active; and
  • gracefully shuts down the operating system after the selected idle period.

It is still important to check that the CPU threshold is appropriate for your workload and that important data is stored on persistent storage.

With these safeguards in place, you can reduce unnecessary EC2 runtime without needing to constantly monitor whether every machine has been switched off.