Stop Wasting Money: Cut Your AWS EC2 Costs by 50% with Automated Scheduling

Table of Contents

Introduction

You can save cost by turning off non-production ec2 instances when they are not needed. Automating start and stop actions using AWS Lambda and CloudWatch can save costs significantly.

Instead of scripting this from scratch, Terraform modules can help implement the solution quickly and cleanly.

In this guide, we’ll walk through using the open-source terraform-aws-lambda-auto-start-stop-ec2-instances module to automatically start and stop EC2 instances based on tags and schedule expressions. We'll use a real-world example where EC2 instances are:

  • Started at 10:00 AM IST
  • Stopped at 10:00 PM IST

This setup is useful for non-prod or testing environments that only need to be active during typical working hours.

We'll use a wrapper module available at kubenine/ec2-auto-start-stop-terraform to configure this easily using Terraform.

Problem Statement

Leaving EC2 instances running 24/7 in lower environments (like dev or QA) leads to unnecessary AWS costs. DevOps teams often need predictable and automated control over instance uptime. While AWS provides start/stop APIs, wiring it all together manually with Lambda, CloudWatch, IAM roles, and tagging logic is error-prone and repetitive.

Solution Overview

We use a Terraform module that provisions:

  • A Lambda function for EC2 start/stop
  • A CloudWatch Event Rule for scheduling
  • IAM roles and permissions

The module works by filtering EC2 instances with specific tags (e.g., ops:env = non-prod) and performing the action (start or stop) at the given time.

Diagram

Setup Instructions

1. Tag Your EC2 Instances

Ensure your instances have the required tag:

ops:env = non-prod

2. Define Terraform Modules

Use this in your main.tf:

# Start EC2 at 10:00 AM IST (4:30 AM UTC)
module "start_ec2_instances" {
  source              = "github.com/julb/terraform-aws-lambda-auto-start-stop-ec2-instances"
  name                = "StartEc2Instances"
  schedule_expression = "cron(30 4 * * ? *)"  # 10:00 AM IST
  action              = "start"
  lookup_resource_tag = {
    key   = "ops:env"
    value = "non-prod"
  }
}

# Stop EC2 at 10:00 PM IST (4:30 PM UTC)
module "stop_ec2_instances" {
  source              = "github.com/julb/terraform-aws-lambda-auto-start-stop-ec2-instances"
  name                = "StopEc2Instances"
  schedule_expression = "cron(30 16 * * ? *)"  # 10:00 PM IST
  action              = "stop"
  lookup_resource_tag = {
    key   = "ops:env"
    value = "non-prod"
  }
}

3. Apply Terraform

tf init
tf apply

Terraform will provision the Lambda functions, IAM roles, and schedules.

Notes on Timezones

AWS cron expressions always use UTC. Convert your local time to UTC before setting schedule_expression.

Local Time (IST)

UTC Equivalent

Cron Expression

10:00 AM IST

4:30 AM UTC

cron(30 4 * * ? *)

10:00 PM IST

4:30 PM UTC

cron(30 16 * * ? *)


Final Thoughts

This approach eliminates the need for custom scripts or manual scheduling. With minimal configuration, EC2 lifecycle actions are now automated and tag-driven. It's a clean way to enforce environment schedules, save on AWS costs, and reduce operational overhead.

Use this as a base and customize the schedule or tags to suit your team’s needs.