A Cloud Engineer’s Midnight Regret
It’s 00:12 AM.
You’re brushing your teeth, mentally preparing for tomorrow’s stand-up, when it hits you like a thunderbolt:
“Wait… did I forget to shut down the EC2 instances?”
You sprint back to your laptop, heart racing, praying your cloud bill isn’t already ballooning past reason.
The AWS Console loads… slowly.
You sigh in frustration.
Another night, another bill for machines you weren’t using.
If this scene feels familiar, you’re not alone. Many engineers — from solo devs to seasoned sysadmins — struggle to manage cloud resources with surgical precision, especially when those resources are needed only part of the day.
The good news?
There’s a fix — and it’s beautifully simple.
In this article, you’ll build a smart, Python-powered automation that shuts down all your EC2 instances at midnight and wakes them up at 5 AM — every day — without fail.
We’ll walk through the process step by step, with logs you can watch live and full control over your infrastructure. No serverless complexity, no expensive automation platforms.
Just you, Python, and a little crontab magic.
Let’s automate like professionals.
Prerequisites
Make sure you have the following ready:
- An AWS account with programmatic access (Access Key & Secret)
- A Linux environment (local machine, EC2 instance, or WSL on Windows)
- Python 3 installed
- boto3 and awscli installed
[Step 1: Install Required Tools]
Install the AWS SDK for Python:
pip install boto3
Configure your AWS credentials:
aws configure
You’ll be prompted to enter:
- Your Access Key ID
- Your Secret Access Key
- Default AWS region (e.g. us-east-1)
- Default output format (e.g. json)
This generates the necessary configuration under ~/.aws/credentials.
[Step 2: Write the Python Scripts]
We’ll create two Python scripts:
- stop_ec2.py → to stop instances at 00:00
- start_ec2.py → to start instances at 05:00
Let’s get started.
stop_ec2.py
mkdir ~/ec2_scheduler
cd ~/ec2_scheduler
nano stop_ec2.py
Paste the following code:
#!/usr/bin/env python3
import boto3
def stop_all_instances():
ec2 = boto3.client('ec2')
response = ec2.describe_instances(Filters=[{
'Name': 'instance-state-name',
'Values': ['running']
}])
instances_to_stop = []
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instances_to_stop.append(instance['InstanceId'])
if instances_to_stop:
print("Stopping instances:", instances_to_stop)
ec2.stop_instances(InstanceIds=instances_to_stop)
else:
print("No running instances found.")
if __name__ == "__main__":
stop_all_instances()
Make it executable:
chmod +x stop_ec2.py
start_ec2.py
Now let’s create the startup script:
nano start_ec2.py
Paste this:
#!/usr/bin/env python3
import boto3
def start_all_instances():
ec2 = boto3.client('ec2')
response = ec2.describe_instances(Filters=[{
'Name': 'instance-state-name',
'Values': ['stopped']
}])
instances_to_start = []
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instances_to_start.append(instance['InstanceId'])
if instances_to_start:
print("Starting instances:", instances_to_start)
ec2.start_instances(InstanceIds=instances_to_start)
else:
print("No stopped instances found.")
if __name__ == "__main__":
start_all_instances()
And make it executable too:
chmod +x start_ec2.py
[Step 3: Schedule Scripts Using crontab]
Open the crontab editor:
crontab -e
Add the following lines at the bottom:
0 0 * * * /usr/bin/python3 /home/isaac/ec2_scheduler/stop_ec2.py >> /home/your_user/ec2_scheduler/stop.log 2>&1
0 5 * * * /usr/bin/python3 /home/isaac/ec2_scheduler/start_ec2.py >> /home/your_user/ec2_scheduler/start.log 2>&1
Replace /home/isaac/ with your actual username or full path.
You can verify your crontab jobs were added:
crontab -l
[Step 4: Monitor with tail -f]
To watch logs in real time:
tail -f ~/ec2_scheduler/stop.log
# or
tail -f ~/ec2_scheduler/start.log
You’ll see output like:
Stopping instances: ['i-01abcd2345efgh678']
or
No stopped instances found.
IAM Policy Required
Your IAM user or role should have the following minimum permissions:
It’s a json file
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*"
}
]
}
Manual Testing (Optional)
You can manually trigger the scripts to test them before relying on the cron jobs:
python3 stop_ec2.py
python3 start_ec2.py
Then check the logs with:
tail ~/ec2_scheduler/stop.log
tail ~/ec2_scheduler/start.log
Conclusion
In this tutorial, we’ve built a clean, reliable automation to manage AWS EC2 instances using nothing but Python and Linux’s built-in cron scheduler. This setup is especially helpful for dev/test environments, overnight cost reduction, or any non-production workloads that don’t need to be running 24/7.
By combining boto3, crontab, and log monitoring with tail -f, you’ve gained fine-grained control over your cloud environment — no expensive scheduler tools, no overengineering. Just simple, effective DevOps.
Take it further by filtering EC2 instances by tags, regions, or instance types, or by sending email alerts on failures.
Automation isn’t just about convenience — it’s about discipline, consistency, and clarity in your operations.