How to auto shutdown when you are not using the Cloud Virtual Machines?
Tags: aws, linux, gcp, azure
Published: 2021-10-31 06:12:13

---
title: How to auto shutdown when you are not using the Cloud Virtual Machines?
published: true
description: Sometimes, you are using AWS EC2 instances/GCP Compute Engines/Azure Virtual Machines to run complex operations on cloud. You use SSH to connect to the machines to run these complex operations like Machine Learning, Data Analysis, Video Processing and so on. You normally use those compute instance which has high processing capabilities and those usually comes with a steep cost per hour. Hence, you need them to turn off automatically once you no longer need them. Here is a way to do that.
tags: AWS, Linux, GCP, Azure
---

## Background
I always forget to turn off my virtual machines on Cloud when I am not using the computer. Because of this, I always end up paying tons for forgetting to turn it off. The cost of these instances/machines are usually $1 per hour. Hence, if I forget to turn it off for a whole day, I would incur $24.

This feels like something the machine should do itself and not burden me for remembering. Hence, I have gathered information from all over the web to make this short, simple and easy to follow guide.

## A script that checks if there is a user connecting through SSH
First, we need a script that checks if there is a user connecting through SSH and turn off the EC2 instance if there are none for a set interval of time. The following script does exactly that:

```bash
#!/bin/bash
#
# Reference: https://serverfault.com/a/1061792
# Shuts down the host on inactivity.
#
# Designed to be executed as root from a cron job.
# It will power off on the 2nd consecutive run without an active ssh session.
# That prevents an undesirable shutdown when the machine was just started, or on a brief disconnect.
#
# To enable, add this entry to /etc/crontab:
# */5 *   * * *   root    /home/<name_of_user>/dotfiles/bin/shutdown-if-inactive
#
set -o nounset -o errexit -o pipefail

MARKER_FILE="/tmp/ssh-inactivity-flag"

STATUS=$(netstat | grep ssh | grep ESTABLISHED &>/dev/null && echo active || echo inactive)

if [ "$STATUS" == "inactive" ]; then
  if [ -f "$MARKER_FILE" ]; then
    echo "Powering off due to ssh inactivity."
    rm "$MARKER_FILE"
    /sbin/shutdown -h now
  else
    # Create a marker file so that it will shut down if still inactive on the next time this script runs.
    touch "$MARKER_FILE"
  fi
else
  # Delete marker file if it exists
  rm --force "$MARKER_FILE"
fi

```

1. Save this script in a file named: `~/bin/shutdown-if-inactive.sh`

2. Don't forget to make the file executable:
```bash
chmod +x ~/bin/shutdown-if-inactive.sh
```

## Add the script to a cron job to run it every 10 minutes
1. Open up the crontab config file for the root user:

```bash
sudo crontab  -u root -e
```

Note: we need to run this cronjob as a root because shutting down requires elevated privileges.

2. Add the following line to the end of the file so that the script from above is invoked every 10 minutes:

```
*/10 * * * * /home/<name_of_user>/bin/shutdown-if-inactive.sh >> /home/<name_of_user>/bin/shutdown-if-inactive-logs  2>&1
```

Here, 
a. `*/10 * * * *` means run the script every 10 minutes at any hour, at any day, at any month and at any day of the month respectively. 
b. `/home/<name_of_user>/bin/shutdown-if-inactive.sh` is the file where we put the bash script from above. 
c. `/home/<name_of_user>/bin/shutdown-if-inactive-logs` is the file where we put the output and errors from the script.
d. `2>&1` means redirect `stderr` to `stdout`. Basically, it means, we are redirecting error stream the output stream. Combine it with `>> file_here`; and we get errors appended to the file.
e. Here, we are storing logs to be able to debug why the above script is not working properly.

3. I would recommend changing the above line to have `*/1` instead of `*/10`. This way, you can check if this whole thing works in 2 minutes instead of having to wait for the whole 20 minutes.

Please let me know in the comments if this worked for you. Thank you for reading my first post in DEV.to.