Demonstrations
These step-by-step demonstrations walk you through complete workflows using the ec2-instance module. Each demonstration includes prerequisites, detailed instructions, and verification steps.
Getting Started
To follow any demonstration, ensure you have:
- Prerequisites met:
Terraform >= 1.0, AWS CLI configured - Authenticate with the registry:
terraform login registry.patterneddesigns.ca - Clone the demonstration repository:
git clone <demo-repo-url> - Follow the step-by-step instructions below
Step-by-Step Guides
Deploy an EC2 instance configured as a web server
Step 1: Create the Instance
module "web_server" {
source = "registry.patterneddesigns.ca/patterneddesigns/ec2-instance/aws"
version = "1.5.0"
instance_name = "web-server"
instance_type = "t3.micro"
ami_id = data.aws_ami.amazon_linux.id
subnet_id = module.vpc.private_subnets[0]
}
Step 2: Configure Security Groups
Allow HTTP/HTTPS traffic to the instance.
Step 3: Install Web Server
SSH into the instance and install nginx or apache.
Deploy a complete LAMP stack on EC2
This demonstration walks through deploying a complete LAMP (Linux, Apache, MySQL, PHP) stack on an EC2 instance using Terraform.
Prerequisites
Before starting, ensure you have:
- AWS account with appropriate permissions
- Terraform 1.0+ installed
- An existing VPC with public and private subnets
- SSH key pair created in your target region
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Internet │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ Security Group │
│ (HTTP/HTTPS/SSH)│
└─────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ EC2 Instance (LAMP) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Apache │ │ MySQL │ │ PHP │ │
│ │ (httpd) │ │ (MariaDB) │ │ 8.x │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ EBS Volume (gp3, encrypted) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Step 1: Create the Terraform Configuration
Create a new directory and add the following files.
main.tf
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
# Get latest Amazon Linux 2023 AMI
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Security group for LAMP server
resource "aws_security_group" "lamp" {
name = "${var.project_name}-lamp-sg"
description = "Security group for LAMP server"
vpc_id = var.vpc_id
ingress {
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTPS"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.allowed_ssh_cidrs
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-lamp-sg"
Environment = var.environment
}
}
# LAMP server EC2 instance
module "lamp_server" {
source = "registry.patterneddesigns.ca/patterneddesigns/ec2-instance/aws"
version = "1.5.0"
instance_name = "${var.project_name}-lamp"
instance_type = var.instance_type
ami_id = data.aws_ami.amazon_linux.id
subnet_id = var.subnet_id
security_group_ids = [aws_security_group.lamp.id]
key_name = var.key_name
assign_public_ip = true
monitoring = true
root_block_device = {
volume_size = 30
volume_type = "gp3"
encrypted = true
}
user_data = templatefile("${path.module}/userdata.sh", {
db_root_password = var.db_root_password
db_name = var.db_name
db_user = var.db_user
db_password = var.db_password
})
tags = {
Environment = var.environment
Project = var.project_name
Stack = "LAMP"
}
}
variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "project_name" {
description = "Project name for resource naming"
type = string
default = "demo"
}
variable "environment" {
description = "Environment name"
type = string
default = "development"
}
variable "vpc_id" {
description = "VPC ID for the LAMP server"
type = string
}
variable "subnet_id" {
description = "Subnet ID for the LAMP server (should be public)"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.small"
}
variable "key_name" {
description = "SSH key pair name"
type = string
}
variable "allowed_ssh_cidrs" {
description = "CIDR blocks allowed for SSH access"
type = list(string)
default = ["0.0.0.0/0"]
}
variable "db_root_password" {
description = "MySQL root password"
type = string
sensitive = true
}
variable "db_name" {
description = "Database name to create"
type = string
default = "app_db"
}
variable "db_user" {
description = "Database user to create"
type = string
default = "app_user"
}
variable "db_password" {
description = "Database user password"
type = string
sensitive = true
}
userdata.sh
#!/bin/bash
set -e
# Log output to file
exec > >(tee /var/log/userdata.log) 2>&1
echo "Starting LAMP stack installation..."
# Update system
dnf update -y
# Install Apache
echo "Installing Apache..."
dnf install -y httpd
systemctl start httpd
systemctl enable httpd
# Install MariaDB (MySQL-compatible)
echo "Installing MariaDB..."
dnf install -y mariadb105-server
systemctl start mariadb
systemctl enable mariadb
# Secure MariaDB installation
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${db_root_password}';"
mysql -u root -p'${db_root_password}' -e "DELETE FROM mysql.user WHERE User='';"
mysql -u root -p'${db_root_password}' -e "DROP DATABASE IF EXISTS test;"
mysql -u root -p'${db_root_password}' -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';"
mysql -u root -p'${db_root_password}' -e "FLUSH PRIVILEGES;"
# Create application database and user
mysql -u root -p'${db_root_password}' -e "CREATE DATABASE IF NOT EXISTS ${db_name};"
mysql -u root -p'${db_root_password}' -e "CREATE USER IF NOT EXISTS '${db_user}'@'localhost' IDENTIFIED BY '${db_password}';"
mysql -u root -p'${db_root_password}' -e "GRANT ALL PRIVILEGES ON ${db_name}.* TO '${db_user}'@'localhost';"
mysql -u root -p'${db_root_password}' -e "FLUSH PRIVILEGES;"
# Install PHP
echo "Installing PHP..."
dnf install -y php php-mysqlnd php-fpm php-json php-mbstring php-xml php-gd
# Configure PHP-FPM
systemctl start php-fpm
systemctl enable php-fpm
# Create PHP info page for testing
cat > /var/www/html/info.php << 'PHPEOF'
<?php
phpinfo();
?>
PHPEOF
# Create database test page
cat > /var/www/html/db-test.php << 'PHPEOF'
<?php
$host = 'localhost';
$db = '${db_name}';
$user = '${db_user}';
$pass = '${db_password}';
try {
$pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
echo "<h1>Database Connection Successful!</h1>";
echo "<p>Connected to database: $db</p>";
} catch (PDOException $e) {
echo "<h1>Connection Failed</h1>";
echo "<p>Error: " . $e->getMessage() . "</p>";
}
?>
PHPEOF
# Set proper permissions
chown -R apache:apache /var/www/html
chmod -R 755 /var/www/html
# Restart Apache to load PHP
systemctl restart httpd
echo "LAMP stack installation completed!"
outputs.tf
output "instance_id" {
description = "EC2 instance ID"
value = module.lamp_server.instance_id
}
output "public_ip" {
description = "Public IP address of the LAMP server"
value = module.lamp_server.public_ip
}
output "private_ip" {
description = "Private IP address"
value = module.lamp_server.private_ip
}
output "web_url" {
description = "URL to access the web server"
value = "http://${module.lamp_server.public_ip}"
}
output "php_info_url" {
description = "URL to access PHP info page"
value = "http://${module.lamp_server.public_ip}/info.php"
}
output "ssh_command" {
description = "SSH command to connect"
value = "ssh -i ~/.ssh/${var.key_name}.pem ec2-user@${module.lamp_server.public_ip}"
}
Step 2: Create terraform.tfvars
aws_region = "us-east-1"
project_name = "myapp"
environment = "development"
vpc_id = "vpc-0123456789abcdef0"
subnet_id = "subnet-0123456789abcdef0"
instance_type = "t3.small"
key_name = "my-key-pair"
allowed_ssh_cidrs = ["203.0.113.0/32"] # Your IP address
db_root_password = "SecureRootPass123!"
db_name = "myapp_db"
db_user = "myapp_user"
db_password = "SecureUserPass456!"
Step 3: Deploy
# Initialize Terraform
terraform init
# Preview changes
terraform plan
# Apply configuration
terraform apply
Step 4: Verify Installation
After deployment completes, verify the LAMP stack:
- Test Apache: Open the web URL in your browser
- Test PHP: Navigate to
/info.php - Test Database: Navigate to
/db-test.php - SSH Access: Connect using the provided SSH command
Step 5: Cleanup
Remove the test pages and secure the installation:
# SSH into the instance
ssh -i ~/.ssh/my-key-pair.pem ec2-user@<public-ip>
# Remove test pages
sudo rm /var/www/html/info.php
sudo rm /var/www/html/db-test.php
# Deploy your application to /var/www/html/
Next Steps
- Configure SSL/TLS with Let’s Encrypt
- Set up a domain name with Route53
- Configure regular backups with AWS Backup
- Add CloudWatch monitoring and alarms
- Consider using RDS for production databases
Cleanup
To destroy all resources:
terraform destroy