How to Create Linux AWS EC2 Instance using Terraform

How to Create Linux AWS EC2 Instance using Terraform. In this post, we will introduce Terraform, its features and major advantages. We will then show you how to create a Linux instance on AWS using the Terraform.

So let’s start with How to Create Linux AWS EC2 Instance using Terraform.

What is Terraform?

HashiCorp found a tool called Terraform that helps system administrator to manage the infrastructure of an application. Basically a tool for infrastructure provisioning. Generally speaking  infrastructure is what your application is based on, from its functioning to its graphics and UI. Everything is dependent and decided by the infrastructure of that application.

What it does it keeps the infrastructure in a compliant state. Extremely important and necessary to provision the infrastructure in order to make the application work. This includes creating a VPC, spinning up the servers, creating AWS users and sanctioning the permissions and installing dockers, if necessary. With Terraform, you deploy all of this needs in the correct order and in the correct manner because the tasks might be dependent on one another.

Features of Terraform

First of all Terraform has various features that allow it to function the way it is meant to be. These features allow it to carry out all its necessary functions. Following are some important features of Terraform:

  • Consists of all the features of Infrastructure as Code (IaC). They help to improve speed and reliability, prevent configuration drift and support experimenting, testing and optimizations.
  • Open source tool which makes it widely accessible, increases its speed and makes it much more reliable than the alternatives.
  • Regardless of the version of cloud storage in use, it is extremely easy to find plug ins and extensions. This allows Terraform to easy adapt to new modifications and benefits making it more consistent. Additionally it also means that you can use it with any cloud storage service provider.
  • Let’s users create infrastructure. Meaning that it let’s the user to decide what will the application look like when it comes out and gives control to the user over every aspect.
  • Allows users to makes changes to the infrastructure in case if the user decides to add more microservices to the infrastructure due to addition of new features.
  • Also the Terraform allows the users to replicate the infrastructure which further allows the users to replicate a production environment. At the same time it makes it possible to keep the original development environment.
  • Includes a graphical user interface for managing all running services. The Terraform also includes a model for access control based on the organisation, teams and users. Besides Its audit logging generates logs whenever there is a change in the infrastructure.

Benefits of Terraform

Here are some of the biggest advantages of Terraform which make it superior to its other alternatives out there:

Platform Agnostic

Platform agnostic, meaning, it does not matter what heterogenous platform is use. But it still allows the user to define all the resources in Terraform. This makes Terraform extremely compatible and practical.

Tendency to maintain the state of infrastructure

Whenever you initialize project, the state files created remain the same throughout the process while using Terraform. No alteration of the state of infrastructure allowing it to be more consistent and reliable.

Consists of a feature called “Terraform Plan”

This feature allows the user to verify the creation resource. Brings up the whole layout and lets the user to verify the creation by showing how the resource creation is going to take place.

Desired State

Delivers the desired state, it does it when the user provides it with a declarative configuration of the things the user wants.

Repeatable and auditable

Repeatable and auditable tool and is multi environment platform through these plugins such as AWS, Azure and Google Cloud.

No requirement for any separate documentation

You can write infrastructure code in a simple text documents. Why? Because Terraform is procedural in nature and let’s users see what is deployed at the moment and what is its configuration.

No need of Master Node

You can say that Terraform is masterless, meaning it maintains the record of all the configs and updates. Because it does not specifically require a master node. Besides it has the ability to deliver infrastructure at quicker speeds with less manual intervention.

This is the main part is now: How to Create Linux AWS EC2 Instance using Terraform.

How to Create Linux AWS EC2 Instance using Terraform


To follow this guide, you need the following:

  • AWS IAM credentials with permissions to manage EC2 instances – access key and secret key
  • A CentOS or Ubuntu operating system installed on your local machine.

Install Terraform

Before starting, you will need to install Terraform on your local machine.

Follow the below steps to install the Terraform on Ubuntu and Debian based operating systems.

First, install the Curl utility with the following command:

					sudo apt install curl -y

Next, download and add the Terraform GPG key with the following command:

					curl -fsSL | sudo apt-key add -

Add the Terraform repository to the APT using the following command:

					sudo apt-add-repository "deb [arch=amd64] $(lsb_release -cs) main"

Run the following command to install the Terraform:

					sudo apt-get install terraform -y

Verify the Terraform version using the following command:

					terraform --version

You should see the Terraform version in the following output:

					Terraform v1.2.8
on linux_amd64

Follow the below steps to install the Terraform on CentOS, RHEL and Rocky Linux operating systems.

					sudo yum install -y yum-utils
sudo yum-config-manager --add-repo
sudo yum -y install terraform

Create an SSH Key

You will need to create an SSH key to connect your AWS EC2 instance from your local machine.

					ssh-keygen -t rsa -f ~/.ssh/aws 

This will creates an SSH key named aws in the .ssh directory:

					Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/aws.
Your public key has been saved in /root/.ssh/
The key fingerprint is:
SHA256:8gkviFGqM8mDLI9r5LapgLZO05bf5JBOe+vwuFFchEw root@vyompc
The key's randomart image is:
+---[RSA 2048]----+
|      oE..       |
|       o.        |
|    .    .       |
|   o  . .        |
|  o   ooS        |
|=+.o..o= .       |
|%B.+.*..+        |
|=O* + @o         |
|O*o  *+*.        |

Create Terraform Project Structure

Before starting, you will need to create a directory structure to store your Terraform configuration.

First, create a directory named AWS with the following command:

					mkdir AWS

Navigate to the AWS directory with the following command:

					cd AWS

Create empty Terraform configuration files:


Define Cloud Provider and Credentials

Mainly you will need to edit the configuration file and define your cloud provider and their credential to access it.


Define your AWS access key, secrete key, region and Terraform version as shown below:

					provider "aws" {
  region = "ap-south-1"
  access_key = "YOUR-ACCESS-kEY"
  secret_key = "YOUR-SECRET-KEY"


terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.37.0"


Save and close the file after you finish.

Define SSH Key Pair

After that edit the configuration file and define your SSH public key and VPS:

					resource "aws_key_pair" "key" {
  key_name   = "hitesh_key"
  public_key = file("~/.ssh/")

resource "aws_default_vpc" "default_vpc" {



Define Security Group

In this step you will need to define the security group and allow SSH inbound traffic to access the VPS via SSH protocol from the remote machine:

					resource "aws_security_group" "allow_ssh" {
  name        = "allow_ssh"
  description = "Allow ssh inbound traffic"
  # using default VPC
  vpc_id      =

  ingress {
    description = "TLS from VPC"
    # we should allow incoming and outoging
    # TCP packets
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    # allow all traffic
    cidr_blocks = [""]

  tags = {
    Name = "allow_ssh"


Define EC2 Image and Operating System

Next, define the AWS instance type, image and operating system:

					resource "aws_instance" "ec2_instance" {
  ami             = var.ami_id
  instance_type   = "t2.micro"
  # refering key which we created earlier
  key_name        = aws_key_pair.key.key_name
  # refering security group created earlier
  security_groups = []

  tags = var.tags

variable "ami_id" {
  description = "Ubuntu ami id"
  # Amazon linux image
  default     = "ami-0a23ccb2cdd9286bb"

variable "tags" {
  type = map(string)
  default = {
    "name" = "Hitesh's ec2"


Print Useful Information

Define the following variable to print useful information like, the Public IP of EC2 instance.

					output "arn" {
  value = aws_instance.ec2_instance.arn

output "public_ip" {
  value = aws_instance.ec2_instance.public_ip


Deploy An EC2 Instance

At this point, Terraform configuration files are ready to deploy the EC2 instance.

Initialize Terraform Plugin

Eventually at this step initialize the terraform’s AWS plugin to fetch all information from the AWS. You can do it using the terraform init

					terraform init

You should see the following output:

					Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.44.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* version = "~> 3.37.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.


Check Terraform Plan

Please check your infrastructure plan to test your configuration. You can check it using the terraform plan command:

					terraform plan

You should see the following output:

					Terraform used the selected providers to generate the following execution plan. 
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_default_vpc.default_vpc will be created
  + resource "aws_default_vpc" "default_vpc" {
      + arn                              = (known after apply)
      + assign_generated_ipv6_cidr_block = (known after apply)
      + cidr_block                       = (known after apply)
      + default_network_acl_id           = (known after apply)
      + default_route_table_id           = (known after apply)
      + default_security_group_id        = (known after apply)
      + dhcp_options_id                  = (known after apply)
      + enable_classiclink               = (known after apply)
      + enable_classiclink_dns_support   = (known after apply)
      + enable_dns_hostnames             = (known after apply)
      + enable_dns_support               = true
      + id                               = (known after apply)
      + instance_tenancy                 = (known after apply)
      + ipv6_association_id              = (known after apply)
      + ipv6_cidr_block                  = (known after apply)
      + main_route_table_id              = (known after apply)
      + owner_id                         = (known after apply)
      + tags_all                         = (known after apply)

  # aws_instance.ec2_instance will be created
  + resource "aws_instance" "ec2_instance" {
      + ami                          = "ami-0a23ccb2cdd9286bb"
      + arn                          = (known after apply)
      + associate_public_ip_address  = (known after apply)
      + availability_zone            = (known after apply)
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "t2.micro"
      + ipv6_address_count           = (known after apply)
      + ipv6_addresses               = (known after apply)
      + key_name                     = "hiteshs_key"
      + outpost_arn                  = (known after apply)
      + password_data                = (known after apply)
      + placement_group              = (known after apply)
      + primary_network_interface_id = (known after apply)
      + private_dns                  = (known after apply)
      + private_ip                   = (known after apply)
      + public_dns                   = (known after apply)
      + public_ip                    = (known after apply)
      + secondary_private_ips        = (known after apply)
      + security_groups              = [
          + "allow_ssh",
      + source_dest_check            = true
      + subnet_id                    = (known after apply)
      + tags                         = {
          + "name" = "hitesh's ec2"
      + tenancy                      = (known after apply)
      + vpc_security_group_ids       = (known after apply)

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)

      + enclave_options {
          + enabled = (known after apply)

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)

  # aws_key_pair.key will be created
  + resource "aws_key_pair" "key" {
      + arn         = (known after apply)
      + fingerprint = (known after apply)
      + id          = (known after apply)
      + key_name    = "hiteshs_key"
      + key_pair_id = (known after apply)
      + public_key  = "ssh-rsa "

  # aws_security_group.allow_ssh will be created
  + resource "aws_security_group" "allow_ssh" {
      + arn                    = (known after apply)
      + description            = "Allow ssh inbound traffic"
      + egress                 = (known after apply)
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "",
              + description      = "TLS from VPC"
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
      + name                   = "allow_ssh"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags                   = {
          + "Name" = "allow_ssh"
      + vpc_id                 = (known after apply)

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + arn       = (known after apply)
  + public_ip = (known after apply)


Note: You didn't use the -out option to save this plan, 
so Terraform can't guarantee to take exactly these actions 
if you run "terraform apply" now.


Deploy EC2 Instance

Finally, run the terraform apply command to create your EC2 instance on AWS:

					terraform apply

You should get the following output:

					aws_security_group.project-iac-sg: Creating...
aws_security_group.project-iac-sg: Still creating... [10s elapsed]
aws_security_group.project-iac-sg: Creation complete after 15s [id=sg-0fd7db3ea267c2527]
aws_instance.project-iac: Creating...
aws_instance.project-iac: Still creating... [10s elapsed]
aws_instance.project-iac: Still creating... [20s elapsed]
aws_instance.project-iac: Still creating... [30s elapsed]
aws_instance.project-iac: Creation complete after 31s [id=i-0d93c366fb2c4a3eb]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate


public_ip =

As you can see, your EC2 instance is created with public IP You can now connect to your EC2 machine via SSH:

					ssh -i ~/.ssh/aws ec2-user@

Cleanup Infrastructure

You can delete and destroy your EC2 instance using a single command:

					terraform destroy

Thank you for reading How to Create Linux AWS EC2 Instance using Terraform.

How to Create Linux AWS EC2 Instance using Terraform Conclusion

In this post, we showed you how to create an EC2 instance using the Terraform. Summing up Terraform is very useful tool that allows system administrators to automate all configuration on AWS, Azure and other cloud providers. It is a popular code tool that lets the users define resources, either cloud or on-prem, in reusable and shareable files which are in a configuration that is readable by a human being.

Take a look at more terraform content in our blog over here.

Avatar for Hitesh Jethva
Hitesh Jethva

I am a fan of open source technology and have more than 10 years of experience working with Linux and Open Source technologies. I am one of the Linux technical writers for Cloud Infrastructure Services.

0 0 votes
Article Rating
Notify of
Inline Feedbacks
View all comments
Would love your thoughts, please comment.x