Automate EC2 Stop and Start with EventBridge Scheduler
Two schedules, one IAM role and a describe-instances check: the AWS-native way to turn instances off at night and back on in the morning.
Amazon EventBridge Scheduler can call almost any AWS API on a timetable through what AWS calls a universal target. That makes it the shortest native route to an automatic evening stop and morning start for EC2, with no Lambda function to maintain. This guide builds exactly that pair for one set of instances, then shows how to prove it ran.
For the same job across Google Cloud and Azure, see one off-hours schedule across three clouds.
What you need first
- AWS CLI v2 with credentials that can create IAM roles (
iam:CreateRole,iam:PutRolePolicy,iam:PassRole) and schedules (scheduler:CreateSchedule). - The instance IDs you want to control, all in one Region.
- Instances whose root volume is EBS. AWS only supports stop and start for EBS-backed instances.
Check the list before you automate it. Instances inside an Auto Scaling group are a trap: AWS documents that the group treats a stopped instance as unhealthy and replaces it, so scale the group instead of stopping its members.
1. Create the execution role
EventBridge Scheduler assumes a role you own. Save the trust policy AWS publishes as trust.json:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "scheduler.amazonaws.com" }, "Action": "sts:AssumeRole" } ]}aws iam create-role --role-name ec2-offhours-scheduler \ --assume-role-policy-document file://trust.json
aws iam put-role-policy --role-name ec2-offhours-scheduler \ --policy-name start-stop \ --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["ec2:StopInstances","ec2:StartInstances"],"Resource":"arn:aws:ec2:*:*:instance/*"}]}'Narrow Resource to specific instance ARNs, or add a tag condition, if other teams share the account.
2. Create the stop schedule
A universal target ARN has the form arn:aws:scheduler:::aws-sdk:service:apiAction. For EC2 stop, that is ec2:stopInstances, and the input JSON uses the same InstanceIds field the StopInstances API takes.
aws scheduler create-schedule --name ec2-stop-weekday-evening \ --schedule-expression "cron(0 19 ? * MON-FRI *)" \ --schedule-expression-timezone "Europe/London" \ --flexible-time-window '{"Mode":"OFF"}' \ --target '{"RoleArn":"arn:aws:iam::111122223333:role/ec2-offhours-scheduler","Arn":"arn:aws:scheduler:::aws-sdk:ec2:stopInstances","Input":"{\"InstanceIds\":[\"i-0abc123def4567890\"]}"}'EventBridge Scheduler cron has six fields (minutes, hours, day-of-month, month, day-of-week, year), unlike the five-field Unix form. --schedule-expression-timezone takes a named zone, so the job follows daylight saving instead of drifting an hour twice a year. --flexible-time-window is required; OFF fires at the stated minute.
3. Create the start schedule
Repeat with the start action and a morning time:
aws scheduler create-schedule --name ec2-start-weekday-morning \ --schedule-expression "cron(0 7 ? * MON-FRI *)" \ --schedule-expression-timezone "Europe/London" \ --flexible-time-window '{"Mode":"OFF"}' \ --target '{"RoleArn":"arn:aws:iam::111122223333:role/ec2-offhours-scheduler","Arn":"arn:aws:scheduler:::aws-sdk:ec2:startInstances","Input":"{\"InstanceIds\":[\"i-0abc123def4567890\"]}"}'4. Verify the next morning
aws ec2 describe-instances --instance-ids i-0abc123def4567890 \ --query "Reservations[].Instances[].[InstanceId,State.Name]" --output textRun it after the stop time and you should see stopped; after the start time, running. For a record of who made the call, look the event up in CloudTrail (last 90 days):
aws cloudtrail lookup-events \ --lookup-attributes AttributeKey=EventName,AttributeValue=StopInstances \ --max-items 5To pause the automation, set the schedule’s state to DISABLED; to remove it, aws scheduler delete-schedule --name ec2-stop-weekday-evening.
What a stop does and does not save
AWS stops charging for the instance while it is stopped, but attached EBS volumes keep billing, and so do any Elastic IP addresses. On the way down the instance loses RAM contents, anything on instance store volumes, and an automatically assigned public IPv4 address, which changes on the next start. Private IPs, network interfaces and EBS data persist. Each start is billed with a one-minute minimum.
Where ZopNight fits
A hand-built schedule per instance list gets hard to track once there are dozens. ZopNight schedules carry a name, an IANA timezone and cron start and stop expressions, and attach to individual resources or to resource groups, with EC2 in its start/stop coverage. Engineers who need a box late can set an override that expires on its own. The account must be connected with read + write access for scheduled execution; a read-only connection still gives discovery and recommendations. The EC2 scheduling page covers the resource-specific details.