├── .gitignore
├── README.md
├── main.tf
└── modules
└── latest
├── aws_ami.tf
├── main_script.tf
├── user_data.tpl
├── userdata_ubuntu.tpl
├── variables.tf
└── versions.tf
/.gitignore:
--------------------------------------------------------------------------------
1 | mykey-pair
2 | mykey-pair.pub
3 | .terraform
4 | .terraform.lock.hcl
5 | terraform.tfstate
6 | terraform.tfstate.backup
7 | user_data(exec).tpl
8 | banner.txt
9 | wordpress_tf.sh
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This terraform projects creates
2 | RDS databse with mysql 5.7
3 | #EC2 instance with wordpress pre installed and configured
4 | ----------------------------------------------------------------------
5 | AWS FREE TRIAL friendly
6 | ----------------------------------------------------------------------
7 | Change database entries ,regions and other variable in terraform.tfvars file
8 | And Database password in user.tfvars file
9 | -------------------------------------------------------------------------
10 | This script is default for Ubuntu
11 | If you want to configure wordpress in AWS LINUX 2 then change IsUbuntu value to false in terraform.tfvars
12 |
13 | Make sure you have configured aws CLI in your local machine
14 |
15 | user_data.tf is script for LINUX 2 and userdata_ubuntu.tpl is for Ubuntu
16 | ----------------------------------------------------------------------------------------
17 | ami-id will be imported using data.aws_ami
18 | --------------------------------------------------------------------------------
19 |
Security:
20 | EC2 will be launched in public subnet and RDS will be launched in private subnet
21 | Only EC2 with defined security group can access RDS and RDS wont have internet access
22 | Password for RDS will be used to create the resource, later it should be changed manually for security purposes. Terraform will ignore any changes in password
23 |
24 |
25 | <----------------------------------------------------------------------------------------------------------------------->
26 |
27 |
Prerequisite
28 | Before launching Terraform template, aws cli should be installed and configured with proper access key and secret key
29 | Terraform should be installed in your local machine
30 | Configure AWS CLI with aws configure
if you havent configured already
31 |
32 | <------------------------------------------------------------------------------------------------------------------------>
33 |
34 | STEPS:
35 |
36 | Clone this repo using command git clone https://github.com/devbhusal/terraform-ec2-RDS-wordpress.git
37 | Go to project folder cd terraform-ec2-RDS-wordpress
38 | Initialize terraform terraform init
39 | Change database and aws setting in terraform.tfvars file
40 | Generate Key pair using ssh-keygen -f mykey-pair
41 | View Plan using terraform plan
42 | Apply the plan using terraform apply
43 |
44 | After successfull provisioning of AWS Resources,Using remote-exec and private key, EC2 instance will be connected via SSH. Tail command will used to check prgress of Wordpress Installation. Once Installation is done ,You will be provided with Public Ip address of WebServer.
45 | everything is Automatic. This will provision all needed aws resources and also build and start webserver using USERDATA
46 |
47 | Destroy the resources terraform destroy
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 |
2 |
3 | module aws_wordpress {
4 | source = "./modules/latest"
5 | database_name = "wordpress_db" // database name
6 | database_user = "wordpress_user" //database username
7 | // Password here will be used to create master db user.It should be chnaged later
8 | database_password = "PassWord4-user" //password for user database
9 | shared_credentials_file = "~/.aws/credentials" //Access key and Secret key file location
10 | region = "ap-southeast-2" //sydney region
11 | IsUbuntu = true // true for ubuntu,false for linux 2 //boolean type
12 | // avaibility zone and their CIDR
13 | AZ1 = "ap-southeast-2a" // for EC2
14 | AZ2 = "ap-southeast-2b" //for RDS
15 | AZ3 = "ap-southeast-2c" //for RDS
16 | VPC_cidr = "10.0.0.0/16" // VPC CIDR
17 | subnet1_cidr = "10.0.1.0/24" // Public Subnet for EC2
18 | subnet2_cidr = "10.0.2.0/24" //Private Subnet for RDS
19 | subnet3_cidr = "10.0.3.0/24" //Private subnet for RDS
20 | PUBLIC_KEY_PATH = "./mykey-pair.pub" // key name for ec2, make sure it is created before terrafomr apply
21 | PRIV_KEY_PATH = "./mykey-pair"
22 | instance_type = "t2.micro" //type of instance
23 | instance_class = "db.t2.micro" //type of RDS Instance
24 | root_volume_size = 22
25 | }
--------------------------------------------------------------------------------
/modules/latest/aws_ami.tf:
--------------------------------------------------------------------------------
1 | data "aws_ami" "linux2" {
2 | most_recent = true
3 | owners = ["amazon"]
4 |
5 | filter {
6 | name = "name"
7 | values = ["amzn2-ami-hvm-*-x86_64-gp2"]
8 | }
9 |
10 |
11 | filter {
12 | name = "virtualization-type"
13 | values = ["hvm"]
14 | }
15 | }
16 |
17 |
18 | data "aws_ami" "ubuntu" {
19 |
20 | most_recent = true
21 |
22 | filter {
23 | name = "name"
24 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
25 | }
26 |
27 | filter {
28 | name = "virtualization-type"
29 | values = ["hvm"]
30 | }
31 |
32 | owners = ["099720109477"]
33 | }
--------------------------------------------------------------------------------
/modules/latest/main_script.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 |
3 | region = var.region
4 | shared_credentials_files =[var.shared_credentials_file]
5 | profile = "default"
6 | }
7 |
8 |
9 | # Create VPC
10 | resource "aws_vpc" "prod-vpc" {
11 | cidr_block = var.VPC_cidr
12 | enable_dns_support = "true" #gives you an internal domain name
13 | enable_dns_hostnames = "true" #gives you an internal host name
14 | instance_tenancy = "default"
15 |
16 |
17 | }
18 |
19 | # Create Public Subnet for EC2
20 | resource "aws_subnet" "prod-subnet-public-1" {
21 | vpc_id = aws_vpc.prod-vpc.id
22 | cidr_block = var.subnet1_cidr
23 | map_public_ip_on_launch = "true" //it makes this a public subnet
24 | availability_zone = var.AZ1
25 |
26 | }
27 |
28 | # Create Private subnet for RDS
29 | resource "aws_subnet" "prod-subnet-private-1" {
30 | vpc_id = aws_vpc.prod-vpc.id
31 | cidr_block = var.subnet2_cidr
32 | map_public_ip_on_launch = "false" //it makes private subnet
33 | availability_zone = var.AZ2
34 |
35 | }
36 |
37 | # Create second Private subnet for RDS
38 | resource "aws_subnet" "prod-subnet-private-2" {
39 | vpc_id = aws_vpc.prod-vpc.id
40 | cidr_block = var.subnet3_cidr
41 | map_public_ip_on_launch = "false" //it makes private subnet
42 | availability_zone = var.AZ3
43 |
44 | }
45 |
46 |
47 |
48 | # Create IGW for internet connection
49 | resource "aws_internet_gateway" "prod-igw" {
50 | vpc_id = aws_vpc.prod-vpc.id
51 |
52 | }
53 |
54 | # Creating Route table
55 | resource "aws_route_table" "prod-public-crt" {
56 | vpc_id = aws_vpc.prod-vpc.id
57 |
58 | route {
59 | //associated subnet can reach everywhere
60 | cidr_block = "0.0.0.0/0"
61 | //CRT uses this IGW to reach internet
62 | gateway_id = aws_internet_gateway.prod-igw.id
63 | }
64 |
65 |
66 | }
67 |
68 |
69 | # Associating route tabe to public subnet
70 | resource "aws_route_table_association" "prod-crta-public-subnet-1" {
71 | subnet_id = aws_subnet.prod-subnet-public-1.id
72 | route_table_id = aws_route_table.prod-public-crt.id
73 | }
74 |
75 |
76 |
77 | //security group for EC2
78 |
79 | resource "aws_security_group" "ec2_allow_rule" {
80 |
81 |
82 | ingress {
83 | description = "HTTPS"
84 | from_port = 443
85 | to_port = 443
86 | protocol = "tcp"
87 | cidr_blocks = ["0.0.0.0/0"]
88 | }
89 |
90 | ingress {
91 | description = "HTTP"
92 | from_port = 80
93 | to_port = 80
94 | protocol = "tcp"
95 | cidr_blocks = ["0.0.0.0/0"]
96 | }
97 |
98 | ingress {
99 | description = "MYSQL"
100 | from_port = 3306
101 | to_port = 3306
102 | protocol = "tcp"
103 | cidr_blocks = ["0.0.0.0/0"]
104 | }
105 |
106 | ingress {
107 | description = "SSH"
108 | from_port = 22
109 | to_port = 22
110 | protocol = "tcp"
111 | cidr_blocks = ["0.0.0.0/0"]
112 | }
113 |
114 | egress {
115 | from_port = 0
116 | to_port = 0
117 | protocol = "-1"
118 | cidr_blocks = ["0.0.0.0/0"]
119 | }
120 | vpc_id = aws_vpc.prod-vpc.id
121 | tags = {
122 | Name = "allow ssh,http,https"
123 | }
124 | }
125 |
126 |
127 | # Security group for RDS
128 | resource "aws_security_group" "RDS_allow_rule" {
129 | vpc_id = aws_vpc.prod-vpc.id
130 | ingress {
131 | from_port = 3306
132 | to_port = 3306
133 | protocol = "tcp"
134 | security_groups = ["${aws_security_group.ec2_allow_rule.id}"]
135 | }
136 | # Allow all outbound traffic.
137 | egress {
138 | from_port = 0
139 | to_port = 0
140 | protocol = "-1"
141 | cidr_blocks = ["0.0.0.0/0"]
142 | }
143 | tags = {
144 | Name = "allow ec2"
145 | }
146 |
147 | }
148 |
149 | # Create RDS Subnet group
150 | resource "aws_db_subnet_group" "RDS_subnet_grp" {
151 | subnet_ids = ["${aws_subnet.prod-subnet-private-1.id}", "${aws_subnet.prod-subnet-private-2.id}"]
152 | }
153 |
154 | # Create RDS instance
155 | resource "aws_db_instance" "wordpressdb" {
156 | allocated_storage = 10
157 | engine = "mysql"
158 | engine_version = "5.7"
159 | instance_class = var.instance_class
160 | db_subnet_group_name = aws_db_subnet_group.RDS_subnet_grp.id
161 | vpc_security_group_ids = ["${aws_security_group.RDS_allow_rule.id}"]
162 | db_name = var.database_name
163 | username = var.database_user
164 | password = var.database_password
165 | skip_final_snapshot = true
166 |
167 | # make sure rds manual password chnages is ignored
168 | lifecycle {
169 | ignore_changes = [password]
170 | }
171 | }
172 |
173 | # change USERDATA varible value after grabbing RDS endpoint info
174 | data "template_file" "user_data" {
175 | template = var.IsUbuntu ? file("${path.module}/userdata_ubuntu.tpl") : file("${path.module}/user_data.tpl")
176 | vars = {
177 | db_username = var.database_user
178 | db_user_password = var.database_password
179 | db_name = var.database_name
180 | db_RDS = aws_db_instance.wordpressdb.endpoint
181 | }
182 | }
183 |
184 |
185 | # Create EC2 ( only after RDS is provisioned)
186 | resource "aws_instance" "wordpressec2" {
187 | ami = var.IsUbuntu ? data.aws_ami.ubuntu.id : data.aws_ami.linux2.id
188 | instance_type = var.instance_type
189 | subnet_id = aws_subnet.prod-subnet-public-1.id
190 | vpc_security_group_ids = ["${aws_security_group.ec2_allow_rule.id}"]
191 | user_data = data.template_file.user_data.rendered
192 | key_name = aws_key_pair.mykey-pair.id
193 | tags = {
194 | Name = "Wordpress.web"
195 | }
196 |
197 | root_block_device {
198 | volume_size = var.root_volume_size # in GB
199 |
200 | }
201 |
202 | # this will stop creating EC2 before RDS is provisioned
203 | depends_on = [aws_db_instance.wordpressdb]
204 | }
205 |
206 | // Sends your public key to the instance
207 | resource "aws_key_pair" "mykey-pair" {
208 | key_name = "mykey-pair"
209 | public_key = file(var.PUBLIC_KEY_PATH)
210 | }
211 |
212 | # creating Elastic IP for EC2
213 | resource "aws_eip" "eip" {
214 | instance = aws_instance.wordpressec2.id
215 |
216 | }
217 |
218 | output "IP" {
219 | value = aws_eip.eip.public_ip
220 | }
221 | output "RDS-Endpoint" {
222 | value = aws_db_instance.wordpressdb.endpoint
223 | }
224 |
225 | output "INFO" {
226 | value = "AWS Resources and Wordpress has been provisioned. Go to http://${aws_eip.eip.public_ip}"
227 | }
228 |
229 | resource "null_resource" "Wordpress_Installation_Waiting" {
230 | # trigger will create new null-resource if ec2 id or rds is chnaged
231 | triggers={
232 | ec2_id=aws_instance.wordpressec2.id,
233 | rds_endpoint=aws_db_instance.wordpressdb.endpoint
234 |
235 | }
236 | connection {
237 | type = "ssh"
238 | user = var.IsUbuntu ? "ubuntu" : "ec2-user"
239 | private_key = file(var.PRIV_KEY_PATH)
240 | host = aws_eip.eip.public_ip
241 | }
242 |
243 |
244 | provisioner "remote-exec" {
245 | inline = ["sudo tail -f -n0 /var/log/cloud-init-output.log| grep -q 'WordPress Installed'"]
246 |
247 | }
248 | }
249 |
250 |
251 |
252 |
253 |
254 |
--------------------------------------------------------------------------------
/modules/latest/user_data.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # variable will be populated by terraform template
3 | db_username=${db_username}
4 | db_user_password=${db_user_password}
5 | db_name=${db_name}
6 | db_RDS=${db_RDS}
7 | # install LAMP Server
8 | yum update -y
9 | #install apache server and mysql client
10 | yum install -y httpd
11 | yum install -y mysql
12 |
13 |
14 | #first enable php7.xx from amazon-linux-extra and install it
15 |
16 | amazon-linux-extras enable php7.4
17 | yum clean metadata
18 | yum install -y php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,gettext,bcmath,json,xml,fpm,intl,zip,imap,devel}
19 | #install imagick extension
20 | yum -y install gcc ImageMagick ImageMagick-devel ImageMagick-perl
21 | pecl install imagick
22 | chmod 755 /usr/lib64/php/modules/imagick.so
23 | cat <>/etc/php.d/20-imagick.ini
24 |
25 | extension=imagick
26 |
27 | EOF
28 |
29 | systemctl restart php-fpm.service
30 |
31 |
32 |
33 |
34 | systemctl start httpd
35 |
36 |
37 | # Change OWNER and permission of directory /var/www
38 | usermod -a -G apache ec2-user
39 | chown -R ec2-user:apache /var/www
40 | find /var/www -type d -exec chmod 2775 {} \;
41 | find /var/www -type f -exec chmod 0664 {} \;
42 |
43 |
44 | # #**********************Installing Wordpress manually*********************************
45 | # # Download wordpress package and extract
46 | # wget https://wordpress.org/latest.tar.gz
47 | # tar -xzf latest.tar.gz
48 | # cp -r wordpress/* /var/www/html/
49 | # # Create wordpress configuration file and update database value
50 | # cd /var/www/html
51 | # cp wp-config-sample.php wp-config.php
52 | # sed -i "s/database_name_here/$db_name/g" wp-config.php
53 | # sed -i "s/username_here/$db_username/g" wp-config.php
54 | # sed -i "s/password_here/$db_user_password/g" wp-config.php
55 | # sed -i "s/localhost/$db_RDS/g" wp-config.php
56 | # cat <>/var/www/html/wp-config.php
57 | # define( 'FS_METHOD', 'direct' );
58 | # define('WP_MEMORY_LIMIT', '128M');
59 | # EOF
60 |
61 | #**********************Installing Wordpress using WP CLI*********************************
62 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
63 | chmod +x wp-cli.phar
64 | mv wp-cli.phar /usr/local/bin/wp
65 | wp core download --path=/var/www/html --allow-root
66 | wp config create --dbname=$db_name --dbuser=$db_username --dbpass=$db_user_password --dbhost=$db_RDS --path=/var/www/html --allow-root --extra-php </,/<\/Directory>/ s/AllowOverride None/AllowOverride all/' /etc/httpd/conf/httpd.conf
80 |
81 | #Make apache autostart and restart apache
82 | systemctl enable httpd.service
83 | systemctl restart httpd.service
84 | echo WordPress Installed
85 |
86 |
--------------------------------------------------------------------------------
/modules/latest/userdata_ubuntu.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # AUTOMATIC WORDPRESS INSTALLER IN AWS Ubuntu Server 20.04 LTS (HVM)
3 |
4 | # varaible will be populated by terraform template
5 | db_username=${db_username}
6 | db_user_password=${db_user_password}
7 | db_name=${db_name}
8 | db_RDS=${db_RDS}
9 |
10 | # install LAMP Server
11 | apt update -y
12 | apt upgrade -y
13 | apt update -y
14 | apt upgrade -y
15 | #install apache server
16 | apt install -y apache2
17 |
18 |
19 |
20 | apt install -y php
21 | apt install -y php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,bcmath,json,xml,intl,zip,imap,imagick}
22 |
23 |
24 |
25 | #and download mysql package to yum and install mysql client from yum
26 | apt install -y mysql-client-core-8.0
27 |
28 | # starting apache and register them to startup
29 |
30 | systemctl enable --now apache2
31 |
32 |
33 | # Change OWNER and permission of directory /var/www
34 | usermod -a -G www-data ubuntu
35 | chown -R ubuntu:www-data /var/www
36 | find /var/www -type d -exec chmod 2775 {} \;
37 | find /var/www -type f -exec chmod 0664 {} \;
38 |
39 | # #**********************Installing Wordpress manually*********************************
40 | # # Download wordpress package and extract
41 | # wget https://wordpress.org/latest.tar.gz
42 | # tar -xzf latest.tar.gz
43 | # cp -r wordpress/* /var/www/html/
44 | # # Create wordpress configuration file and update database value
45 | # cd /var/www/html
46 | # cp wp-config-sample.php wp-config.php
47 | # sed -i "s/database_name_here/$db_name/g" wp-config.php
48 | # sed -i "s/username_here/$db_username/g" wp-config.php
49 | # sed -i "s/password_here/$db_user_password/g" wp-config.php
50 | # sed -i "s/localhost/$db_RDS/g" wp-config.php
51 | # cat <>/var/www/html/wp-config.php
52 | # define( 'FS_METHOD', 'direct' );
53 | # define('WP_MEMORY_LIMIT', '128M');
54 | # EOF
55 |
56 | #**********************Installing Wordpress using WP CLI*********************************
57 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
58 | chmod +x wp-cli.phar
59 | mv wp-cli.phar /usr/local/bin/wp
60 | wp core download --path=/var/www/html --allow-root
61 | wp config create --dbname=$db_name --dbuser=$db_username --dbpass=$db_user_password --dbhost=$db_RDS --path=/var/www/html --allow-root --extra-php </,/<\/Directory>/ s/AllowOverride None/AllowOverride all/' /etc/apache2/apache2.conf
75 | a2enmod rewrite
76 |
77 | # restart apache
78 |
79 | systemctl restart apache2
80 | echo WordPress Installed
81 |
82 |
--------------------------------------------------------------------------------
/modules/latest/variables.tf:
--------------------------------------------------------------------------------
1 | variable "database_name" {}
2 | variable "database_password" {}
3 | variable "database_user" {}
4 |
5 | variable "region" {}
6 | variable "shared_credentials_file" {}
7 | variable "IsUbuntu" {
8 | type = bool
9 | default = true
10 |
11 | }
12 | variable "AZ1" {}
13 | variable "AZ2" {}
14 | variable "AZ3" {}
15 | variable "VPC_cidr" {}
16 | variable "subnet1_cidr" {}
17 | variable "subnet2_cidr" {}
18 | variable "subnet3_cidr" {}
19 | variable "instance_type" {}
20 | variable "instance_class" {}
21 | variable "PUBLIC_KEY_PATH" {}
22 | variable "PRIV_KEY_PATH" {}
23 | variable "root_volume_size" {}
24 |
25 |
--------------------------------------------------------------------------------
/modules/latest/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | version = "~>4.30.0"
5 | }
6 | null = {
7 | version = "~> 3.1.1"
8 | }
9 | template ={
10 | version= "~> 2.2.0"
11 |
12 | }
13 | }
14 |
15 | required_version = "~> 1.1.3"
16 | }
--------------------------------------------------------------------------------