{"id":23750614,"url":"https://github.com/hamdiz0/employee-directory-app-aws","last_synced_at":"2026-04-13T17:02:53.829Z","repository":{"id":270006634,"uuid":"904988034","full_name":"hamdiz0/employee-directory-app-aws","owner":"hamdiz0","description":"A Dockerized scalable AWS employee directory app setup with DynamoDB, S3 and EC2 instances in a secure multi-AZ VPC using  IAM ,Security Groups and Nacls, configured with an Auto Scaling Group along with an Application Load Balancer for high availability and scalability","archived":false,"fork":false,"pushed_at":"2024-12-27T19:09:43.000Z","size":7495,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-12T09:08:13.641Z","etag":null,"topics":["auto-scaling-group","aws","devops","docker","dynamodb","ec2","iam","load-balancer","nacls","s3","script","security-groups","vpc"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/hamdiz0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2024-12-17T23:53:38.000Z","updated_at":"2025-04-24T16:55:49.000Z","dependencies_parsed_at":"2024-12-27T20:28:45.398Z","dependency_job_id":null,"html_url":"https://github.com/hamdiz0/employee-directory-app-aws","commit_stats":null,"previous_names":["hamdiz0/employee-directory-app-aws"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hamdiz0/employee-directory-app-aws","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Femployee-directory-app-aws","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Femployee-directory-app-aws/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Femployee-directory-app-aws/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Femployee-directory-app-aws/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hamdiz0","download_url":"https://codeload.github.com/hamdiz0/employee-directory-app-aws/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamdiz0%2Femployee-directory-app-aws/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31761996,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T15:25:13.801Z","status":"ssl_error","status_checked_at":"2026-04-13T15:25:09.162Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["auto-scaling-group","aws","devops","docker","dynamodb","ec2","iam","load-balancer","nacls","s3","script","security-groups","vpc"],"created_at":"2024-12-31T16:23:20.111Z","updated_at":"2026-04-13T17:02:53.785Z","avatar_url":"https://github.com/hamdiz0.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Employee directory app on aws\n\nA simple and scalable employee directory application deployed on AWS, allowing you to view and manage employee information with photos stored in S3 and data in DynamoDB. \nRunning as a Docker container on an EC2 instance within a VPC with subnets across multiple availability zones for high availability, it uses an Internet Gateway for internet access. \nSecurity groups and IAM roles ensure secure resource access. \nAuto Scaling adjusts the number of EC2 instances based on CPU usage, while an Application Load Balancer distributes traffic for reliability and performance.\n\n- [Prerequisites](#prerequisites-)\n- [Dockerizing the app](#dockerizing-the-app-)\n- [Architecture](#architecture-)\n- [Deploying on AWS](#deploying-on-aws-)\n    - [Setting up a VPC](#setting-up-a-vpc-)\n    - [Configuring IAM roles and security groups](#configuring-iam-roles-and-security-groups-)\n    - [Setting up S3 and DynamoDB](#setting-up-s3-and-dynamodb-)\n    - [Launching an EC2 instance](#launching-an-ec2-instance-)\n- [Auto Scaling](#auto-scaling-) \n    - [Setting up a Target Group](#setting-up-a-target-group-)\n    - [Creating a Load Balancer](#creating-a-load-balancer-)\n    - [Setting up  a launsh template](#setting-up--a-launsh-template-)\n    - [Creating an Auto Scaling Group](#creating-an-auto-scaling-group-)\n- [Testing the Auto Scaling](#testing-the-auto-scaling-)\n- [Results](#results-)\n\n## Prerequisites :\n\n* an AWS account (Free tier)\n* Docker\n\n## Dockerizing the app :\n\n* add the necessary environment variables to the `.env` file \u003ca href=\"./env.example\"\u003e.env.example\u003c/a\u003e\n\n    ```\n    NODE_ENV= \"production ,development\"\n    PORT= \"port number\"\n    AWS_PROFILE=default\n    PHOTOS_BUCKET= \"bucket-name\"\n    DEFAULT_AWS_REGION= \"region\"\n    TABLE_NAME= \"name of the database table\"\n    ```\n\n* created two docker file versions :\n\n    - simplified version \u003ca href=\"./dockerfile\"\u003edockerfile\u003c/a\u003e\n    - optimized version \u003ca href=\"./dockerfile-optimized\"\u003edockerfile-optimized\u003c/a\u003e\n\n* the optimized version takes up less space but uses two stages unlike the simplified version, it also uses lightweight alpine images as base\n\n    \u003cimg src=\"./imgs/opt⁄smp.png\" style=\"width:100%\"\u003e\n\n    ```\n    docker build . -f dockerfile-optimized -t hamdiz0/empdir-app\n    ```\n* pushed the optimized image version to dockerhub :\n\n    ```\n    docker push hamdiz0/empdir-app\n    ```\n## Architecture :\n\n\u003cimg src=\"./imgs/empdir.png\" style=\"width:100%\"\u003e\n\n## Deploying on AWS :\n\n### Setting up a VPC :\n\n* creata VPC with two subnets in two different avaibility zones\n\n    \u003cimg src=\"./imgs/vpc.png\" style=\"width:100%\"\u003e\n\n* add a Internet Gateway and attached it to the VPC allowing access to internet\n\n    \u003cimg src=\"./imgs/gw.png\" style=\"width:100%\"\u003e\n\n* setup a Route Table for public access throught the created Internet Gateway\n\n    \u003cimg src=\"./imgs/rt.png\" style=\"width:100%\"\u003e\n\n* associate the subnetes to the public Route Table\n\n    \u003cimg src=\"./imgs/rt-assoc.png\" style=\"width:100%\"\u003e\n\n* create an Access List allowing both Inbound and Outbound traffic to the created subnets\n\n    \u003cimg src=\"./imgs/acls.png\" style=\"width:100%\"\u003e\n\n### Configuring IAM roles and security groups :\n\n* create an custom IAM role for the EC2 instance to grant full access to S3 along with DynamoDB\n\n    \u003cimg src=\"./imgs/role.png\" style=\"width:100%\"\u003e\n\n* add a security group to allow SSH (optional), HTTP and HTTPS traffic\n\n    \u003cimg src=\"./imgs/sec.png\" style=\"width:100%\"\u003e\n\n### Setting up S3 and DynamoDB :\n\n* create an S3 bucket to store the employees images\n* pre upload the \u003ca href=\"./employee-img/\" \u003eemployees images\u003c/a\u003e to the bucket for testing\n\n    \u003cimg src=\"./imgs/upload.png\" style=\"width:100%\"\u003e \n\n* add a policy to the bucket in the permissions tab to allow the EC2 instance to access the bucket using the IAM role\n\n    ```\n    {\n        \"Version\":\"2012-10-17\",\n        \"Statement\":[\n            {\n                \"Sid\":\"AllowS3ReadAccess\",\n                \"Effect\":\"Allow\",\n                \"Principal\": {\n                    \"AWS\":\"arn:aws:iam::\u003cACCOUNT-NUMBER\u003e:role/\u003cROLE\u003e\"   // ensure only the IAM role can access the bucket\n                },\n                \"Action\":\"s3:*\",                                        // full access\n                \"Resource\":[\n                    \"arn:aws:s3:::\u003cBUCKET-NAME\u003e\",                       // allow operations on the bucket itself\n                    \"arn:aws:s3:::\u003cBUCKET-NAME\u003e/*\"                      // allow opertaions on the bucket objects\n                ]\n            }\n        ]\n    }\n    ```\n* add CROS configuration to the bucket to avoid request issues \n\n    ```\n    [\n        {\n            \"AllowedHeaders\": [\"*\"],                                    // allow all headers\n            \"AllowedMethods\": [                                         // allow GET ,POST and PUT http methods\n                \"GET\",\n                \"POST\",\n                \"PUT\"\n            ],\n            \"AllowedOrigins\": [\"*\"],                                    // allow all traffic ,you can specify a specific url\n            \"ExposeHeaders\": [\"ETag\"],\n            \"MaxAgeSeconds\": 3000\n        }\n    ]\n    ```\n\n* add a DynamoDB table to store the employee information \n\n    \u003cimg src=\"./imgs/dynamo.png\" style=\"width:100%\"\u003e\n\n### Launching an EC2 instance :\n\n* launch the instance on a public subnet of the created VPC\n* attach the security group \n\n    \u003cimg src=\"./imgs/ec2-net.png\" style=\"width:100%\"\u003e\n\n* add the \"s3dynamodbfullaccess\" role to the EC2\n\n    \u003cimg src=\"./imgs/ec2-addrole.png\" style=\"width:100%\"\u003e\n\n* make sure the Metadata service is enabled with both versions v1 and v2 allowing the app to retrieve the instance metadata\n\n    \u003cimg src=\"./imgs/v1andv2.png\" style=\"width:100%\"\u003e    \n\n* add a script in the user data field to launch the app automaticly when the instance done creating \n\n    \u003cimg src=\"./imgs/ec2-user-data.png\" style=\"width:100%\"\u003e\n\n* the script installs docker and launches the app as a container\n\n    ```\n    #!/bin/bash\n\n    USER_NAME=\"ubuntu\"\n\n    # install docker\n    curl -fsSL https://test.docker.com -o test-docker.sh\n    sudo sh test-docker.sh\n    sudo usermod -aG docker $USER_NAME\n    newgrp docker\n\n    # run the employee directory app as container\n    sudo -u $USER_NAME docker run -p 80:80 -d --name=empdir hamdiz0/empdir-app\n    ```\n* alternatively you can launch the app directly not as a docker container with the following script\n\n    ```\n    #!/bin/bash\n\n    # Set environment variables\n    export PORT=\"80\"\n    export PHOTOS_BUCKET=\"s3-bucket-name\"\n    export DEFAULT_AWS_REGION=\"region\"\n    export SHOW_ADMIN_TOOLS=\"1\"\n\n    # Update apt\n    apt update -y\n\n    # Install tools and dependencies\n    apt install stress nodejs npm unzip -y\n\n    # Create a dedicated directory for the application\n    sudo mkdir -p /var/app\n    cd /var/app\n\n    # Download the app from S3\n    wget https://aws-tc-largeobjects.s3-us-west-2.amazonaws.com/ILT-TF-100-TECESS-5/app/app.zip\n\n    # Extract it to the desired folder\n    sudo unzip app.zip -d /var/app/\n    cd /var/app/\n\n    # Install dependencies\n    npm install\n\n    # Start the app\n    npm start\n    ```\n* a crontab expression can be added to strat the app on boot\n\n    ```\n    @reboot docker run -p 80:80 -d --name=empdir hamdiz0/empdir-app\n    ```\n    ```\n    @reboot cd /var/app/ \u0026\u0026 npm start\n    ```\n* the app can be accessed throught http using the EC2 instance ip@\n\n    ```\n    http://\u003cEC2_IP_ADDRESS\u003e:80\n    ```\n\n## Auto Scaling :\n\n### Setting up a Target Group :\n\n* create a target group for the EC2 instances \n* add the VPC along with the disired health check settings\n\n    \u003cimg src=\"./imgs/tg-1.png\" style=\"width:100%\"\u003e\n    \u003cimg src=\"./imgs/tg.png\" style=\"width:100%\"\u003e\n\n\n### Creating a Load Balancer :\n\n* create an Application Load Balancer (ALB)\n\n    \u003cimg src=\"./imgs/lb-alb.png\" style=\"width:100%\"\u003e\n\n* add the VPC network and the created subnets along with the security group\n\n    \u003cimg src=\"./imgs/lb-net.png\" style=\"width:100%\"\u003e\n\n* add the target group to the ALB\n\n    \u003cimg src=\"./imgs/lb-tg.png\" style=\"width:100%\"\u003e\n\n* the app can be accessed throught the ALB DNS name\n\n    ```\n    http://\u003cALB_DNS_NAME\u003e\n    ```\n\n    \u003cimg src=\"./imgs/lb.png\" style=\"width:100%\"\u003e\n\n### Setting up  a launsh template : \n\n* configure the template with the AMI from the previous EC2 instance along with network settings , IAM role and user data (launching script)\n\n* make sure the auto assign public ip is enabled\n\n    \u003cimg src=\"./imgs/lt-net.png\" style=\"width:100%\"\u003e\n\n### Creating an Auto Scaling Group :\n\n* add the created launch template\n\n   \u003cimg src=\"./imgs/sg.png\" style=\"width:100%\"\u003e\n   \n* add the VPC with the desired availability zones\n\n    \u003cimg src=\"./imgs/sg-net.png\" style=\"width:100%\"\u003e\n\n* attach the load balancer and the target group\n\n    \u003cimg src=\"./imgs/sg-lb.png\" style=\"width:100%\"\u003e\n\n* configue the scaling values to youre needs\n\n    \u003cimg src=\"./imgs/sg-scal.png\" style=\"width:100%\"\u003e\n\n* add a scaling policy to scale up and down based on the CPU usage (50% in this case)\n\n    \u003cimg src=\"./imgs/sg-scal-pol.png\" style=\"width:100%\"\u003e\n\n## Testing the Auto Scaling :\n\n* if you refresh the app page you will notice that the \"Availability Zone\" along with the \"EC2 Instance Id\" values change indicating that the app is being served by different instances\n\n    \u003cimg src=\"./imgs/3a.png\" style=\"width:100%\"\u003e\n\n    \u003cimg src=\"./imgs/3b.png\" style=\"width:100%\"\u003e\n\n* the app has a built in stress feature that uses the stress linux utility to simulate high CPU usage\n\n* start the stress test by clicking the \"Stress Application Server For\" button\n\n    \u003cimg src=\"./imgs/stress.png\" style=\"width:100%\"\u003e\n\n* the number of instances before starting the stress test\n\n    \u003cimg src=\"./imgs/before-scal.png\" style=\"width:100%\"\u003e\n\n* the number of instaces increases when the CPU usage exceeds the threshold from 2 to 4 instances\n\n    \u003cimg src=\"./imgs/after-scal.png\" style=\"width:100%\"\u003e\n\n    \u003cimg src=\"./imgs/scal-up.png\" style=\"width:100%\"\u003e\n\n* the cpu usage drops drastically after the app scales up\n\n    \u003cimg src=\"./imgs/stress-after-scal.png\" style=\"width:100%\"\u003e\n\n* after the stress test is done the number of instances goes back to the initial value\n\n    \u003cimg src=\"./imgs/scal-down.png\" style=\"width:100%\"\u003e\n\n## Results :\n\n* Application\n\n\u003cimg src=\"./imgs/0.png\" style=\"width:100%\"\u003e\n\n\u003cimg src=\"./imgs/1.png\" style=\"width:100%\"\u003e\n\n\u003cimg src=\"./imgs/2.png\" style=\"width:100%\"\u003e\n\n\u003cimg src=\"./imgs/3.png\" style=\"width:100%\"\u003e\n\n* DynamoDB table\n\n\u003cimg src=\"./imgs/dynamores.png\" style=\"width:100%\"\u003e\n\n* adding an employee with an uploaded image\n\n\u003cimg src=\"./imgs/4.png\" style=\"width:100%\"\u003e\n\n\u003cimg src=\"./imgs/5.png\" style=\"width:100%\"\u003e\n\n## Checkout my \u003ca href=\"https://github.com/hamdiz0/LearningDevOps\"\u003eLearningDevops\u003c/a\u003e repo for more details about these tools and devops in general do not hesitate to contribute","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamdiz0%2Femployee-directory-app-aws","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhamdiz0%2Femployee-directory-app-aws","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamdiz0%2Femployee-directory-app-aws/lists"}