Launch Public and Private Subnet in a VPC using Terraform

In this article, we will discuss how to launch a website(WordPress site) by considering the security measures. This project has the following key points:

  1. Deploying a WordPress site in a Public Subnet
  2. Deploying a MySQL database in a Private Subnet

Let’s start the project by writing a Terraform code in a file.

  • Configuring AWS:
// Configuring the provider information
provider "aws" {
region = "ap-south-1"
profile = "ankush"

Specifying the provider we are going to use(in my case AWS), default region, and the profile. The profile contains all of the credentials to log in to the AWS.

Crating new Profile: Run the following command and follow the steps.

$ aws configure --profile ankush
  • Creating Private EC2 Key-Pair:
// Creating the EC2 private keyvariable "key_name" {default = "Terraform_vpc"}resource "tls_private_key" "ec2_private_key" {algorithm = "RSA"rsa_bits  = 4096provisioner "local-exec" {command = "echo '${tls_private_key.ec2_private_key.private_key_pem}' > ~/Desktop/task2/${var.key_name}.pem"}}// Making the access of .pem key as a privateresource "null_resource" "key-perm" {depends_on = [tls_private_key.ec2_private_key,]provisioner "local-exec" {command = "chmod 400 ~/Desktop/task2/${var.key_name}.pem"}}module "key_pair" {source = "terraform-aws-modules/key-pair/aws"key_name   = var.key_namepublic_key = tls_private_key.ec2_private_key.public_key_openssh}

Above code will create a private EC2 Key-Pair named Terraform_vpc

  • Creating a VPC:

Creating a VPC with the CIDR block length

resource "aws_vpc" "myVpc" {cidr_block       = ""instance_tenancy = "default"tags = {Name = "my-vpc"}enable_dns_hostnames = true}
  • Creating Subnet:

Now, we will create two subnets in a VPC named my-vpc. Out of these two subnets, one subnet is a public subnet and another is a private subnet. The public subnet have access to the internet where the private subnet is isolated.

Let's create a public subnet named my-subnet1

resource "aws_subnet" "mySubnet1" {depends_on = [aws_vpc.myVpc,]vpc_id     = "${}"cidr_block = ""availability_zone_id = "aps1-az1"tags = {Name = "my-subnet1"}map_public_ip_on_launch = true}

In this public subnet, we will launch the WordPress site.

Now, create private subnet named my-subnet2

resource "aws_subnet" "mySubnet2" {depends_on = [aws_vpc.myVpc,]vpc_id     = "${}"cidr_block = ""availability_zone_id = "aps1-az1"tags = {Name = "my-subnet2"}}

In this private subnet, we will launch the MySQL database.

  • Creating an Internet Gateway and Route table:

Until now, we had set up labs(Subnet) for our WordPress site. For providing Internet connectivity inside public subnet we required to create an Internet Gateway. So, let’s create Internet Gateway inside the my-vpc.

resource "aws_internet_gateway" "myInternetGateway" {depends_on = [aws_vpc.myVpc,]vpc_id = "${}"tags = {Name = "my-internet-gateway"}}

The above code will create an Internet Gateway named my-internet-gateway.

After that create a Route Table and associate this Route table with the public subnet(my-subnet1).

resource "aws_route_table" "myRouteTable" {depends_on = [aws_vpc.myVpc,aws_internet_gateway.myInternetGateway,]vpc_id = "${}"route {cidr_block = ""gateway_id = "${}"}tags = {Name = "my-route-table"}}

Now, the Route Table named my-route-table is created.

Associate this route table with the public subnet.

resource "aws_route_table_association" "associateRouteTableWithSubnet" {depends_on = [aws_subnet.mySubnet1,aws_route_table.myRouteTable,]subnet_id      = aws_subnet.mySubnet1.idroute_table_id =}

Finally, the complete lab for launching a WordPress site is set up successfully.

  • Creating Security Groups for WordPress and MySQL Instances:

Security Group for WordPress Instance:

As we know, WordPress works on port 80 by default. So, we will allow inbound traffic from port 80. Also, for management purposes, we required to login inside the instance. So, we will allow port 22 for SSH.

resource "aws_security_group" "allowHttp" {depends_on = [aws_vpc.myVpc,]
name = "allow_http"description = "Allow http inbound traffic"vpc_id = "${}"
ingress {description = "TCP from VPC"from_port = 80to_port = 80protocol = "tcp"cidr_blocks = [""]}ingress {description = "SSH from VPC"from_port = 22to_port = 22protocol = "tcp"cidr_blocks = [""]}egress {from_port = 0to_port = 0protocol = "-1"cidr_blocks = [""]}}

Security Group for MySQL instance:

As we are running MySQL instance in a private subnet, we required that MySQL can only be accessed by the WordPress instance. So, we will only allow the inbound traffic from port 3306 on which MySQL works by default.

resource "aws_security_group" "allowMysql" {depends_on = [aws_vpc.myVpc,]name        = "allow_mysql"description = "Allow mysql inbound traffic"vpc_id      = "${}"ingress {description = "TCP from VPC"from_port   = 3306to_port     = 3306protocol    = "tcp"cidr_blocks = [""]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = [""]}}

Launching MySQL Instance:

The WordPress required MySQL database to be set up first. So, we will launch a MySQL instance first.

resource "aws_instance" "mysql" {depends_on = [aws_security_group.allowMysql,]ami = "ami-0af4f2ae8f9fac390"instance_type = "t2.micro"vpc_security_group_ids = ["${}"]subnet_id = "${}"tags = {Name = "mysql"}}

Launching WordPress Instance:

Finally, we will launch the WordPress Instance and this will successfully launch the WordPress site.

resource "aws_instance" "wordpress" {depends_on = [aws_security_group.allowHttp,aws_instance.mysql,]ami = "ami-ff82f990"instance_type = "t2.micro"key_name = var.key_namevpc_security_group_ids = ["${}"]subnet_id = "${}"tags = {Name = "wordpress"}}

Finally, the Terraform code for launching the WordPress site using public and private subnet in the same VPC is completed.

Run the Terraform Code:

Step 1: Initializing the modules

$ terraform init
$ terraform init

Step 2: Validating the Terraform code

$ terraform validate
$ terraform validate

Step 3: Run the Terraform code

$ terraform apply --auto-approve
$ terraform apply — auto-approve

Step 4: Check if the WordPress and MySQL instances are launched successfully by login into the AWS Console.

WordPress and MySQL instances are launched

As we can see in the above image, the WordPress instance has public IP allocated. So, WordPress can be accessed from the public world using public IP.

But, the MySQL instance doesn’t have any public IP assigned. So, there is no way we can access the MySQL instance from the public world.

Step 5: Accessing the WordPress Site

Now, open the public IP of the WordPress instance form the browser.

WordPress site launched

The WordPress site is launched successfully and can be accessed by using the public IP of the WordPress instance.

Removing all of the Infrastructure:

Deleting all of the infrastructure managed by Terraform is pretty easy. With just a single command we can take down the whole infrastructure.

$ terraform destroy --auto-approve
terraform destroy — auto-approve

If you liked this article, please applaud it.

You can also follow me on Twitter at @cankush625 or find me on LinkedIn.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Ankush Chavan

Ankush Chavan

Tech blogger, researcher and integrator