Stop Virtual Machine If no active SSH connections
Published on

Stop Virtual Machine If no active SSH connections


Let's say we have VM which we are accessing from the cloud, for example, Azure, AWS or GCloud, etc. Nowadays, we do most of our development in remote VM so that we don't have to configure all the dependencies in our laptops or desktop.

But a development machine doesn't have to be online 24 hours. So it makes sense to shut down our server without active users. Because these cloud providers bill the VM per minute/hour, shutting down VM when not in use could save you about 60-70% of your cloud bill.

Let me start by explaining the solution first. Then we can present the intricacies of the implemented solution.

Solution to stop cloud VM if no active SSH connections
#! /bin/bash

x=$(ss | grep -i ssh | wc -l)

if [ "$x" -gt "0" ]
    echo "SSH connection active!"
    # Ignore or add any required code.
    echo "SSH connections inactive!"
    # Code for stopping VM if inactive
    az vm deallocate --name cjvm --resource-group cjvm

In the above code, we will count the number of active SSH connections, and if it's zero, it will go to the else block, where we can write our logic to close/deallocate VM. We can then run this task as a CRON job which runs about every 30 mins or 15 minutes, etc.

Let me give an overview of this command ss | grep -i ssh | wc -l

ss - Used to dump socket statistics. It allows showing information similar to netstat. It can display more TCP and state information than other tools.

grep - Searches for Patterns in each file, and -i is an option to ignore the case.

wc - Counts newlines, words, bytes, etc. -l is an option to count lines.

So all these commands piped together would give you a count of SSH connections, which we will check with if condition to see if we need to shutdown our VM or not.

I normally do my development in Azure VM so the shut down command would be az vm deallocate --name cjvm --resource-group cjvm, where cjvm is the VM name & resource group name.

Add script as CRON job

To add a cron job, you need to type in crontab -e, which will open an editor with cron jobs. Make sure you add your script in some easily addressable location.

I've placed my script in /etc/; you can put it anywhere you like on the VM.

In the crontab file, add this one-liner at the end. I've run this task every 15 mins, so it will check if there are any SSH connections; if not, it will deallocate my VM.

You can make it every 30 minutes or 2 hours per your need, but the concept would remain the same. The VM would run a scheduled job, check for active SSH connections, and shut down if not.

# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# For more information see the manual pages of crontab(5) and cron(8)
# m h  dom mon dow   command
*/15 *  * * *  sh /etc/ | logger -t close-vm

| logger -t close-vm is needed because we can't view the logs in /var/log/syslog. To show records in the system log, you'll have to pipe them to the logger with a tag as close-vm

By doing so, you can view the logs using grep close-vm /var/log/syslog.

Dec 12 12:00:01 snrahul11 CRON[5573]: (codingjump) CMD (sh /etc/ | logger -t close-vm)
Dec 12 12:00:01 snrahul11 close-vm: SSH connection active!
Dec 12 12:45:01 snrahul11 CRON[7141]: (codingjump) CMD (sh /etc/ | logger -t close-vm)
Dec 12 12:45:01 snrahul11 close-vm: SSH connections inactive!
Dec 12 18:15:01 snrahul11 CRON[3630]: (codingjump) CMD (sh /etc/ | logger -t close-vm)
Dec 12 18:15:01 snrahul11 close-vm: SSH connection active!

Disadvantages of shutting down with this approach

If we leave the system inactive or our laptop sleeps, the SSH connection will be closed, so this script can also stop the VM. If the VM is shut down, we need to be able to power the machine with a simple command. Most cloud providers have some command which would turn on your device. I use the Azure CLI to turn on my VM (az vm start --name cjvm --resource-group cjvm)

Also, if you're going on a break, you'll need to ensure you don't leave anything unsaved. Also, there is no way to stop this scheduled job without removing this CRON entry.

This approach would work for anyone using the VM purely for development purposes with an SSH connection, i.e., Remote development using VSCode, IntelliJ, etc. However, if you want this machine to run constantly, it doesn't make sense to use this approach.


Suppose you're using a VM purely for development purposes and don't have any background or CRON jobs running. You can save a lot of money by deallocating you're VM when not in use. Furthermore, using this approach is very easy to implement your preferred time for shutting down a VM.