Search Posts on Binpipe Blog

Terraform: EC2 Instance Creation

Let's jump into creating an EC2 Instance with Terraform!

Creating the project directory

In a location of your choice, create a directory named 1-ec2-instance

Create the following directory structure (where the .tf files are blank text files):

1-ec2-instance/      -      -      -      -      - .gitignore  


This is not a required directory structure. Terraform will automatically read all `.tf` files within the directory and figure out what to do. This is a file structure that has proven effective in a production environment.


I would recommend creating a Git repository with these files. If you do so, you should start with this .gitignore content:

# Compiled files  *.tfstate  *.tfstate.backup    # Module directory  .terraform/    # Sensitive Files  /  

I recommend adding / to your .gitignore file because we're about to put some AWS secrets into it. Keeping the secrets out of Github can keep them more secure and resistent to accidents. In the future, your team may also want to use different secrets to manage permissions to different resources.

If working with a team, you can choose how you'd like these variables to be shared between each member of the team in a way that's right for you.

Here is where we'll set some variables to be re-used by the rest of the configuration. It will also serve as a handy place to keep our AWS secrets.

Let's start with these contents for the file:

# AWS Config
variable "aws_access_key" {
variable "aws_secret_key" {
variable "aws_region" {
default = "us-west-2"

Variables can have a default value that will be used if nothing is there to override them. In this case, we are utilizing default values to create reusable variables that will be utilized throughout the rest of our configuration files.

Explanation of Variables

aws_access_key - Access Key ID that allows your machine to make calls to the AWS API.

aws_secret_key - Secret Access Key that pairs with that Access Key ID

aws_region - The region in which our infrastructure is hosted (I'm using us-west-2 but you can change it if you'd like)

This file is pretty short:

provider "aws" {
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
region = "${var.aws_region}"
version = "~> 1.7"

In Terraform, Providers are interfaces to the services that maintain our Resources. For example - An EC2 Instance is a Resource provided by the Amazon Web Services Provider. A Git Repository is a Resource provided by the Github Provider.

Because Terraform is an open source tool, contributors can build custom providers to accomplish different tasks. For now, we will focus purely on the AWS provider and the resources it provides.

More specifically, we will be using version 1.7 of the AWS provider. This version will allow our configurations to work similarly on your machine - Even if the provider is updated after this chapter is written.

The AWS Provider requires an access_key (identifying the user Terraform should use) and a secret_key (authenticating the user Terraform should use). There is also an aws_region that identifies which region of the world Terraform should instantiate this infrastructure in.

This file is dedicated to finding the right Ubuntu AMI to install on our server. AMI IDs change from region to region and change over time as upgrades come out. We're going to create a data source to track down the right one.

The contents of the file are:

data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
filter {
name = "virtualization-type"
values = ["hvm"]
owners = ["099720109477"] # Canonical

A data source is a read-only view into data stored outside of Terraform. The data sources available will change based on the provider. In this case, we are creating an aws_ami data source with the unique identifier of ubuntu.

The owners of the AMI that we're looking for (the official Ubuntu AMI), will always be Amazon. Therefore, the ID stored in owners is a constant.

We are using filter tags to filter all possible AMIs in the AWS AMI repository by nameand virtualization-type.

Lastly, there will likely be multiple results when we apply all of these filters. most_recent will select the most recent of the possible AMIs and return the attributes of that for later use in our Terraform configuration.

Here's the fun part. The part that initializes the server. It's also surprisingly short:

resource "aws_instance" "my-test-instance" {
ami = "${}"
instance_type = "t2.micro"
tags {
Name = "test-instance"

With all the work we've done in the other files, all we need to do here is describe the server we want.

Let's break down what this configuration is saying:

  • We are defining an aws_instance with the unique Terraform identifier of my-test-instance

  • That instance should use the AMI found in to initialize the server

  • That instance should be a t2.micro (the cheapest AWS instance type)

  • We've attached a Name tag to the instance, test-instance, for easy identification

This server won't do much - yet. As you'll notice, we haven't installed anything on it.

We could theoretically do that through a manual process, after we create the server. But that's not in the spirit of Infrastructure as Code!

We'll start adding things to this server in the next chapter. But before that happens, let's try out Terraform!

Creating the Infrastructure

Open up bash, navigate to the project's directory, and run the following:

$ terraform init  

This will download and install the proper version of the AWS provider for your project and place it in a directory called .terraform.

You should see a message like this in response:

Initializing provider plugins...  - Checking for available provider plugins on  - Downloading plugin for provider "aws" (1.7.0)...    Terraform has been successfully initialized!    You may now begin working with Terraform. Try running "terraform plan" to see  any changes that are required for your infrastructure. All Terraform commands  should now work.    If you ever set or change modules or backend configuration for Terraform,  rerun this command to reinitialize your working directory. If you forget, other  commands will detect it and remind you to do so if necessary.  

We'll now run the command that will take the configurations we've written and use the AWS API to build our servers. This command is one that you'll be using throughout most of your time with Terraform:

$ terraform apply  

You should see a message like this in response:

An execution plan has been generated and is shown below.  Resource actions are indicated with the following symbols:    + create    Terraform will perform the following actions:      +        id:                           <computed>        ami:                          "ami-1ee65166"        associate_public_ip_address:  <computed>        availability_zone:            <computed>        ebs_block_device.#:           <computed>        ephemeral_block_device.#:     <computed>        instance_state:               <computed>        instance_type:                "t2.micro"        ipv6_address_count:           <computed>        ipv6_addresses.#:             <computed>        key_name:                     <computed>        network_interface.#:          <computed>        network_interface_id:         <computed>        placement_group:              <computed>        primary_network_interface_id: <computed>        private_dns:                  <computed>        private_ip:                   <computed>        public_dns:                   <computed>        public_ip:                    <computed>        root_block_device.#:          <computed>        security_groups.#:            <computed>        source_dest_check:            "true"        subnet_id:                    <computed>        tags.%:                       "1"        tags.Name:                    "test-instance"        tenancy:                      <computed>        volume_tags.%:                <computed>        vpc_security_group_ids.#:     <computed>      Plan: 1 to add, 0 to change, 0 to destroy.    Do you want to perform these actions?    Terraform will perform the actions described above.    Only 'yes' will be accepted to approve.      Enter a value:  

A message like this will always appear before changes are made to your infrastructure through apply. Terraform analyzes the existing resources in your AWS account and builds a plan of exactly what it will do and why. It outputs this plan and asks whether or not you'd like to make the changes.


Always read this plan carefully and take note of what's being created, modified or destroyed. This will prevent you from accidentally destroying infrastructure that does not need to be modified.

You can type yes and hit Enter to create the new server.

Congratulations! You've created your first piece of AWS infrastructure through Terraform. Welcome to the wonderful world of Infrastructure as Code!

Right now, this server doesn't do much. But we're going to start fixing that in the next chapter.

Destroying the Infrastructure

The idea of destroying infrastructure can sound a bit ominous. But, we're going to start getting rid of that ominous feeling right now. Let's destroy this server we've created!

With an established infrastructure, you are unlikely to use this next command. But destruction of resources will happen on a smaller scale, implicitly, through certain configuration changes.

Until we make this server do something in future chapters, let's destroy it to save a little money. Run the following command:

$ terraform destroy  

You should see a message like this in response: Refreshing state... (ID: i-0efdd3309c3a08f1e)    An execution plan has been generated and is shown below.  Resource actions are indicated with the following symbols:    - destroy    Terraform will perform the following actions:      -      Plan: 0 to add, 0 to change, 1 to destroy.    Do you really want to destroy?    Terraform will destroy all your managed infrastructure, as shown above.    There is no undo. Only 'yes' will be accepted to confirm.      Enter a value:  

Like with the apply command, this details exactly what is about to happen and asks you if it's what you are expecting.

You can type yes and hit Enter.


  1. I'm extremely impressed with your writting skills as well as with the layout
    oon your blog. Is this a paid theme or did you customizee it yourself?

    Either way keep up the excellent quality writing, it is rare too see a great blog like this one nowadays.

  2. I wɑs recommended this web sitе Ƅy means of my
    cousin. I'm now not sure whetһеr this ⲣublish is written by him as nobody else recognize such distinctive apρroximately my trouble.

    You ɑre incredible! Thank you!
    һe haѕ a good point : How To Lock Files In Lеss Thɑn Six Minutes
    Usіng Theѕe Amazing Tools

  3. Hi, i feel that i saw you visited my website so i got here to return the choose?.I am trying to to find things
    to improve mmy website!I guesss its ok to make use of some of your ideas!!

  4. Excelklent items from you, man. I've remember your stucf prior to and you are just too
    wonderful. I actually like what you have obtained right here, certainly like what you're saying and
    the way wherein yoou say it. You're making
    it enjoyable and you still take care of to keep it smart.

    I can not wait to read much more from you. That is actually a wonderful

  5. I'm truly enjoуing thе design and layout of your websіte.
    It's a very easү οn the eyes which makes it much more enjoyable for me to come here and visit morе often. Diԁ you hire оut a developer to crеate your
    theme? Fantastiⅽ work!
    Full Repoгt : How To Password Protect Ϝolder The Planet Using Just Your Blog

  6. Spot oon with this write-up, I honestly think this website needs
    a great deal more attention. I'll probably be returning tto read more, thanks foor the information!

  7. hey tһere and thank you for your information – I have
    certainly picked up something new from right herе.
    I did however eҳpertise several technical points using
    this site, since I experienced to reload thе site a lot of
    times previous to I could get it to load properⅼy.

    I had been wondering if your web hosting is
    OK? Not that I'm complaining, but sⅼuցgish loaɗing
    instances times will sometimes affect your placement in google and could damage your high quaⅼity sсorе if advеrtising and marketing with
    Adwords. Well I am addіng this ᏒSS to my e-mail and
    could look out for a lot morе of your respectivе intеresting content.
    Make ѕure you update this again very ѕoon.
    check that : The Ninja Guide To How To Passwߋrd Prⲟtect
    Folder Better

  8. Exϲellent post. I was checking continuoսsly this blog аnd I'm impressed!
    Extremely useful info specifically the last paгt :)
    I carе for such info much. I was looking for thiѕ partiсսlar info for a verу
    long time. Thank you and good luck.
    look at thіs web-ѕite : H᧐w To Locк Files When Nobody Else Will

  9. Gostei muito do post! Me interessa basntante esse tipo de assunto

  10. Wonderful article! We will be linking to this great content on our website.
    Keep up the great writing.

  11. Hello, for all time i used to check blog posts here early in the daylight, since i like to find out more and more.

  12. This design is steller! You definitely know how to keep a reader
    amused. Between your wit and your videos, I
    was almost moved to start my own blog (well, almost...HaHa!) Excellent job.
    I really enjoyed what you had to say, and more than that,
    how you presented it. Too cool!

  13. I all the time emailed this website post page to all my contacts, since if like to read it
    next my friends will too.

  14. Greate pieces. Keep posting such kind of information on your
    site. Im really impressed by your blog.
    Hey there, You've done a great job. I'll definitely digg it and personally recommend to my friends.

    I'm confident they will be benefited from this web site.


Hi, Leave a comment here and one of the binary piper's will reply soon :)