Save 99% on AWS EC2: Schedule Your Instance to Run Only 30 Minutes a Day
Use AWS Lambda and EventBridge to automatically start and stop EC2 instances on a precise schedule no always-on server required.
Save 99% on AWS EC2: Schedule Your Instance to Run Only 30 Minutes a Day
Use AWS Lambda and EventBridge to automatically start and stop EC2 instances on a precise schedule no always-on server required.
The Problem
I built a Telegram bot that automates my daily attendance check-in at work. The bot runs on an EC2 instance, and its job is simple:
- At 08:00, it sends me a reminder to clock in. I reply with a confirmation and an MFA code, and the bot logs into the attendance system on my behalf.
- At 17:00, it does the same thing for clocking out.
Each interaction takes about 2–3 minutes. That means my EC2 instance only needs to be alive for roughly 15 minutes in the morning and 15 minutes in the evening a total of 30 minutes per day.
Yet if I leave the instance running 24/7, I am paying for 1,440 minutes of uptime every single day, of which 1,410 minutes are completely wasted.
The Solution
The idea is straightforward. Use AWS Lambda (triggered by EventBridge on a cron schedule) to start and stop the EC2 instance at exact times:
- 07:55 Lambda starts the EC2 instance (gives it 5 minutes to boot and let Docker containers come up).
- 08:15 Lambda stops the EC2 instance (morning check-in is done).
- 16:55 Lambda starts the EC2 instance again.
- 17:15 Lambda stops the EC2 instance (evening check-out is done).
The instance is alive for two short windows on weekdays. Everything else is off. Weekends are completely off.

Cost Comparison

The Lambda invocations and EventBridge rules are covered by the AWS free tier. The scheduling infrastructure itself costs nothing.
Step 1 Write the Lambda Function
A single Python function handles both starting and stopping. The behavior is determined by an environment variable called ACTION.
import os
import boto3
import logging
log = logging.getLogger()
log.setLevel(logging.INFO)
ec2 = boto3.client("ec2", region_name=os.environ.get("AWS_REGION", "ap-southeast-1"))
INSTANCE_ID = os.environ["INSTANCE_ID"]
ACTION = os.environ["ACTION"]
def lambda_handler(event, context):
log.info(f"Action: {ACTION} | Instance: {INSTANCE_ID}")
if ACTION == "start":
ec2.start_instances(InstanceIds=[INSTANCE_ID])
return {"status": "starting", "instance": INSTANCE_ID}
elif ACTION == "stop":
ec2.stop_instances(InstanceIds=[INSTANCE_ID])
return {"status": "stopping", "instance": INSTANCE_ID}
else:
raise ValueError(f"Invalid ACTION: {ACTION}")
One codebase, deployed multiple times with different environment variables. Simple and maintainable.
Step 2 Create an IAM Role
The Lambda function needs permission to control EC2 instances. Create a role with the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeInstances"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
Steps:
- Go to IAM, then Roles, then Create Role.
- Select AWS Service and choose Lambda as the use case.
- Attach the custom policy above.
- Name the role
lambda-ec2-scheduler.
For production use, restrict the Resource field to your specific instance ARN instead of using a wildcard.
Step 3 Deploy the Lambda Functions
For this use case, you need four Lambda deployments:

For each function:
- Go to Lambda and create a new function with Python 3.12 runtime.
- Assign the
lambda-ec2-schedulerrole. - Paste the code from Step 1.
- Set the environment variables
INSTANCE_IDandACTION. - Set the timeout to 10 seconds.
Step 4 Create EventBridge Schedules
Each Lambda function gets its own cron trigger. All cron expressions in EventBridge use UTC. Adjust based on your timezone.
In my case, the local timezone is UTC+7 (Asia/Jakarta). Here is the mapping:

To create each rule:
- Go to EventBridge, then Rules, then Create Rule.
- Choose Schedule as the rule type.
- Enter the cron expression.
- Set the target to the corresponding Lambda function.
Double check your timezone offset before deploying. A one hour mistake means your instance might not be ready when your application needs it.
Step 5 Ensure Your Application Auto-Starts on Boot
When EC2 starts, your application must come up automatically without manual intervention. If you are using Docker Compose, set the restart policy:
services:
my-app:
build: .
restart: unless-stopped
Also make sure the Docker daemon is enabled on boot:
sudo systemctl enable docker
With this configuration, every time the instance boots, Docker starts, and your containers come up with it.
Step 6 Test Manually
Before relying on the schedule, verify everything end to end:
- Open one of the stop Lambda functions in the AWS console.
- Click Test with an empty event (
{}). - Confirm the EC2 instance begins stopping in the EC2 console.
- Invoke the start function and confirm the instance boots.
- SSH into the instance after boot and verify your application is running and responsive.
This setup takes five minutes and costs nothing beyond the EC2 hours you actually consume. For workloads that only need to run during specific short windows like a bot that clocks in at 8:00 and clocks out at 17:00 this approach can reduce your bill by over 98%.
Key points:
- A single Python function handles both start and stop via an environment variable.
- EventBridge cron triggers invoke Lambda at precise times.
- Docker with a restart policy ensures your application recovers automatically on boot.
- Lambda and EventBridge cost nothing under the free tier.
- The entire scheduling layer is serverless and requires no maintenance.
메타데이터
- post_id
- 6ac168f6b22e
- slug
- save-99-on-aws-ec2-schedule-your-instance-to-run-only-30-minutes-a-day-6ac168f6b22e
- url
- https://medium.com/@nitaoktaviani2005/save-99-on-aws-ec2-schedule-your-instance-to-run-only-30-minutes-a-day-6ac168f6b22e
- canonical_url
- https://medium.com/@nitaoktaviani2005/save-99-on-aws-ec2-schedule-your-instance-to-run-only-30-minutes-a-day-6ac168f6b22e
- author_url
- https://medium.com/@nitaoktaviani2005
- status
- ok
- fetched_at
- 2026-08-28 08:14:07