{"id":13821195,"url":"https://github.com/miztiik/AWS-Demos","last_synced_at":"2025-05-16T12:33:03.209Z","repository":{"id":41158184,"uuid":"63545155","full_name":"miztiik/AWS-Demos","owner":"miztiik","description":"A hands on repo with multiple demonstrations on AWS 🎓","archived":false,"fork":false,"pushed_at":"2024-02-19T18:53:21.000Z","size":14437,"stargazers_count":513,"open_issues_count":12,"forks_count":1335,"subscribers_count":46,"default_branch":"master","last_synced_at":"2024-11-19T21:36:01.572Z","etag":null,"topics":["automation","aws","aws-cli","aws-demo","bash","boto3","cloudformation","python","rds","serverless","vpc"],"latest_commit_sha":null,"homepage":"https://www.udemy.com/course/aws-cloud-development-kit-from-beginner-to-professional/?referralCode=E15D7FB64E417C547579\u0026couponCode=AWS_4U_MAY","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/miztiik.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"ko_fi":"miztiik"}},"created_at":"2016-07-17T17:55:53.000Z","updated_at":"2024-11-17T17:10:14.000Z","dependencies_parsed_at":"2024-11-19T21:41:02.551Z","dependency_job_id":null,"html_url":"https://github.com/miztiik/AWS-Demos","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miztiik%2FAWS-Demos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miztiik%2FAWS-Demos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miztiik%2FAWS-Demos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miztiik%2FAWS-Demos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/miztiik","download_url":"https://codeload.github.com/miztiik/AWS-Demos/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254530639,"owners_count":22086651,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","aws","aws-cli","aws-demo","bash","boto3","cloudformation","python","rds","serverless","vpc"],"created_at":"2024-08-04T08:01:17.242Z","updated_at":"2025-05-16T12:32:58.200Z","avatar_url":"https://github.com/miztiik.png","language":"Python","funding_links":["https://ko-fi.com/miztiik"],"categories":["Python"],"sub_categories":[],"readme":"# AWS 2 Tier Architecture setup with AWS CLI - Wordpress application on AWS RDS running MySQL\n\nThere are two parts to the setup,\n- **Part 1** - Setting up the network infrastructure (VPC, Subnets, Security Groups)\n- **Part 2** - Create \u0026 Configure the Database, Web \u0026 Load Balancer Instances\n![Fig 1 : Web-App-DB (3 Tier) - Reference Architecture Context](https://raw.githubusercontent.com/miztiik/AWS-Demos/master/img/web-App-DB-Ref-Arch.png)\nAssuming you have already setup your AWS CLI for Region `US East (N. Virginia)`. Lets move forward;\n\n# Part 1 - Create VPC, Subnet, Security Group\n### Setting the AWS Region\n```sh\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n### Creating a VPC\nLets create a `Virtual Private Cloud - VPC` for our setup with /20 range and get our VPC ID using the `query` parameter and set the output format to `text`. Its is a good practice to give meaningful name to the AWS resources, Lets call our VPC `tmpVPC`\n\n```sh\nvpcID=$(aws ec2 create-vpc \\\n      --cidr-block 10.0.0.0/20 \\\n      --query 'Vpc.VpcId' \\\n      --output text)\n```\n##### Tag the VPC\n```sh\naws ec2 create-tags --resources \"$vpcID\" --tags 'Key=Name,Value=tmpVPC'\n```\n\nInstances launched inside a VPC are invisible to the rest of the internet by default. AWS therefore does not bother assigning them a public DNS name. This can be changed easily by enabling the `DNS` support as shown below,\n\n```sh\naws ec2 modify-vpc-attribute --vpc-id \"$vpcID\" --enable-dns-support \"{\\\"Value\\\":true}\"\n\naws ec2 modify-vpc-attribute --vpc-id \"$vpcID\" --enable-dns-hostnames \"{\\\"Value\\\":true}\"\n```\n\n_Check if internet gateway is set. If it wasn't there then do these,_\n```sh \ninternetGatewayId=$(aws ec2 create-internet-gateway \\\n                  --query 'InternetGateway.InternetGatewayId' \\\n                  --output text) \u0026\u0026 echo \"$internetGatewayId\"\naws ec2 attach-internet-gateway --internet-gateway-id \"$internetGatewayId\" --vpc-id \"$vpcID\"\n```\n\n##### Tag the Internet Gateway\n\n```sh\naws ec2 create-tags --resources $internetGatewayId --tags 'Key=Name,Value=tmpVPC-Internet-Gateway'\n```\n\n\u003csup\u003eI have chosen /20 CIDR deliberately to allow us to create different subnets for our db, web instances and reserve some for the future. You might want to choose something else that works better for you. **Important:** _AWS reserves both the first four and the last IP address in each subnet's CIDR block. They're not available for use. The smallest subnet (and VPC) you can create uses a /28 netmask (16 IP addresses), and the largest uses a /16 netmask (65,536 IP addresses). Excellent resources to understand CIDR blocks [here](http://bradthemad.org/tech/notes/cidr_subnets.php) \u0026 [here](https://coderwall.com/p/ndm54w/creating-an-ec2-instance-in-a-vpc-with-the-aws-command-line-interface) \u0026 my quick help [gist](https://gist.github.com/miztiik/baecbaa67b1f10e38186d70e51c13a6c#file-cidr-ip-range)_\u003csup\u003e\n\n\n\n## Subnet Reservation for the Database, Web Servers \u0026 future\nLets [reserve the IP Range](https://medium.com/aws-activate-startup-blog/practical-vpc-design-8412e1a18dcc#.dqxj9dlh2) to spread across multiple availability zones.\n\n| VPC Range   | Availability Zone | Reservation Purpose | IP Ranges   | IP Ranges    | IP Ranges    |\n|-------------|-------------------|---------------------|-------------|--------------|--------------|\n| 10.0.0.0/20 |                   |                     |             |              |              |\n|             | AZ1               | US-East-1b          | 10.0.0.0/21 |              |              |\n|             | AZ1               | Private - DB Subnet |             |  10.0.0.0/22 |              |\n|             | AZ1               |                     |             |  10.0.4.0/22 |              |\n|             | AZ1               | Web Subnet          |             |              |  10.0.4.0/23 |\n|             | AZ1               | Spare Subnet        |             |              |  10.0.6.0/23 |\n|             |                   |                     |             |              |              |\n|             | AZ2               | US-East-1c          | 10.0.8.0/21 |              |              |\n|             | AZ2               | Private - DB Subnet |             |  10.0.8.0/22 |              |\n|             | AZ2               |                     |             | 10.0.12.0/22 |              |\n|             | AZ2               | Web Subnet          |             |              | 10.0.12.0/23 |\n|             | AZ2               | Spare Subnet        |             |              | 10.0.14.0/23 |\n       \n_After creating all the subnets, It should look something like this,_\n![alt tag](https://github.com/miztiik/AWS-Demos/blob/master/img/VPC-Subnet-AZ%5B1-2%5D-Mapping.png)\n \n\n\n### Creating subnets for the DB \u0026 Web Servers in AZ1\n```sh\nUSEast1b_DbSubnetID=$(aws ec2 create-subnet --vpc-id \"$vpcID\" --cidr-block 10.0.0.0/22 --availability-zone us-east-1b --query 'Subnet.SubnetId' --output text)\n\nUSEast1b_WebSubnetID=$(aws ec2 create-subnet --vpc-id \"$vpcID\" --cidr-block 10.0.4.0/23 --availability-zone us-east-1b --query 'Subnet.SubnetId' --output text)\n\nUSEast1b_SpareSubnetID=$(aws ec2 create-subnet --vpc-id \"$vpcID\" --cidr-block 10.0.6.0/23 --availability-zone us-east-1b --query 'Subnet.SubnetId' --output text)\n```\n\n##### Tag the subnet ID's for AZ1\n```sh\n\naws ec2 create-tags --resources \"$USEast1b_DbSubnetID\" --tags 'Key=Name,Value=az1-us-east-1b-DB-Subnet'\n\naws ec2 create-tags --resources \"$USEast1b_WebSubnetID\" --tags 'Key=Name,Value=az1-us-east-1b-Web-Subnet'\n\naws ec2 create-tags --resources \"$USEast1b_SpareSubnetID\" --tags 'Key=Name,Value=az1-us-east-1b-Spare-Subnet'\n\n```\n\n### Creating subnets for the DB \u0026 Web Servers in AZ2\n```sh\nUSEast1c_DbSubnetID=$(aws ec2 create-subnet --vpc-id \"$vpcID\" --cidr-block 10.0.8.0/22 --availability-zone us-east-1c --query 'Subnet.SubnetId' --output text)\n\nUSEast1c_WebSubnetID=$(aws ec2 create-subnet --vpc-id \"$vpcID\" --cidr-block 10.0.12.0/23 --availability-zone us-east-1c --query 'Subnet.SubnetId' --output text)\n\nUSEast1c_SpareSubnetID=$(aws ec2 create-subnet --vpc-id \"$vpcID\" --cidr-block 10.0.14.0/23 --availability-zone us-east-1c --query 'Subnet.SubnetId' --output text)\n```\n##### Tag the subnet ID's for AZ2\n```sh\naws ec2 create-tags --resources \"$USEast1c_DbSubnetID\" --tags 'Key=Name,Value=az1-us-east-1c-DB-Subnet'\n\naws ec2 create-tags --resources \"$USEast1c_WebSubnetID\" --tags 'Key=Name,Value=az1-us-east-1c-Web-Subnet'\n\naws ec2 create-tags --resources \"$USEast1c_SpareSubnetID\" --tags 'Key=Name,Value=az1-us-east-1c-Spare-Subnet'\n```\n\n### Configuring the Route Table\nEach subnet needs to have a route table associated with it to specify the routing of its outbound traffic. By default every subnet inherits the default VPC route table which allows for intra-VPC communication only.\n\nThe following adds a route table to our subnet that allows traffic not meant for an instance inside the VPC to be routed to the internet through our earlier created internet gateway.\n\n```sh\nrouteTableID=$(aws ec2 create-route-table --vpc-id \"$vpcID\" --query 'RouteTable.RouteTableId' --output text)\n\naws ec2 create-route --route-table-id \"$routeTableID\" --destination-cidr-block 0.0.0.0/0 --gateway-id \"$internetGatewayId\"\n\naws ec2 associate-route-table --route-table-id \"$routeTableID\" --subnet-id \"$USEast1b_WebSubnetID\"\n\naws ec2 associate-route-table --route-table-id \"$routeTableID\" --subnet-id \"$USEast1c_WebSubnetID\"\n```\n\n### Creating a security group for the Web Servers\n - Group Name - `webSecGrp`\n - Description - `My Web Security Group`\n\n```sh\nwebSecGrpID=$(aws ec2 create-security-group --group-name webSecGrp \\\n            --description \"Security Group for Web servers\" \\\n            --vpc-id \"$vpcID\" \\\n            --output text)\n```\n\n#### Add a rule that allows inbound SSH, HTTP, HTTP traffic ( from any source )\n\n```sh\naws ec2 authorize-security-group-ingress --group-id \"$webSecGrpID\" --protocol tcp --port 22 --cidr 0.0.0.0/0\naws ec2 authorize-security-group-ingress --group-id \"$webSecGrpID\" --protocol tcp --port 80 --cidr 0.0.0.0/0\naws ec2 authorize-security-group-ingress --group-id \"$webSecGrpID\" --protocol tcp --port 443 --cidr 0.0.0.0/0\n```\n_Interesting reading here about why we need to use security group ID instead of name; [AWS Documentation](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html) \u0026 [Github Bug Report](https://github.com/hashicorp/terraform/issues/575)_\n\n\u003eWhen you specify a security group for a nondefault VPC to the CLI or the API actions, you must use the security group ID and not the security group name to identify the security group.\n\n# Part 2 - Create \u0026 Configure the Database, Web \u0026 Load Balancer Instances\n## Creating the RDS Instance\n### Pre-Requisites\n- DB Subnet - _[The RDS instances requires the db subnet group to span across (atleast two) availability zones](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html?shortFooter=true)_\n- DB Security Group - _Security group all allows other EC2  instances to connect with this RDS instance_\n\n#### Create the `DB Subnet`\nCreates a new DB subnet group. DB subnet groups must contain at least one subnet in at least two AZs in the region.\n```sh\naws rds create-db-subnet-group \\\n        --db-subnet-group-name \"mysqlDBSubnet\" \\\n        --db-subnet-group-description \"Subnet group for my databases instances\" \\\n        --subnet-ids \"$USEast1b_DbSubnetID\" \"$USEast1c_DbSubnetID\"\n```\n\n#### Creating a Security Group for RDS Database (running MySQL)\n - Group Name - `dbSecGrp`\n - Description - `My Database Security Group`\n\n```sh\ndbSecGrpID=$(aws ec2 create-security-group \\\n           --group-name dbSecGrp \\\n           --description \"Security Group for database servers\" \\\n           --vpc-id \"$vpcID\" \\\n           --output text)\n```\n\n#### Add a rule that allows inbound MySQL from Webservers (in our Web Security Group)\n\n```sh\naws ec2 authorize-security-group-ingress \\\n        --group-id \"$dbSecGrpID\" \\\n        --protocol tcp \\\n        --port 3306 \\\n        --source-group \\\n        \"$webSecGrpID\"\n```\n\n##### Create a DB parameter group to monitor CRUD\n```sh\naws rds create-db-parameter-group \\\n    --db-parameter-group-name myParamGrp \\\n    --db-parameter-group-family MySQL5.6 \\\n    --description \"My new parameter group\"\n\naws rds modify-db-parameter-group --db-parameter-group-name myParamGrp --parameters \"ParameterName=general_log, ParameterValue=ON, Description=logParameter,ApplyMethod=immediate\"\n```\n\n### Start the RDS - MySQL Instance\n```sh\nrdsInstID=rds-mysql-inst01\naws rds create-db-instance \\\n        --db-instance-identifier \"$rdsInstID\" \\\n        --allocated-storage 5 \\\n        --db-instance-class db.t2.micro \\\n        --no-multi-az \\\n        --no-auto-minor-version-upgrade \\\n        --availability-zone us-east-1b \\\n        --vpc-security-group-ids \"$dbSecGrpID\" \\\n        --db-subnet-group-name \"mysqldbsubnet\" \\\n        --engine mysql \\\n        --port 3306 \\\n        --master-username dbuser \\\n        --master-user-password dbuserpass \\\n        --db-parameter-group-name myParamGrp \\\n        --db-name wpdb \\\n        --backup-retention-period 3\n        \naws rds modify-db-instance --db-instance-identifier \"$rdsInstID\" --db-parameter-group-name myParamGrp\n```\n\n_**Refer:**_ \n- [1] https://www.linux.com/blog/introduction-aws-command-line-tool-part-2\n- [2] http://docs.aws.amazon.com/cli/latest/reference/rds/create-db-instance.html\n- [3] [Cloning RDS Instances for Testing](http://blog.dmcquay.com/devops/2015/09/18/cloning-rds-instances-for-testing.html)\n\n# Create the Web Servers\n\n#### Create the SSH Keys \u0026 boot-strap the binaries\n```sh\naws ec2 create-key-pair --key-name webKey --query 'KeyMaterial' --output text \u003e webKey.pem\nchmod 400 webKey.pem\n\ncat \u003e\u003e userDataScript \u003c\u003cEOF\n#!/bin/bash\nset -e -x\n\n# Setting up the HTTP server \nyum update -y\nyum install -y httpd php php-mysql mysql\nservice httpd start\nchkconfig httpd on\ngroupadd www\nusermod -a -G www ec2-user\n\n\n# Download wordpress site \u0026 move to http\ncd /var/www/\ncurl -O https://wordpress.org/latest.tar.gz \u0026\u0026 tar -zxf latest.tar.gz\nrm -rf /var/www/html\nmv wordpress /var/www/html\n\n# Set the permissions\nchown -R root:www /var/www\nchmod 2775 /var/www\nfind /var/www -type d -exec chmod 2775 {} +\nfind /var/www -type f -exec chmod 0664 {} +\n\n# SE Linux permissive\n# needed to make wp connect to DB over newtork\nsetsebool -P httpd_can_network_connect=1\nsetsebool httpd_can_network_connect_db on\n\nsystemctl restart httpd\n# Remove below file after testing\necho \"\u003c?php phpinfo(); ?\u003e\" \u003e /var/www/html/phpinfo.php\nEOF\n```\n\n### Start the Web Instance\n```sh\ninstanceID=$(aws ec2 run-instances \\\n           --image-id ami-2051294a \\\n           --count 1 \\\n           --instance-type t2.micro \\\n           --key-name wpKey \\\n           --security-group-ids \"$webSecGrpID\" \\\n           --subnet-id \"$webSubnetID\" \\\n           --user-data file://userDataScript \\\n           --associate-public-ip-address \\\n           --query 'Instances[0].InstanceId' \\\n           --output text)\n\ninstanceUrl=$(aws ec2 describe-instances \\\n            --instance-ids \"$instanceID\" \\\n            --query 'Reservations[0].Instances[0].PublicDnsName' \\\n            --output text)\n\n# Get the IP address of the running instance:\nip_address=$(aws ec2 describe-instances \\\n           --instance-ids \"$instanceID\" \\\n           --output text --query 'Reservations[*].Instances[*].PublicIpAddress')\n```\n\n# Create the Elastic Load Balancer\n_**Ref:**_ https://aws.amazon.com/articles/1636185810492479\n\n```\naws elb create-load-balancer \\\n--load-balancer-name my-load-balancer \\\n--listeners \"Protocol=HTTP,LoadBalancerPort=80,InstanceProtocol=HTTP,InstancePort=80\" \\\n--subnets \"$USEast1c_WebSubnetID\" \\\n--security-groups \"$webSecGrpID\"\n```\n\n# Apache Workbench Results\n```sh\n[root@ip-172-31-55-78 ec2-user]# ab -n 20000 -c 30 -k http://xx.xx.xx.xx/\nThis is ApacheBench, Version 2.3 \u003c$Revision: 1430300 $\u003e\nCopyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\nLicensed to The Apache Software Foundation, http://www.apache.org/\n\nBenchmarking xx.xx.xx.xx (be patient)\nCompleted 2000 requests\nCompleted 4000 requests\nCompleted 6000 requests\nCompleted 8000 requests\nCompleted 10000 requests\nCompleted 12000 requests\nCompleted 14000 requests\nCompleted 16000 requests\nCompleted 18000 requests\nCompleted 20000 requests\nFinished 20000 requests\n\n\nServer Software:        Apache/2.4.6\nServer Hostname:        xx.xx.xx.xx\nServer Port:            80\n\nDocument Path:          /\nDocument Length:        11951 bytes\n\nConcurrency Level:      30\nTime taken for tests:   4684.053 seconds\nComplete requests:      20000\nFailed requests:        5641\n   (Connect: 0, Receive: 0, Length: 5641, Exceptions: 0)\nWrite errors:           0\nKeep-Alive requests:    0\nTotal transferred:      349703793 bytes\nHTML transferred:       344441217 bytes\nRequests per second:    4.27 [#/sec] (mean)\nTime per request:       7026.079 [ms] (mean)\nTime per request:       234.203 [ms] (mean, across all concurrent requests)\nTransfer rate:          72.91 [Kbytes/sec] received\n\nConnection Times (ms)\n              min  mean[+/-sd] median   max\nConnect:        1    2  49.6      1    7014\nProcessing:   356 7013 3842.2   5067   43302\nWaiting:        0 6040 3317.2   4332   40634\nTotal:        357 7014 3842.9   5069   43303\n\nPercentage of the requests served within a certain time (ms)\n  50%   5069\n  66%   7997\n  75%   9596\n  80%  10332\n  90%  12134\n  95%  13574\n  98%  16122\n  99%  18490\n 100%  43303 (longest request)\n[root@ip-172-31-55-78 ec2-user]#\n```\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiztiik%2FAWS-Demos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiztiik%2FAWS-Demos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiztiik%2FAWS-Demos/lists"}