Auto Start and Stop Your EC2 Instances

Have you ever forgotten to shut down your test instances that you just used for few days and got a surprise when the monthly AWS bill came? Do you want to stop your development instances automatically at night and weekends when you don’t use them? If your answers are yes, you will want to continue reading this post.

It is fairly easy to set up a schedule to start and stop your EC2 instances automatically to control your EC2 usage. There are quite a few 3rd party providers offering this service. If you search for “EC2 schedule” or “auto start stop EC2” in google or AWS forums, you will be able to see what is available.  I list few of them in alphabetical order for your reference in case you are interested:

Of course, there is a monthly subscription fee associated with these 3rd party services, and you also need to give out your access key and secret key to the 3rd party service provider. These service providers offer more feature than just auto start and stop EC2 instances. It is probably worth using them if you are planning to use other features as well. Otherwise, it may be hard to justify when you can do it on your own without revealing your credentials to a 3rd party provider.

In fact, AWS has provided all the APIs you need to manipulate EC2 instances. That’s how these 3rd party service providers are able to manage AWS resources. It is indeed pretty straight forward.  All you really have to do is to put together a simple Python script to leverage these APIs with Boto, which are well documented and supported.

In this post, I will show you how to use a micro instance with an IAM role to start and stop your EC2 instances automatically within a region. Here are the 3 simple steps to get started:

  1. Create an IAM role
  2. Provision a micro EC2 instance
  3. Tag your instances

STEP 1: Create an IAM Role

On the IAM Management Console, go to Roles and click Create New Roles to open a wizard to start the process to create a new role. In the screenshots below, I called the IAM role as ec2-operator. You can call it whatever you want as long as you can identify it.


Type a self-explanatory name to the Role Name field. It is used for identifying your IAM role. You will need to use the name later when you create a micro EC2 instance.


On the next screen, select AWS Service Roles and then Amazon EC2.


On the next screen, select Custom Policy.


Type an arbitrary name to the Policy Name field.


Paste the following JSON block to the Policy Document field to indicate the IAM role is allowed to perform describe instances, start instances and stop instances action.

Review the role information and click Create Role to finish. The new role should be created immediately.


STEP 2: Provision a micro EC2 instance

I recommend to use a micro EC2 instance. I think it is sufficient to handle what we need here to set up a cron job to run a Python script to process auto-start and auto-stop requests, but feel free to use a different instance type.

On the EC2 Management Console, click Launch Instance to start the process to provision a micro EC2 instance. Let’s call this instance as an EC2 operator.


I recommend to select the latest Amazon Linux AMI, which has AWS tools, python and boto pre-installed.


You can pretty much take the default value for each step except on Step 3: Configure Instance Details and Step 6: Configure Security Group.

On the Configure Instance Details screen, you need to make sure you select the IAM role you created and assign it to the instance. In my case, I selected ec2-operator as the IAM role. You will not be able to change the IAM role for the instance once it is launched.


You can cut and past the following shell script  into the User Data field. It will install few Python libraries and modules, create a Python script, and set up a cron job to execute it every 5 minutes. The shell script is set to operate instances for all regions. In other words, the script will go through each region to start and stop instances.

On the Configure Security Group screen, make sure you are not open the instance to the world ( for the security group. In fact, you can get rid of the security rule. You don’t really need to SSH to the instance.

STEP 3: Tag your instances

The last step is go to EC2 Dashboard Console to tag your instances that you want to start and stop automatically at certain time. The EC2 operator instance looks for the auto:start and auto:stop tags to determine when to start and stop instances. The name of the tags are case-sensitive. The value of the tags should be in a cron format. For instance, 0 14 * * * is 2 pm everyday. The time is based on the OS time of the EC2 operator instance. If you have not changed the default time zone of the EC2 operator instance, it should be in UTC. It will ignore any instances that do not have the tags set or the format is invalid. The auto:start tag holds the start schedule, and the auto:stop tag holds the stop schedule. Do not tag the EC2 operator instance, otherwise it will get stopped by itself.


The script may not start or stop instances at the requested time exactly. For the start operation, it will start the instance between 30 minutes prior to the start time and the requested time. For the stop operation, it will stop the instance between the requested time and 30 minutes after the requested time. The EC2 operator instance is set to check every 5 minutes. It will process any auto-start and auto-stop requests few times if they have not started or stopped during the 30-minute window in case the operation does not go well.

I have been using the script for a while, and it has been performing pretty well. I am able to get all my development instances stopped during non-business hours.  I am even able to check the operations with CloudTrail to audit if the instances were indeed started and stopped within few minutes of the requested time.

This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

92 Responses to Auto Start and Stop Your EC2 Instances

  1. Tarun says:

    Are you applying this script on same instance which you want to start / stop?
    If your instance is stopped state, will the script still gets executed?

    • Shing Chen says:

      No, you cannot stop the instance that runs this script. There is a cron job in the instance running this script every 5 minutes to start/stop other instances according to the auto:start and auto:stop tag.

  2. Jonathan says:

    Great work! Curious, why is there a 30min window?

    • Shing Chen says:

      The 30 min window is to give the script few more opportunities to execute the start/stop operation in case there are network hiccups or other unexpected exceptions for the operation.

  3. Pingback: Setting up EC2 Operator Instance with CloudFormation | Shing Chen's Blog

  4. Matt says:

    I’m curious if I could make adjustments to the schedule to stop an instance over the weekend say on Friday evening and restart the instances Monday morning? Do you have any thoughts on that type of functionality?

    • Shing Chen says:

      Hi Matt,

      You should be able to schedule to stop and stop according to your requirements. You can set auto.stop to 0 20 * * 5 to indicate to stop your instance at 8 pm every Friday. You can set auto.start to 0 8 * * 1 to indicate to start your instance at 6 am every Monday. Hope it helps.


  5. rocky says:

    How to set up for the instance only running during weekdays from 8AM to 8PM but stop during weekends? Thanks.

    • Shing Chen says:

      Hi Rocky,

      You can set auto.stop to 0 20 * * 0-4 to indicate to stop your instance at 8 pm every weekday. You can set auto.start to 0 8 * * 0-4 to indicate to start your instance at 8 am every weekday. With these settings, your instance will be stopped during weekend starting 8pm Friday and start up again on Monday. Hope it helps.


  6. Shing Chen says:

    Good catch, Rocky! 0 is for Sunday, and 1 is for Monday. The auto.start and auto.stop should be set to 0 8 * * 1-5 and 0 20 * * 1-5 respectively. Thanks.

  7. Mike Lacey says:

    Note if you want to launch this instance inside a VPC, which is the norm these days, you will need to given the instance a EIP to allow outbound access to download the necessary files, and configure the security group accordingly. You can remove both once the components have been installed.

  8. I think we need to change the region in Python script? because I saw the script by logging-in using SSH to” ec2-operator” Instance, It have conn=boto.ec2.connect_to_region(‘us-east-1’), so I changed it to my region and again run the acript.
    Did I do something wrong ?

  9. on which line should I change region name, => ‘s/US-EAST-1/us-east-1/i’
    I changed this to ‘s/AP-SOUTHEAST-1/ap-southeast-1/i’

  10. Chandan says:

    Great article!
    How can I do it for Windows Instances?


  11. Stephan says:

    I have created a scheduler that runs as a windows service and allows you to:

    -start EC2 instances

    -stop EC2 instances

    -create snapshots

    You can find it here:

  12. Federico says:

    Congrats, is a great idea to store the config in the instance tags. Did you plan to add suport for elastic IP?

  13. Matt says:

    If I have an existing Linux server that I’m already running a few cron jobs on can I still use this code on it? How do I use a particular aws user that’s not setup as a role at instance creation time? Do I need to specify those credentials some how?

  14. Shing Chen says:

    You can download the python script directly from and set up a cron job to run the python script.

    If I were you, I would consider leveraging an IAM role. Unfortunately, an IAM role can only be added when you launch an EC2 instance. You may want to consider creating an AMI out of your existing EC2 instance and re-launch it from the AMI to enable an IAM role.

    If you don’t want to use IAM role, you will need to either modify line 27 – “conn=boto.ec2.connect_to_region(‘us-east-1’)” to supply your access key and secret key or add the keys to a configuration file. See and for more details.

  15. TonyPony14 says:

    This is good. Thank You. Works like a charm. Only trouble we had in the beginning was it wasn’t shutting down and starting at the correct time. And then found it was a timezone issue on the server. So just an advise to the users. Just make sure the time entries (tags) on the amazon server is in sync with the time (your local time) to make sure it happens at the correct time. sometimes we forget that some amazon servers are running at other timezones or UTC time.

  16. Oliver Rojo says:

    Hi, Shing,

    What if I have instances which are currently stopped and I don’t want to start them except only to those I need to be started. What is the tweak that I need to include into the script?


    • Shing Chen says:

      Hi Oliver,

      I don’t think you need to change the script. You just need to set the auto:start tag to the instances you want to start. For example, you an set it to * * * * * and the script will start the instances right away.


  17. Suzuki Fujimore says:

    Hi Shing,

    Accessing returns a 404 There isn’t a GitHub Page here.


  18. Shing Chen says:


    It looks like the url was changed to on the github side. I have updated to reflect the new url.


  19. Guy says:

    I have this running via Cron but, it is not picking up my tags or is not starting/stoping my instances. Where where will I find the Python logs to troubleshoot?


    • Shing Chen says:


      The Python script does not write any logs. You can edit /etc/crontab on the server to redirect outputs and errors to a log file. You should see something like this in your /etc/crontab file:

      */5 * * * * ec2-user python /home/ec2-user/

      Change it to something like it to redirect outputs and errors to /home/ec2_operator.log:

      */5 * * * * ec2-user python /home/ec2-user/ > /home/ec2-user/ec2_operator.log 2>&1


  20. Guy says:


    This was helpful, thank you!

    You can see I had a leading space on my autostart tag.

    “more ec2_operator.log | grep SSH
    us-east-1 SSHTest i-68fee293 t2.micro 2015-02-06T16:47:21.000Z stopped None None {u’Application’: u’test’, u’ auto:start’: u’* * * * *’, u’Name’: u’SSHTest’}”

    I also created a thinned out JSON that I can use in a VPC:


  21. Terje says:

    Great script, thanks.

    Only problem I had with it was the 30 minute stop window. I have added an auto stop at the end of work day, but some times we might be working late and still need the machine. It is fine that is stops the machine once, we just have to start it again. However, with the 30 minute stop window it kept turning the machine off every 5 minutes.
    To fix this I added a check against launch_time. So if launch_time > d2 it would not try to stop the machine again. That way it would stop it once and allow us to turn the machine on and continue working on it.

  22. Laurie says:

    I set this up today. I keep getting this error:
    File “/root/”, line 38
    if ‘Name’ in inst.tags else ‘Unknown’
    SyntaxError: invalid syntax

    You can’t tell it here but the carot is pointed to the letter e in else. I have not modified the file.

    • Shing Chen says:


      I downloaded the file from and ran it
      by typing “python” without the quotes from the command prompt. I was not able to reproduce the error. The line from the downloaded file was line 37 instead of line 38.

      37 name = inst.tags[‘Name’] if ‘Name’ in inst.tags else ‘Unknown’
      38 state = inst.state

      I wonder if the file was misaligned. If you share the file you downloaded, I can take a look at it.


  23. Papak says:

    I have also found this that creates you an instance from scratch with latest packages and after it is done terminates. Quite handy to have everything disposed and released. Set the time on lots of seconds and you are good to go.

  24. kiewietr says:

    Just tried this today and with some little changes, it still works perfectly

    – the way you create a new policy has changed, so first you have to create the policy and than attach it to the new role you are creating
    – the policy json format is not valid anymore, you have to add a version part, something like this:

    “Version”: “2012-10-17”,
    “Statement”: [
    “Action”: [
    “Effect”: “Allow”,
    “Resource”: “*”

  25. Brad says:


    It looks like there are now issues with the install of croniter with your script. After I installed the instance, through cloudformation or manually with the advanced setup, the start/stop doesn’t work. I SSHed into the instance, downloaded the py file and ran the command python
    It came back with an error saying:
    File “”, line 4, in
    import cronitor
    ImportError: No module named croniter.

    Thanks for providing all of your knowledge and support.


    • Brad says:


      Any thoughts on this?


      • Shing Chen says:


        Apologize for the delay. Thanks for your information. I will check it out to see why croniter was not installed.


      • Shing Chen says:


        I just launched a new EC2 Amazon linux (ami-d114f295) at us-west-1 and run the following lines to install it. I ran /home/ec2-user/ and did not get the error you saw.

        #!/bin/bash -v

        yum install -y python26-pip gcc
        pip install croniter
        wget -O $OPERATOR
        chown ec2-user:ec2-user $OPERATOR
        chmod 644 $OPERATOR
        echo "*/5 * * * * ec2-user python $OPERATOR" >> /etc/crontab

        If you are using Amazon Linux, you may need to change the installation script to reflect your favorite of Linux.


  26. scratty says:

    Great solution. Love storing the start and stop times in the tags!!

  27. Brad says:


    Thanks for your assistance. I was having problems starting and stopping instances automatically after I removed the elastic IP. Which I was never able to resolve. However I ended up running an instance on a private subnet inside a VPC that has Internet access through a NAT. That way it did not need an elastic IP.

    I really appreciate your assistance!


  28. Manjunath H says:


    Thanks for writing such a scalable script and sharing with the community.

    I got a strange issue.

    I can run your script fine in couple of accounts without any issue. But one of the accounts has been giving problems.

    Not sure if you have been contacted for this issue before. Let me give more context and error details:
    —> Script works fine for all the regions except for the eu-west-1 region.
    —> I have checked the role and also the credentials given by the role from the metadata. Its perfectly fine(Moreover the same script execution starts/stops the instance for other regions).
    —> In Eu-west-1 region, the script checks the first 5 instances’s tag value but then throws “Exception error in eu-west-1”. Every single time I see the same error and it happens only for the eu-west-1 region.
    This particular instance has about 50+ instances, so something is amiss.

    I have enabled the debug mode in the script. I can see the POST going out from the instance with the right signature and also 200 ok message from the endpoint. The script starts parsing the tag value of instances but abruptly stops after 5 instances.

    From my troubleshooting so far, I have been able to conclude that the credentials of the role is fine, the endpoint is correct, the request sent from the instance to the api endpoint is correct, api endpoint has responded back correctly.

    Though I dont think it is not creds related, I am planning to hardcode(aws configure) the creds of admin user to check if that helps.

    I am not a dev guy so not quite sure how to modify the script to run only for the eu-west-1 region. If you can help me with this, it would be awesome.

    I am also thinking of hardcoding(aws configure) the admin credentials and checking how it goes(only for testing).

    If you have any other leads on how to go about troubleshooting this, I would really appreciate it.


    • Shing Chen says:


      You can add the line “if region != “eu-west-1: break” to only run it for eu-west-1 between the line “for region in boto.ec2.regions():” and “try:”

      for region in boto.ec2.regions():
      if region != "eu-west-1: break

      I suspect you may have a special character in the value of one of the tags that break the script. The script loops through each instance in the region and examine the tags. You may want to check after which EC2 instance the script stops and compare the tags for that instance with others that were processed OK.


      • Manjunath H says:

        Thank you so much for the lead Shing. It turned out to a special character which looked like a “-” but was not a “-“(I had overlooked it thinking it was an -)
        After taking it out, the script started working fine.

  29. tester says:

    Do you a tutorial video how to Set this up please. After I select Amazon EC2, I do not see how to configure the custom policy. Thank you!

  30. Sumeet says:

    Hi Shing,
    I am trying to use your formation stack but getting error WaitCondition received failed message: ‘Failed to run cfn-init’ in us-west region.. any suggestion

    • Shing Chen says:

      I think the cloudformation template may be outdated. It has been a year old i put it together. It is probably time to update it. When I get some time, I will create a new cloudformation. Please stay tuned!

  31. Sumeet says:

    I am trying to create the this feature but its not working. I did setup manually, using CFN but still no luck.
    When i am seeing the python scrip log its stating
    time_to_action False

    i did try but still no luck.
    auto:start * * * * *
    suto:stop * * * * *

    Can you suggest further

  32. Vincent says:

    If I want the scheduler to work according to Japan time, does changing the local timezone of the ec2 operator to Japan is enough? assuming all instances being controlled are in Japan timezone.

  33. Proger says:

    I got a error with script in line
    print “%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s” % (, name,, inst.instance_type, inst.launch_time, state, start_sched, stop_sched, inst.tags)
    Script is working if i execute it in the console, but not executing by crond.
    After commented this line, all is OK.

  34. deecogowran says:

    Great Work, I’m getting not start or stops and when I run python
    I “u’aws:cloudformation:logical-id’: u’BigIpInstanceAzA1′}
    Exception error in us-gov-west-1: AWS was not able to validate the provided access credentials

    Does this point to role ? there is also load balancer and separate Auth in account .. is this possible ?

  35. deecogowran says:

    Does this support hvm images ? when I try to deploy cloudformation script and point to HVM ami it comes back with not supported error

  36. LaSalle says:


    First, thanks for a great script. I have been encountering an issue where some of my tagged instances aren’t being shut down. When I check the tags through the console, I see an error message displayed that reads “Cannot retrieve tags: Request limit reached” on the instances that were passed over. It then takes a refresh or two for the tags to appear on the screen. I assume this is in reference to the DescribeInstance API. Any suggestions on how to avoid this scenario?

    • Shing Chen says:

      Intertesting. I have been getting “Request limit reached” lately while manipulating with AWS APIs as well. I suspect AWS may have throttled api calls. It should be fine. The cronjob behind the sense runs every 5 minutes. If it fails to shutdown or start instances, it can catch up when it runs the next time.

  37. thomasspicer says:


    Thanks for the script, works great. We have a use case where an instance would be started and stopped multiple times in a day. AWS does not allow the same tags to be used more than once. This means you can have one start and stop tag. I think and ideal approach would be to allow a comma separated list of cron commands for each tag. For example:
    aws:start 44 10 * * *, 45 17 * * *
    aws:stop 43 11 * * *, 44 18 * * *

    This would allow each instance to have multiple conditions to be started and stopped. The user will need to make sure the cron commands are aligned, but the script would be able to evaluate as it does now based on what command should be run according to the statement.


    • Shing Chen says:

      Good idea. To accomplish multiple schedules, the python script can be modified to split the auto:start and auto:stop tags by comma into an array and process them.

      • Andrew says:


        Great article thanks! I’d also be interested in the multiple schedules, but not very good with Python. Has anyone been able to achieve this?


      • Shing Chen says:

        You can change line number 46 to 52 to process multiple schedules. Add a for loop above each if statement to parse multiple schedules.

        # queue up instances that have the start time falls between now and the next 30 minutes
        if start_sched != None and state == “stopped” and time_to_action(start_sched, now, 31 * 60):

        # queue up instances that have the stop time falls between 30 minutes ago and now
        if stop_sched != None and state == “running” and time_to_action(stop_sched, now, 31 * -60):

  38. stewart says:

    Great script, thanks! I have a requirement whereby I’d like to tag all un-tagged instances in a specific region used for dev (i.e. us-west-1) with the auto:stop/start tags before this script runs.

    So the process would be : check and tag all untagged instances in us-west-1, run the original script to start/stop tagged instances.

    Is this possible?

    • Shing Chen says:

      You need to update the IAM permissions of the Instance Profile. It is called something like OperatorInstanceProfile under AWS Console -> IAM -> Roles to add “ec2:CreateTags” action to grant the EC2 instance to create tags:
      You also need to modify the python script (/home/ec2-user/ On line 37 or so, you will see it loops through each region. If the region is us-west-1, add tags. Here are the pseudo code snippet:

      if == “us-west-1”
      inst.add_tag(“auto:stop”, “value goes here”);
      inst.add_tag(“auto:start”, “value goes here”);

      With the two changes above, the cron job should update all of your instances in us-west-1 with auto:stop and auto:start tags with default values in the next run. Hope it helps.

  39. Anurag Sinha says:


    when I run wget -O $OPERATOR it returns URL missing.
    when I run the script manually it stops the instance, but fails to stop automatically.
    I have used the same Script in USER DATA while launching the instance but when I SSH into it, I could not see any file. Hence I copied the content into the instance with same file name and location.
    on running manually “python”, it stops the instance, but the script is not running automatically.
    On running pip install croniter I am getting the following error – bash: pip: command not found
    Any help!

  40. Gulfam says:

    # Shing Chen,,,thanks a lot for this script

    But when I am running this script in logs i am getting this error:
    Exception error in us-east-1: No handler was ready to authenticate. 1 handlers were checked. [‘HmacAuthV4Handler’] Check your credentials

    and it is not stopping/starting my instances after tagging them like:
    auto:start 30 05 * * *
    auto:stop 30 02 * * *

    But the access credentials are ok because it is able to fetch the instance details like :

    eu-west-1 testinst1 i-dbcd3f71 m3.2xlarge 2015-09-09T04:26:45.000Z running None None {u’Name’: u’testinst1′}
    eu-west-1 Myinst i-caa1dc60 m3.medium 2015-06-08T04:55:46.000Z running 30 03 * * * 30 02 * * * {u’auto:stop’: u’30 02 * * *’, u’Name’: u’Myinst’, u’auto:start’: u’30 05 * * *’},u
    time_to_action False

    Please let me were I am going wrong

  41. Hariharan k says:

    Hi Chen,

    Great work…

    Is there a option to stop all the running instances from a particular region without providing instance details? Have to setup the cron job for the above job.

  42. Katy Stalcup says:

    Hi Shing, to your list at the top with Elastic Cloud Gate/ Skeddly/ Ylastic, you may also want to add ParkMyCloud – new, inexpensive service designed to do this exactly! Super easy to schedule on/off times, and pays for itself in under a month.

  43. Anny says:

    Please help,
    I’m use iam windows sever. I can’t do

  44. Revanth says:

    Hi Shing,

    Need a help on below:

    Do we need to change below line:

    wget -O $OPERATOR

    As I am getting a error No Suchfile or directory.


  45. Dennis says:

    interesting that I can only get it to stop using auto;stop but no matter what time I put in I can’t get any instance to start using the auto:start tag…. any ideas? Nice work, thanks for sharing!!!

  46. Hi Shing,
    This script is working is great, thank you for sharing!

    My instance stopped successfully, but didn’t start in the morning. I’ve added the log as mentioned in one of the comments above so I’ll report back to see why, but I’m wondering if it’s because of the timezone. Both the ec2-monitor and the instance to control are in the southeast region. Can you confirm how the time works in that case?

  47. Gavin says:

    Hi Shng,

    I currently have this running in EU Region only and think it works really well, but I have another region in the same AWS account that I would like to use it for. Do I need to set another Linux micro in that region and install script again or is there some way I can use the same instance??

    • Shing Chen says:

      You don’t have to set up another Linux micro instance for another region. The script does loop through each region. The same instance should be able to handle all regions.

      • Gavin says:

        OK that’s great, but what time zone are the scripts in as I have some guys in the US region who will want to setup the cron times but would be easier if this was in the US time zone if you see what I mean…any way to do this???

      • Shing Chen says:

        If you want to use US time zone, go into the EC2 instance that has the script set up and change the timezone on the OS level.

  48. Gavin says:

    What about if my EC2 instance is in the EU Ireland region….is there any way where you can use the local time for the region that you in. For example if I wanted to setup the cron for 8am-8pm Mon – Fri in EU region, and similar for US region??

  49. Gavin says:

    Hi Shing,

    I have been using your script to stop/start instances withing 2 regions now and it has been working perfectly.

    Do you know if there is a way to alter this script so that I can setup automatic backups on the instances on a daily/weekly/monthly schedule??

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s