Provision a Linux VM on a cloud provider.

Provision a Linux VM on a cloud provider.

Introduction.

Infrastructure as Code (IaC) has become an essential practice in modern cloud computing, allowing teams to automate, standardize, and scale their environments with minimal manual intervention. Terraform, a powerful and provider-agnostic IaC tool, simplifies the process of defining and deploying infrastructure across multiple cloud platforms using clear, declarative configuration files.

In this project, the goal is to provision a Linux virtual machine on a cloud provider and automatically configure it to serve a simple blog website, demonstrating how effortless and consistent infrastructure deployment becomes when powered by Terraform. By writing reusable modules, organized variables, and efficiently structured resource blocks, users can create a fully functional environment that launches a server, installs required software, and hosts a basic web page with minimal effort.

This approach highlights the importance of automation in reducing human error, improving deployment speed, and ensuring predictable outcomes. The Linux VM serves as a stable and lightweight foundation for the blog, while Terraform orchestrates networking, security, compute resources, and initialization scripts seamlessly.

Through this project, learners gain valuable hands-on experience with cloud provisioning, infrastructure planning, and real-world configuration workflows. It also reinforces best practices such as maintaining version-controlled infrastructure, enabling easy replication across development, testing, and production environments.

Ultimately, this introduction demonstrates how combining Terraform with a Linux-based server delivers a reliable, scalable, and efficient method for hosting web content, and it lays the groundwork for more advanced automation, CI/CD integration, and multi-tier architectures in future projects.

Folder Structure

terraform-blog/
│
├── main.tf
├── variables.tf
├── outputs.tf
└── user_data.sh

main.tf

terraform {
  required_version = ">= 1.5"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.region
}

# --- Create Key Pair (for SSH) ---
resource "aws_key_pair" "blog_key" {
  key_name   = var.key_name
  public_key = file(var.public_key_path)
}

# --- Create Security Group ---
resource "aws_security_group" "blog_sg" {
  name        = "blog-sg"
  description = "Allow HTTP and SSH"

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# --- Create EC2 Instance ---
resource "aws_instance" "blog_server" {
  ami           = var.ami_id
  instance_type = var.instance_type
  key_name      = aws_key_pair.blog_key.key_name

  security_groups = [
    aws_security_group.blog_sg.name
  ]

  user_data = file("user_data.sh")  # installs Nginx + blog

  tags = {
    Name = "blog-server"
  }
}

variables.tf

variable "region" {
  description = "AWS region to deploy"
  default     = "us-east-1"
}

variable "instance_type" {
  description = "EC2 instance size"
  default     = "t2.micro"
}

variable "ami_id" {
  description = "AMI ID for Ubuntu"
  # Latest Ubuntu 22.04 for us-east-1adjust for your region
  default     = "ami-0fc5d935ebf8bc3bc"
}

variable "key_name" {
  description = "SSH key name"
  default     = "blog-key"
}

variable "public_key_path" {
  description = "Path to your public SSH key"
  default     = "~/.ssh/id_rsa.pub"
}

outputs.tf

output "public_ip" {
  value = aws_instance.blog_server.public_ip
}

output "blog_url" {
  value = "http://${aws_instance.blog_server.public_ip}"
}

user_data.sh (installs Nginx + blog)

#!/bin/bash
apt update -y
apt install -y nginx

cat <<EOF >/var/www/html/index.html
<html>
<head>
  <title>My Terraform Blog</title>
</head>
<body>
  <h1>Welcome to My Blog!</h1>
  <p>This Linux VM was provisioned using Terraform 🤖</p>
</body>
</html>
EOF

systemctl enable nginx
systemctl start nginx

Deployment Instructions

Install prerequisites

  • Terraform
  • AWS CLI
  • An AWS account
  • SSH key (~/.ssh/id_rsa.pub)

Initialize Terraform

terraform init

Preview changes

terraform plan

Deploy infrastructure

terraform apply -auto-approve

Get the blog URL

Terraform prints:

blog_url = http://XX.XX.XX.XX

Open it in your browser you should see your Terraform-built blog.

Your Linux Blog VM is Live!

You now have:

  • A Terraform project provisioning a Linux VM on AWS
  • Automatic blog deployment
  • SSH access + Infrastructure-as-Code setup

Conclusion.

In conclusion, this project demonstrates the efficiency and reliability that Infrastructure as Code brings to modern cloud deployments through the use of Terraform. By provisioning a Linux virtual machine on a cloud provider and automatically configuring it to host a functional blog, the project showcases how automated workflows can replace time-consuming manual setup and reduce the risk of configuration errors.

Terraform’s declarative approach enables clear, repeatable, and scalable infrastructure management, making it easy to adjust resources, reproduce environments, or extend the architecture as needs evolve. The successful deployment of a fully operational web server illustrates not only the power of automation but also the flexibility of combining Linux’s stability with Terraform’s orchestration capabilities.

Overall, this project provides a strong foundation for understanding cloud automation practices and paves the way for more advanced implementations, including multi-tier applications, CI/CD pipelines, and enterprise-grade infrastructure design.

Comments are closed.