Day 3 of the #30DayTerraformChallenge was pure instance gratification β no more just talking about cloud infrastructure, but actually deploying it and watching code bring resources to life!
π Quick Wins of the Day:
I achieved two key deployments:
- β A π₯οΈ Single Server β a basic standalone EC2 instance with no configurations.
- β
A π Web Server β an EC2 instance that auto-installs Apache and serves a custom web page using
user_data. (a fully functional web server) Seeingterraform applywork its magic? Priceless! β¨
π§ Key Differences: Single Server vs Web Server
| Feature | Single Server π₯οΈ | Web Server π |
|---|---|---|
| Purpose | Basic EC2 VM | Hosts a website |
| User Data Script | β No | β Installs Apache & HTML |
| HTTP Access | β No | β Yes |
| Visible in Browser | β No | β Yes |
1. The Simple Start: Deploying a Basic EC2 Instance πΆ
- Every cloud journey begins somewhere, and for me, it was a fundamental EC2 instance. This represents the simplest form of compute in AWS β a virtual server spun up straight from code.
π₯οΈ Single Server: Basic EC2 Setup
- This is a minimal EC2 instance β no web server, no automation, just a VM in the cloud.
-
Why deploy this? To confirm my Day 2 setup was solid and to witness the raw power of
terraform applyin action for basic resource creation.
π Code: single-server.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "af-south-1"
}
resource "aws_instance" "single-server" {
ami = "ami-0914bddde8faa93a0" # Amazon Linux 2023 AMI
instance_type = "t3.micro"
key_name = "cloudykey"
tags = {
Name = "single-server"
}
}
π¬ Code Comments:
- provider "aws": Your entry point to AWS, specifying the region (af-south-1 for Nairobi vibes! π).
- resource "aws_instance": The core block for creating an EC2 VM.
- ami: The Amazon Machine Image β essentially the operating system pre-configured.
- instance_type: Defines the CPU, memory, and networking capacity (e.g., t3.micro is usually free-tier eligible).
- key_name: Links to your SSH key pair for secure remote access.
- tags: Simple key-value pairs for organizing and identifying your resources in AWS.
2. Beyond Basic: Spinning Up A Web Server! π
- This EC2 instance runs a startup script to install Apache and serve a static HTML page.
π Web Server: With Apache and HTML Page
- Why deploy this? To demonstrate automating server configuration post-launch (user_data) and managing network traffic (Security Groups).
π Code: web-server.tf
# Terraform 0.13 and later:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# Configure the AWS provider
provider "aws" {
region = "af-south-1" # Specify your desired AWS Region
}
# Create an EC2 Instance
resource "aws_instance" "web-server" {
ami = "ami-0914bddde8faa93a0" # Amazon Linux 2023 AMI ID for af-south-1
instance_type = "t3.micro" # Free tier eligible
key_name = "cloudykey"
vpc_security_group_ids = [aws_security_group.web-server-sg.id]
user_data = <<-EOF
#!/bin/bash
sudo yum update -y # Update all installed packages
sudo yum install -y httpd # Install Apache Web Server
sudo systemctl start httpd # Start the Apache Web Server Service
sudo systemctl enable httpd # Configure Apache to start on every reboot
echo "<!DOCTYPE html>
<html>
<head><title>We Are Live, Baby!πππ₯³</title></head>
<body style='background-color:#1e1e1e; color:#00ffcc; text-align:center; padding-top:15%; font-family:monospace;'>
<p>Infrastructure as Code? More like <strong>Magic as Code!ππ«β¨</strong></p>
</body>
</html>" > /var/www/html/index.html
EOF
tags = {
Name = "web-server"
}
}
# Data source to Default VPC
data "aws_vpc" "default_vpc" {
default = true
}
resource "aws_security_group" "web-server-sg" {
name = "web-server-ssh-http-sg"
description = "Allow SSH and HTTP inbound traffic for web server"
vpc_id = data.aws_vpc.default_vpc.id # Or hardcode your VPC ID
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # From ANYWHERE - Be cautious! Wide open for testing only
description = "Allow SSH"
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # From ANYWHERE - Be cautious! Wide open for testing only
description = "Allow HTTP"
}
egress {
from_port = 0 # All Ports
to_port = 0 # All Ports
protocol = "-1" # All Protocols
cidr_blocks = ["0.0.0.0/0"] # To ANYWHERE
}
}
π¬ Code Comments & What's New:
-
user_data Power: This is where the real "Magic as Code" shines! It's a bash script that runs when the instance first launches. I used it to:
- β‘οΈ Update packages, install Apache.
- β‘οΈ Start/enable the Apache service.
- β‘οΈ Create my awesome custom HTML welcome page:"Infrastructure as Code? More like Magic as Code!ππ«β¨"
-
aws_security_group: This acts as a virtual firewall for your server.
- π It allows Port 22 (SSH) for secure remote access.
- π It allows Port 80 (HTTP) so web browsers can connect to our page.
- π Caution: 0.0.0.0/0 means "from anywhere." Super easy for testing, but in production, you'd restrict this to known IPs for better security!
- data "aws_vpc" "default_vpc": A neat way to reference your default VPC without hardcoding its ID.
π§ͺ The Terraform Lifecycle: From Code to Cloud (and Back!) π
I truly experienced the core Terraform workflow:
β‘οΈ terraform init: Initializes the working directory, downloading necessary provider plugins (like hashicorp/aws). It's the setup step.
β‘οΈ terraform plan: Before applying any changes, terraform plan shows you exactly what Terraform will do. It's a crucial "dry run" to avoid surprises!
β‘οΈ terraform apply: Brings your infrastructure to life! It executes the changes outlined in the plan, creating, updating, or deleting resources in your cloud provider.
β‘οΈ terraform destroy: The responsible cleanup crew! This command tears down all the resources managed by your Terraform configuration. Crucial for avoiding unwanted cloud costs! π°
π‘ Brain Bytes from Day 3 π§
- 'terraform apply' is Real Power!: Transforms code into live cloud infrastructure.
- Layered Deployments: Start simple, build complexity.
- 'user_data' for Automation: Automates server setup right after launch.
- Security Groups as Firewalls: Essential for controlling network access.
- Full Lifecycle: Remember init -> plan -> apply -> destroy! Budgeting: Always terraform destroy when done!
What's Next? β‘οΈ
- Day 3: Mission accomplished! Code was tangible and deployed real infrastructure.
- Stay tuned for more awesome automation on Day 4!



Top comments (0)