Automate EC2 Instance Type Switching for Cost Optimization

Managing cloud costs efficiently is one of the biggest challenges for developers and small businesses. Often, database servers like MySQL on EC2 run 24/7 — even when not in use. This leads to unnecessary billing and wasted resources. In this project, we’ll automate EC2 instance type switching based on the time of day. During low workloads (nighttime), the instance runs as t2.micro, and during active hours (daytime), it switches back to t3.microwithout manual intervention.

By leveraging AWS Lambda, EventBridge Scheduler, and Python (Boto3), we achieved ~50% monthly cost reduction while ensuring high availability and minimal downtime (1–2 minutes).

After Implementation – What We Achieved

After implementing this automated EC2 instance type switching solution, we successfully achieved a more cost-efficient, secure, and intelligent AWS environment. The automation completely eliminated the need for manual intervention in resource scaling, ensuring that the MySQL server always runs on the most optimal instance type based on actual workload demand. This change alone helped reduce the monthly EC2 cost by approximately 40–50%, without affecting application stability or performance.

Additionally, the use of AWS Lambda and EventBridge made the process fully serverless and maintenance-free, minimizing operational overhead. The automation runs reliably on schedule every day, maintaining consistent system performance during business hours and switching to low-cost operation mode at night. Because the instance uses an Elastic IP, the application remains continuously accessible, with downtime limited to just 1–2 minutes during the switch.

Security and compliance standards were also improved by implementing a least-privilege IAM role, secure credential handling, and detailed logging through CloudWatch. The project also laid a foundation for future scalability — the same framework can be replicated across multiple EC2 instances or environments, amplifying cost savings organization-wide.

In summary, this project delivered automated cost optimization, improved resource utilization, reduced human effort, and enhanced cloud operational efficiency, making it a highly practical and impactful DevOps automation initiative.

End-to-End Implementation

The goal of this project is to automatically switch the EC2 instance type of a MySQL database server every day to save costs and optimize performance — without any manual effort. At 9 AM IST, the instance will change to t3.micro for better performance during the day, and at 9 PM IST, it will switch to t2.micro for low-cost operation during the night. This automation ensures that the Elastic IP remains the same, so the application endpoint never changes. The entire process is managed by AWS Lambda functions triggered by EventBridge Scheduler, which automatically stops the instance, changes its type, and restarts it with minimal downtime


Prerequisites

Before you begin, make sure your setup is ready. Your EC2 instance should already be running on Ubuntu (or any other operating system) and have an Elastic IP (EIP) assigned so that its public IP address remains the same even after restarting. The instance should currently be of type t3.micro and host your MySQL database for your Laravel application.

You should also have the necessary permissions to create Lambda functions and EventBridge rules in AWS. Additionally, keep your EC2 instance ID (for example, i-0abcd1234567890ef) and your AWS region (such as ap-south-1 for Mumbai) handy before proceeding.


Step 1: Create IAM Role for Lambda
  1. Go to IAM → Roles → Create role

2. Choose Trusted Entity: AWS Service

3. Use case: Lambda

4. Click Next

5. Attach the following inline policy (you can create a custom one)

IAM Policy (JSON)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:StopInstances",
        "ec2:StartInstances",
        "ec2:ModifyInstanceAttribute",
        "ec2:DescribeInstances"
      ],
      "Resource": "*"
    }
  ]
}

6. Name the role → LambdaEC2ModifyRole

7. Click Create role


Step 2: Create Lambda Function for Night (Switch to t2.micro)
  1. Go to Lambda → Create Function
  2. Choose Author from scratch
  3. Function name: SwitchToT2MicroNight
  4. Runtime: Python 3.12

5.Permissions → Choose existing role → LambdaEC2ModifyRole

6.Click Create Function

Paste the following code:
import boto3
import time

ec2 = boto3.client('ec2', region_name='ap-south-1')
INSTANCE_ID = 'i-04a79857911989ab0'  # Replace with your EC2 ID

def wait_for_state(state, timeout=180):
    """Wait until instance reaches a specific state."""
    start = time.time()
    while time.time() - start < timeout:
        response = ec2.describe_instances(InstanceIds=[INSTANCE_ID])
        current_state = response['Reservations'][0]['Instances'][0]['State']['Name']
        print(f"Current state: {current_state}")
        if current_state == state:
            return True
        time.sleep(5)
    raise TimeoutError(f"Timeout waiting for state {state}")

def lambda_handler(event, context):
    print("Stopping instance...")
    ec2.stop_instances(InstanceIds=[INSTANCE_ID])
    wait_for_state("stopped")

    print("Changing instance type to t2.micro...")
    ec2.modify_instance_attribute(InstanceId=INSTANCE_ID, InstanceType={'Value': 't2.micro'})

    print("Starting instance...")
    ec2.start_instances(InstanceIds=[INSTANCE_ID])
    wait_for_state("running")

    print(" Successfully switched to t2.micro")

7. Click Deploy


Create text event and click on save

Step 3: Create Lambda Function for Morning (Switch to t3.micro)

Repeat steps from above, but name it SwitchToT3MicroMorning

and use this code:

cmd import boto3
import time

ec2 = boto3.client('ec2', region_name='ap-south-1')
INSTANCE_ID = 'i-04a79857911989ab0'  # Replace with your EC2 ID

def wait_for_state(state, timeout=180):
    """Wait until instance reaches a specific state."""
    start = time.time()
    while time.time() - start < timeout:
        response = ec2.describe_instances(InstanceIds=[INSTANCE_ID])
        current_state = response['Reservations'][0]['Instances'][0]['State']['Name']
        print(f"Current state: {current_state}")
        if current_state == state:
            return True
        time.sleep(5)
    raise TimeoutError(f"Timeout waiting for state {state}")

def lambda_handler(event, context):
    print("Stopping instance...")
    ec2.stop_instances(InstanceIds=[INSTANCE_ID])
    wait_for_state("stopped")

    print("Changing instance type to t2.micro...")
    ec2.modify_instance_attribute(InstanceId=INSTANCE_ID, InstanceType={'Value': 't3.micro'})

    print("Starting instance...")
    ec2.start_instances(InstanceIds=[INSTANCE_ID])
    wait_for_state("running")

    print(" Successfully switched to t3.micro")

Click Deploy again.

Note:-

If your lamda function fails then increase the function execution timeout from 0.3 minutes to 3 minutes to setup this go to

LamDa Function → Your function → Configuration → Edit General Configuration


Step 4: Create EventBridge (CloudWatch) Scheduled Rules
A)Night Schedule (9 PM IST → 15:30 UTC)
  1. Go to Amazon EventBridge → Rules → Create rule

Name: SwitchToT2MicroNight

Rule type: Schedule

2. Schedule pattern → Cron expression

cron(30 15 * * ? *)  # Runs daily at 9:00 PM IST
# india cron(30 3 * * ? *)

*/2 * * * ? *

3. Target: Lambda function Choose → SwitchToT2MicroNight

4.click next and create new role for event bridge

Click Create


B) Morning Schedule (9 AM IST → 03:30 UTC)
  1. Create a new EventBridge rule and name it SwitchToT3MicroMorning.
  2. In the Schedule pattern, use this cron expression: cron(30 3 * * ? *) # This means it will run every day at 9:00 AM IST
  3. Set the Target to your Lambda function named SwitchToT3MicroMorning.
  4. Finally, click Create to save the rule.

Now your automation will automatically run every morning at 9 AM (IST) and switch the instance type to t3.micro.


Step 5: Validate the Setup
  1. Open the AWS Lambda console and go to your Lambda function. Then, click on the Test button at the top.
  2. Create a new test event — you can give it any name, no special configuration is needed.
  3. Click the Test button again to run the function.

Once you run the test, the function will automatically:

  • Stop your EC2 instance
  • Change its instance type
  • Start it again
  1. Go to the EC2 Console and check your instance details. You’ll see that the instance type has been updated automatically.
  2. Because you are using an Elastic IP, your Laravel application will reconnect smoothly once the MySQL database restarts — no extra configuration needed.

Step 6: Verify Automation

Once everything is set up, you can wait for the scheduled times to check if your automation is working properly:

  • At 9 PM, your EC2 instance should automatically change to t2.micro.
  • At 9 AM, it should switch back to t3.micro.

You can confirm this in two ways:

  • Go to the CloudWatch Logs to see if the Lambda function ran successfully.
  • Or open the EC2 Console and check the Instance Type column — it should show the updated type after each schedule.

How This Project Optimizes AWS Cost

This project optimizes cost by dynamically resizing the EC2 instance based on actual usage patterns. In many production environments, database servers (like MySQL) experience high load during business hours and remain mostly idle at night. Keeping a higher-performance instance type running 24/7 leads to unnecessary costs.

Here’s how the project reduces cost effectively:

  1. Instance Type Scheduling: During the day (9 AM – 9 PM), the EC2 instance runs as a t3.micro, which provides better CPU performance for handling active user requests. During the night (9 PM – 9 AM), it automatically switches to a t2.micro, which has lower hourly cost since system usage is minimal.
  2. No Extra AWS Services Used: Instead of using AWS Lambda or EventBridge (which could incur additional costs), the scheduling is handled through cron jobs on a local Ubuntu system, making it completely free to operate.
  3. On-Demand Instance Modification: The instance type is only changed when needed, ensuring you pay for performance only when required and save cost during idle hours.
  4. Continuous Uptime Maintenance: The automation ensures minimal downtime during the stop-modify-start cycle and doesn’t require creating new instances — reducing manual operations and potential human errors.
  5. Estimated Savings: By switching between instance types, the cost reduction can range from 30% to 50% monthly, depending on usage hours and AWS region pricing.

Conclusion

In this project, we successfully automated EC2 instance type modification using AWS Lambda and Amazon EventBridge. The setup ensures that your EC2 instance automatically switches between t2.micro at night and t3.micro in the morning — helping you save costs during low-usage hours while maintaining performance during peak times.

We also used IAM roles to securely give Lambda the necessary permissions, and optionally integrated Amazon SNS for email notifications to stay informed about every instance change.

Overall, this project demonstrates how to combine AWS automation services to optimize resource usage, reduce manual work, and achieve a cost-efficient, fully automated EC2 environment — ideal for small businesses, developers, or anyone hosting applications like a Laravel MySQL server on AWS.