Engineering Core
ISB Vietnam's skilled software engineers deliver high-quality applications, leveraging their extensive experience in developing financial tools, business management systems, medical technology, and mobile/web platforms.

I. Introduction.

Separating directories for different environments (Dev, Staging, Production) is a mandatory standard in real-world projects to ensure security and manageability.

The best approach is to use a modular model. We will refactor the previous EC2 creation code into a shared module (template), which the Dev and Prod environments will then call using different parameters.

II. Terraform Project Structure.

We will create a Terraform project with the following requirements:

  • Separate configurations for dev and prod environments.

  • Define shared variables for code reusability.

  • Store the State File in AWS S3.

Below is the new directory structure and the implementation steps:

The function of each folder is as follows:

setup-backend: Configuration for the Terraform backend.

modules: Stores reusable code modules.

environments: Contains environment-specific configurations.

File: setup-backend\main.tf

The function of this code is to bootstrap the foundational infrastructure required for a Terraform Remote Backend. This allows the State file to be stored securely on the Cloud instead of a local machine, which is essential for team collaboration.

# Configure the AWS Provider and set the region where resources will be created.
provider "aws" {
  region = "us-east-1"
}

# Create an S3 bucket to store the 'terraform.tfstate' file.
resource "aws_s3_bucket" "terraform_state" {
  bucket = "terraform-state-project-9999"
  lifecycle {
    prevent_destroy = true 
  }
}

# Enable versioning on the S3 bucket.
# This is crucial for state recovery. It allows you to revert to an older 
# state file if the current one gets corrupted or accidentally overwritten.
resource "aws_s3_bucket_versioning" "enabled" {
  bucket = aws_s3_bucket.terraform_state.id
  versioning_configuration {
    status = "Enabled"
  }
}

# Create a DynamoDB table to handle state locking.
# This prevents race conditions (e.g., two developers running 'apply' simultaneously).
resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

# Output the name of the S3 bucket for easy reference later.
output "bucket_name" {
  value = aws_s3_bucket.terraform_state.bucket
}

# Output the name of the DynamoDB table for easy reference later.
output "dynamodb_table_name" {
  value = aws_dynamodb_table.terraform_locks.name
}

 

File: modules\ec2_instance\main.tf

This code snippet creates a basic Web Server infrastructure on AWS. It consists of two main components: a "Virtual Firewall" (Security Group) and a "Virtual Server" (EC2 Instance) protected by that firewall.

resource "aws_security_group" "sg" {
  name        = "${var.env_name}-sg"
  description = "Security Group for ${var.env_name}"

  ingress {
   ...
  }
  
  egress {
   ...
  }
}

resource "aws_instance" "app_server" {
  ami             = var.ami_id
  instance_type   = var.instance_type
  security_groups = [aws_security_group.sg.name]

  tags = {
    Name        = "${var.env_name}-Web-Server"
    Environment = var.env_name
  }
}

 

File: environments\dev\main.tf

This code represents a complete Terraform configuration (Root Module) for the Development environment. It orchestrates various infrastructure components: from state file storage (Backend) to resource instantiation (Module), and finally displaying the results.

# TERRAFORM CONFIGURATION
terraform {
  # Define the providers required by this configuration.
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  # Configure Terraform to store the state file in an S3 bucket instead of locally.
  backend "s3" {
    bucket         = "terraform-state-project-9999" 
    key            = "dev/terraform.tfstate" 
    region         = "us-east-1"
    dynamodb_table = "terraform-locks" 
    encrypt        = true
  }
}

# Configure the AWS Provider to deploy resources into the US East 1 region.
provider "aws" {
  region = "us-east-1"
}

# Instantiate the 'web_server' module using code defined in a local directory.
# This promotes code reusability and cleaner project structure.
module "web_server" {
  # The relative path to the module source code.
  source = "../../modules/ec2_instance"
  # Pass input variables to the module to customize its behavior.
  env_name      = "dev"
  instance_type = "t3.micro"
  ami_id        = "ami-0fa3fe0fa7920f68e"
}

# Retrieve the public IP address from the module's outputs and display it.
output "server_ip" {
  value = module.web_server.public_ip
}

 

File: environments\prod\main.tf

This code represents a complete Terraform configuration (Root Module) for the Production environment. It orchestrates various infrastructure components: from state file storage (Backend) to resource instantiation (Module), and finally displaying the results.

# TERRAFORM CONFIGURATION
terraform {
  # Define the providers required by this configuration.
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  # Configure Terraform to store the state file in an S3 bucket instead of locally.
  backend "s3" {
    bucket         = "terraform-state-project-9999" 
    key            = "prod/terraform.tfstate" 
    region         = "us-east-1"
    dynamodb_table = "terraform-locks" 
    encrypt        = true
  }
}
# Configure the AWS Provider to deploy resources into the US East 1 region.
provider "aws" {
  region = "us-east-1"
}

# Instantiate the 'web_server' module using code defined in a local directory.
# This promotes code reusability and cleaner project structure.
module "web_server" {
  # The relative path to the module source code.
  source = "../../modules/ec2_instance"
  # Pass input variables to the module to customize its behavior.
  env_name      = "prod"
  instance_type = "t3.micro"
  ami_id        = "ami-0fa3fe0fa7920f68e"
}
# Retrieve the public IP address from the module's outputs and display it.
output "server_ip" {
  value = module.web_server.public_ip
}

 

Full source code: https://github.com/ivc-phampbt/terraform-project

III. Run the project to provision resources on the AWS Cloud.

  • Proceed to provision the Terraform backend resources.
taipham@Tais setup-backend % pwd
/Users/taipham/Desktop/projects/terraform/setup-backend
taipham@Tais setup-backend % terraform init
taipham@Tais setup-backend % terraform apply

 

  • Initializing the Development Environment (Proceed similarly for Production)
taipham@Tais dev % pwd  
/Users/taipham/Desktop/projects/terraform/environments/dev
taipham@Tais dev % terraform init
taipham@Tais dev % terraform apply

 

  • Result on AWS: Two EC2 instances were created for the production and development environments

  • Check the S3 bucket for the stored state file.

Development:

Production:

Conclusion

The project successfully transitioned to a professional IaC architecture by implementing the Module pattern and deploying a secure Remote Backend on AWS.

Key Achievements:

  • High Reusability: Infrastructure logic was encapsulated into Terraform Modules, ensuring consistency between Dev and Prod environments.

  • Safety & Collaboration: Implemented a Remote Backend using S3 (for state storage) and DynamoDB (for state locking), ensuring secure team collaboration.

  • Separation: The project structure clearly isolates Dev/Prod environments, confirming that each state file is independently managed and verified.

Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let’s build something great together—reach out to us today. Or click here to explore more ISB Vietnam's case studies.

[References]

https://developer.hashicorp.com/terraform
https://www.sudeepa.com/?p=382 [Image link]

Written by
Author Avatar
Engineering Core
ISB Vietnam's skilled software engineers deliver high-quality applications, leveraging their extensive experience in developing financial tools, business management systems, medical technology, and mobile/web platforms.

Popular Articles

Fintech Development Outsourcing: The Ultimate Guide for 2026
OUTSOURCING

Fintech Development Outsourcing: The Ultimate Guide for 2026

November 25, 2025 · By ISB Vietnam(IVC) Business Development Team

Healthcare IT Outsourcing: A Complete Guide for Medical Software Development
OUTSOURCING

Healthcare IT Outsourcing: A Complete Guide for Medical Software Development

December 29, 2025 · By ISB Vietnam(IVC) Business Development Team

DevOps Best Practices: What to Build and What to Outsource
OUTSOURCING

DevOps Best Practices: What to Build and What to Outsource

March 16, 2026 · By ISB Vietnam(IVC) Business Development Team

What Is Adaptive Software Development (ASD)? A Practical Guide for Modern Engineering Teams
OUTSOURCING

What Is Adaptive Software Development (ASD)? A Practical Guide for Modern Engineering Teams

June 4, 2026 · By ISB Vietnam(IVC) Business Development Team

White Paper

COMPANY PROFILE

Please check out our Company Profile.

Download

COMPANY PORTFOLIO

Explore my work!

Download

ASK ISB Vietnam ABOUT DEVELOPMENT

Let's talk about your project!

Contact US