<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Uwadone Joshua</title>
    <description>The latest articles on DEV Community by Uwadone Joshua (@uwadon1).</description>
    <link>https://dev.to/uwadon1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2315717%2Fc2ae94fb-8d93-40d1-aa45-fdd71b78320e.jpg</url>
      <title>DEV Community: Uwadone Joshua</title>
      <link>https://dev.to/uwadon1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uwadon1"/>
    <language>en</language>
    <item>
      <title>Implement a GitLab CI pipeline to deploy a Spring Boot app.</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Tue, 28 Oct 2025 07:40:13 +0000</pubDate>
      <link>https://dev.to/uwadon1/implement-a-gitlab-ci-pipeline-to-deploy-a-spring-boot-app-510k</link>
      <guid>https://dev.to/uwadon1/implement-a-gitlab-ci-pipeline-to-deploy-a-spring-boot-app-510k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2goljiaui23ic75rcib7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2goljiaui23ic75rcib7.png" alt="Homepage" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A complete, step-by-step guide to implement a GitLab CI/CD pipeline to:&lt;/p&gt;

&lt;p&gt;✅ Deploy a Spring Boot Java application&lt;br&gt;
 ✅ Use a specific GitLab Runner on an EC2 t2.medium instance with Docker executor&lt;br&gt;
 ✅ Use Maven Docker image for builds&lt;br&gt;
 ✅ Host a SonarQube dashboard on the same EC2 instance&lt;/p&gt;

&lt;p&gt;🔧 PREREQUISITES&lt;br&gt;
GitLab account and repository (your Spring Boot app should be in GitLab)&lt;br&gt;
AWS EC2 instance (Ubuntu 22.04 LTS, t2.medium, security group open to ports 22, 8080, 9000, and 22)&lt;br&gt;
A domain/subdomain (optional) if you want to expose SonarQube externally.&lt;/p&gt;

&lt;p&gt;STEP 1: &lt;u&gt;Launch &amp;amp; Prepare EC2 Instance&lt;/u&gt;&lt;br&gt;
First, you need to fork the source code of this project from my GitLab repo. You can download it into your local machine by running the command &lt;code&gt;git clone https://gitlab.com/uwadon1/Jenkins-Zero-To-Hero.git&lt;/code&gt;, and then cd into the directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firy3dwolc67jvco3lfq0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firy3dwolc67jvco3lfq0.png" alt="Clone the repo and move into it" width="666" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;a. Launch an Ubuntu EC2 (t2.medium)&lt;br&gt;
Navigate to the AWS console and launch an instance. We will launch an Ubuntu instance that will serve as the runner, and give it the name "Gitlab-server" and select the AMI server to be Ubuntu Server 22.04 LTS&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfaav0v0tozj3si9nfy9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfaav0v0tozj3si9nfy9.png" alt="Select EC2 Instance Name and AMI!" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will select the instance type t2.medium and make use of an existing keypair named "devopsapp" and leave the network settings as default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5vm284ubh1wjo1jby50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5vm284ubh1wjo1jby50.png" alt="Select EC2 Instance keypair and Type!" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will leave the other options as default and click launch instance (we will leave the Security group setting for now and come back to make necessary adjustments to our S.G)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbqac4wjb2j2dj74h8fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbqac4wjb2j2dj74h8fw.png" alt="Launch EC2 Instance!" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will navigate to the SG overview page to make the manual adjustments to our security group settings to allow necessary traffic.&lt;br&gt;
We will open the following traffic and allow access to IPv4 anywhere:&lt;br&gt;
22 (SSH)&lt;br&gt;
80 (Http)&lt;br&gt;
443 (Https)&lt;br&gt;
9000 (SonarQube)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmklym8k3jtwxwf7iyorr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmklym8k3jtwxwf7iyorr.png" alt="Security Group!" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;b. SSH into the instance&lt;br&gt;
Now we will SSH into the instance we just created, using the command below:&lt;br&gt;
&lt;code&gt;ssh -i ~/.ssh/devopsapp.pem ubuntu@35.91.67.242&lt;/code&gt;&lt;br&gt;
(Ensure to replace with your instance IP address)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0a1yjykhwuxm9vqls1kp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0a1yjykhwuxm9vqls1kp.png" alt="Ssh into the Instance!" width="654" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;c. Update and install dependencies&lt;br&gt;
We will first need to update the instance and install Docker using the command &lt;code&gt;sudo apt update&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yql8bo4lw47t4p1ws86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yql8bo4lw47t4p1ws86.png" alt="Update Instance" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will also install Docker using the command &lt;br&gt;
&lt;code&gt;sudo apt install docker.io&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4jbz2jt509s9jc0gv4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4jbz2jt509s9jc0gv4r.png" alt="Install Docker" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will install JDK, which is a prerequisite for installing Jenkins, using the command&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install openjdk-17-jre
Sudo apt update
sudo apt install openjdk-11-jre
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbxed1vaf15co1wzjbek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbxed1vaf15co1wzjbek.png" alt="Install Java 11" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STEP 2: &lt;u&gt;Set up and Configure SonarQube on EC2&lt;/u&gt;&lt;br&gt;
To install SonarQube, we need to ensure Java is already installed.&lt;br&gt;
The next thing we will have to do is move to the root directory, so that we can have admin privileges, using the commands below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su -
apt install unzip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpz5cegxbpu16h7vqikc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpz5cegxbpu16h7vqikc.png" alt="Install Unzip!" width="800" height="414"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adduser sonarqube
sudo su - sonarqube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1v735kjiw3d3c5hlg41q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1v735kjiw3d3c5hlg41q.png" alt="Add Sonarqube as a User!" width="564" height="336"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-9.4.0.54424.zip

unzip *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcohfqkw7vx4g1eblxnf6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcohfqkw7vx4g1eblxnf6.png" alt="Download Sonarqube binary and Unzip!" width="800" height="435"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod -R 755 /home/sonarqube/sonarqube-9.4.0.54424

chown -R sonarqube:sonarqube /home/sonarqube/sonarqube-9.4.0.54424

cd sonarqube-9.4.0.54424/bin/linux-x86–64/

./sonar.sh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can verify the status of SonarQube via this command: &lt;code&gt;./sonar.sh status&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floss61zb509n9ed5qbku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floss61zb509n9ed5qbku.png" alt="Start Sonarqube!" width="710" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait for SonarQube to start (2–3 minutes), then access your SonarQube on your browser via &lt;a href="http://54.245.159.36:9000/" rel="noopener noreferrer"&gt;http://54.245.159.36:9000/&lt;/a&gt; {ensure to input your EC2 IP address)&lt;br&gt;
The Default login details will be: admin/admin. You will need to change the default password to a new one in the next tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vhaz8ufxzmez5zrexv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vhaz8ufxzmez5zrexv5.png" alt="Login to the SonarQube server!" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will generate a Sonar Token. To do that, navigate to 'my account' at the top right corner, then go to the settings tab, and click on generate token to generate a token to allow GitLab CI/CD to communicate with your SonarQube server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4p4gg0mdmfqjfhm46pzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4p4gg0mdmfqjfhm46pzy.png" alt="Generate the sonarqube token!" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STEP 3: &lt;u&gt;Secure Your CI/CD&lt;/u&gt;&lt;br&gt;
We will input the SonarQube token into our GitLab variables. To do this, we will go to the settings tab on GitLab, select CICD and click on variables. Go to GitLab → Settings → CI/CD → Variables&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0yp25rp645epzkd5n6pc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0yp25rp645epzkd5n6pc.png" alt="Configure secrets on Gitlab" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the token API key to the GitLab CICD variables:&lt;br&gt;
Key = SONAR_LOGIN&lt;br&gt;
Value = cd14b6f8bb12f8a7a94127f3ce1044516d33a5fa&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3b45tfrpdh65kd42cvwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3b45tfrpdh65kd42cvwc.png" alt="Added the SonarQube token to my GitLab variables" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure GitLab CI/CD Variables&lt;br&gt;
Add these variables (mask sensitive ones):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SONAR_HOST_URL&lt;/code&gt;: &lt;code&gt;http://&amp;lt;your-ec2-public-ip&amp;gt;:9000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SONAR_LOGIN&lt;/code&gt;: The token you generated in SonarQube&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DOCKER_USENAME&lt;/code&gt;: (if pushing to Docker registry)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DOCKER_PASSWORD&lt;/code&gt;: (if pushing to Docker registry)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STEP 4: &lt;u&gt;Register GitLab Runner on EC2&lt;/u&gt;&lt;br&gt;
We will have to create a runner, so we can always have backend access to it and be in full control of the runner. We will install the runner on our instance. To set up the runner, we will navigate to the settings, then CICD, then runners: Settings → CI/CD → Variables&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbutp4kr7q1lrrgqqn3te.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbutp4kr7q1lrrgqqn3te.png" alt="To create a Gitlab Runner" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmno8aeo6xby96b35662e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmno8aeo6xby96b35662e.png" alt="To create a Gitlab Runner" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;a. Install GitLab Runner&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Download the binary for your system
sudo curl -L - output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

# Give it permission to execute
sudo chmod +x /usr/local/bin/gitlab-runner

# Create a GitLab Runner user
sudo useradd - comment 'GitLab Runner' - create-home gitlab-runner - shell /bin/bash

# Install and run as a service
sudo gitlab-runner install - user=gitlab-runner - working-directory=/home/gitlab-runner

sudo gitlab-runner start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fece4a5t2ntnuhjm5dx9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fece4a5t2ntnuhjm5dx9h.png" alt="Download GitLab runner and run as a service!" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Command to register runner&lt;br&gt;
&lt;code&gt;sudo gitlab-runner register - url https://gitlab.com - token glrt-92fA16tAk07hUeItqxgyj286MQpwOjE2Y2QwYwp0OjMKdTpneHBzNhg.01.1j1fxtc8g&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Follow prompts:&lt;br&gt;
GitLab URL: &lt;a href="https://gitlab.com/" rel="noopener noreferrer"&gt;https://gitlab.com/&lt;/a&gt;&lt;br&gt;
Registration token: (get from GitLab project → Settings → CI/CD → Runners → Expand)&lt;br&gt;
Description: my-runner&lt;br&gt;
Tags: Docker&lt;br&gt;
Executor: docker&lt;br&gt;
Docker image: uwadon01/maven-uwadon1-docker-agent:v1&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5o8hqoljfxpsqylgfcbj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5o8hqoljfxpsqylgfcbj.png" alt="Register runner!" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7xyodzwcgnqy9olei3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7xyodzwcgnqy9olei3w.png" alt="Runner Installation command!" width="755" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An equivalent Dockerfile sample that replicates the &lt;code&gt;uwadon01/maven-uwadon1-docker-agent:v1&lt;/code&gt; image with modern best practices:&lt;br&gt;
Reconstructed Dockerfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dockerfile

# Start with the same base as the original (Ubuntu-based)
FROM ubuntu:20.04
# Set environment variables to match original
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
JAVA_VERSION=jdk-11.0.11+9 \
JAVA_HOME=/opt/java/openjdk \
MAVEN_VERSION=3.8.1 \
MAVEN_HOME=/usr/share/maven \
MAVEN_CONFIG=/root/.m2
# Install base dependencies (matches original apt commands)
RUN apt-get update &amp;amp;&amp;amp; \
apt-get install -y - no-install-recommends \
curl \
ca-certificates \
gnupg \
git \
bash \
docker.io \
&amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
# Install AdoptOpenJDK 11 (matches original version)
RUN mkdir -p /opt/java/openjdk &amp;amp;&amp;amp; \
curl -L https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.11+9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.11_9.tar.gz | \
tar -xz -C /opt/java/openjdk - strip-components=1
# Install Maven 3.8.1 (matches original)
RUN mkdir -p /usr/share/maven /usr/share/maven/ref &amp;amp;&amp;amp; \
curl -L https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz | \
tar -xz -C /usr/share/maven - strip-components=1 &amp;amp;&amp;amp; \
ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
# Copy the original maven entrypoint script (recreated from inspection)
RUN echo $'#!/bin/sh\n\
# Licensed to the Apache Software Foundation (ASF) under one\n\
# or more contributor license agreements. See the NOTICE file\n\
# distributed with this work for additional information\n\
# regarding copyright ownership. The ASF licenses this file\n\
# to you under the Apache License, Version 2.0 (the\n\
# "License"); you may not use this file except in compliance\n\
# with the License. You may obtain a copy of the License at\n\
#\n\
# http://www.apache.org/licenses/LICENSE-2.0\n\
#\n\
# Unless required by applicable law or agreed to in writing,\n\
# software distributed under the License is distributed on an\n\
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n\
# KIND, either express or implied. See the License for the\n\
# specific language governing permissions and limitations\n\
# under the License.\n\
\n\
# For backwards compatibility with older versions of Docker\n\
if [ "$1" = "mvn" ]; then\n\
shift\n\
fi\n\
exec "$@"' &amp;gt; /usr/local/bin/mvn-entrypoint.sh &amp;amp;&amp;amp; \
chmod +x /usr/local/bin/mvn-entrypoint.sh
# Set working directory and entrypoint
WORKDIR /workspace
ENTRYPOINT ["/usr/local/bin/mvn-entrypoint.sh"]
CMD ["mvn"]
# Verify installations
RUN mvn - version &amp;amp;&amp;amp; \
java - version &amp;amp;&amp;amp; \
docker - version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt;How to Build and Use&lt;/u&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the image:
&lt;code&gt;docker build -t maven-uwadon1-docker-agent:v1 .&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verify it matches the original:
&lt;code&gt;docker run -it - rm maven-uwadon1-docker-agent:v1 bash -c "mvn - version; docker - version; java - version"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Push to your registry:
&lt;code&gt;docker tag maven-uwadon1-docker-agent:v1 yourusername/maven-yourname-docker-agent:v1&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker push yourusername/maven-yourname-docker-agent:v1&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  For GitLab CI/CD Usage
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yaml
image: uwadon01/maven-uwadon1-docker-agent:v1
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
build:
script:
- mvn clean install
- docker build -t myapp .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Dockerfile image sample provides the same functionality as the original but with a more maintainable and transparent construction.&lt;br&gt;
PS: You can decide to use my Docker image, but you have to retag it; here's how to retag an existing image for use:&lt;br&gt;
Pull the original image:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker pull uwadon01/maven-uwadon1-docker-agent:v1&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retag the image (to your own registry or for local use):
&lt;code&gt;docker tag uwadon01/maven-uwadon1-docker-agent:v1 yourusername/maven-yourname-docker-agent:v1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Push to your registry (if needed)
&lt;code&gt;docker push yourusername/maven-yourname-docker-agent:v1&lt;/code&gt;
You can view the runner that was just created. You will see a green dot beside it, which shows it is now active.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqko24523zy3i9kfkyuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqko24523zy3i9kfkyuj.png" alt="View active executor!" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;STEP 5: &lt;u&gt;Create/Edit the .gitlab-ci.yml in your Spring Boot repo&lt;/u&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image: 'uwadon01/maven-uwadon1-docker-agent:v1'
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ''
# SONAR_HOST_URL: http://54.237.226.245:9000
# SONAR_LOGIN: ${SONAR_LOGIN}
# Define the default working directory for the pipeline
before_script:
- cd java-maven-sonar-argocd-helm-k8s/spring-boot-app
stages:
- build
- test
- sonarqube
# - dockerization
build-job:
stage: build
tags:
- docker
script:
- echo "Compiling the code…"
- mvn clean package
unit-test-job:
stage: test
tags:
- docker
script:
- echo "Running unit tests… This will take about 60 seconds."
- mvn test
code-quality-job:
stage: sonarqube
tags:
- docker
script:
- echo "scanning code"
- mvn sonar:sonar -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_LOGIN}
#docker:
# stage: dockerization
# image: docker:19.03
# services:
# - name: docker:dind
# script:
# - whoami
# - docker build -t gitlab-cicd-demo:latest .
# - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
# - docker tag gitlab-cicd-demo:latest $DOCKER_USERNAME/gitlab-cicd-demo:latest
# - docker push $DOCKER_USERNAME/gitlab-cicd-demo:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STEP 6: &lt;u&gt;Push and Trigger Pipeline&lt;/u&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .gitlab-ci.yml

git commit -m "Add GitLab CI/CD pipeline"

git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipeline will now run the various commands listed in your .gitlab.yml file&lt;br&gt;
You can view the progress in the pipeline dashboard&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbim04kmz0wiajlaj22vm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbim04kmz0wiajlaj22vm.png" alt="View The Pipeline running!" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3duwueowbniv5ysa9vsh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3duwueowbniv5ysa9vsh.png" alt="View the pipeline result!" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This command will build the Spring Boot app using our Docker image, run the unit tests and send code analysis to SonarQube. You can view the result by logging in to your SonarQube project dashboard&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmb4lpobxw33gb5hq525.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmb4lpobxw33gb5hq525.png" alt="View Sonarqube result!" width="800" height="389"&gt;&lt;/a&gt;\&lt;/p&gt;

&lt;p&gt;✅ TROUBLESHOOTING&lt;br&gt;
Issue &amp;amp; Solution&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Runner says "no tags match"&lt;/em&gt;&lt;br&gt;
Make sure your job has the correct tags: matching your runner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;SonarQube is not accessible&lt;/em&gt;&lt;br&gt;
Ensure port 9000 is open and the container is running&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;App not reachable&lt;/em&gt;&lt;br&gt;
Make sure your app binds to 0.0.0.0:8080, not localhost&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Docker permission issues&lt;/em&gt;&lt;br&gt;
Ensure the user is in the Docker group&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;SonarQube Issues&lt;/em&gt;&lt;br&gt;
Check logs: &lt;code&gt;docker logs sonarqube&lt;/code&gt;, Ensure enough memory (t2.medium should be sufficient)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maven Build Issues&lt;br&gt;
Clear cache: &lt;code&gt;mvn dependency:purge-local-repository&lt;/code&gt;, Check network connectivity from EC2&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NB: To edit the runner configuration:&lt;br&gt;
sudo nano /etc/gitlab-runner/config.toml&lt;/p&gt;

&lt;p&gt;Afterwards, you can restart the runner:&lt;br&gt;
&lt;code&gt;sudo gitlab-runner restart&lt;/code&gt;&lt;br&gt;
Ensure your Spring Boot project has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pom.xml&lt;/code&gt; with required dependencies and &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; at the root&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This comprehensive guide provides a complete walkthrough to set up a GitLab CI/CD pipeline for a Spring Boot Java application using a specific GitLab Runner on an EC2 t2.medium instance with Docker executor, Maven image, and hosting SonarQube on the same instance.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>cicd</category>
      <category>devops</category>
      <category>aws</category>
    </item>
    <item>
      <title>Deploying a Secure Static Website using AWS EC2, Route 53, and Certbot in AWS</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Tue, 15 Jul 2025 13:31:32 +0000</pubDate>
      <link>https://dev.to/uwadon1/deploying-a-secure-static-website-using-aws-ec2-route-53-and-certbot-in-aws-2p0b</link>
      <guid>https://dev.to/uwadon1/deploying-a-secure-static-website-using-aws-ec2-route-53-and-certbot-in-aws-2p0b</guid>
      <description>&lt;p&gt;A Comprehensive Walkthrough to deploy a secure, high-performance static website&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgzgqksz37jznm5fwnyj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgzgqksz37jznm5fwnyj.jpeg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Overview of Architecture
&lt;/h3&gt;

&lt;p&gt;This guide provides a step-by-step, real-world approach to deploying a static website on AWS using:&lt;br&gt;
Host a static website using Nginx (Web Server) on an EC2 instance (Virtual Server)..&lt;/p&gt;

&lt;p&gt;Point a custom domain from Route 53 (DNS &amp;amp; Domain Management) to that server.&lt;/p&gt;

&lt;p&gt;Secure it with SSL/TLS certificates using Certbot &amp;amp; Let’s Encrypt.&lt;/p&gt;
&lt;h3&gt;
  
  
  📌 Prerequisites
&lt;/h3&gt;

&lt;p&gt;✅ AWS account: free-tier eligible (with necessary permissions to use EC2, Route 53, and Security Groups)&lt;/p&gt;

&lt;p&gt;✅ Domain name (already registered via Route 53)&lt;/p&gt;

&lt;p&gt;✅ Basic static website files (HTML/CSS/JS)&lt;/p&gt;

&lt;p&gt;✅ SSH key pair to access the EC2 instance&lt;/p&gt;

&lt;p&gt;✅ AWS CLI &amp;amp; access to terminal (e.g., VS Code terminal or local shell)&lt;/p&gt;

&lt;p&gt;✅ Basic Linux CLI Knowledge (SSH, file editing)  &lt;/p&gt;
&lt;h2&gt;
  
  
  🚀 Step-by-Step Guide
&lt;/h2&gt;
&lt;h3&gt;
  
  
  🟩 Step 1: Launch a Secure EC2 Instance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Launched an Ubuntu EC2 Instance named “jodinho_agency_server” with AMI of 24.04 LTS (HVM) in the us-west-2 region using the AWS console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvihb5ta2brwzje7i2r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvihb5ta2brwzje7i2r8.png" alt="Create Server Name" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Gave it the instance type of t2.micro which is within the free-tier. Created SSH key pair named &lt;strong&gt;jodinho-kp&lt;/strong&gt; to access the instance on port 22.  The default VPC and Subnet were used for the networking configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpywhp2rwxoqib2i3p5xm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpywhp2rwxoqib2i3p5xm.png" alt="Instance Type" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; The security group was configured with the following inbound rules:&lt;/p&gt;

&lt;p&gt;Allow traffic on port 22 (SSH) with source IP addresses from any location.&lt;br&gt;
Allow traffic on port 443 (HTTPS) with source from anywhere on the internet.&lt;br&gt;
Allow traffic on port 80 (HTTP) with source from anywhere on the internet.&lt;br&gt;
 And we’ll leave the storage at default, 8GB GP3 volume storage. Then we hit the launch instance button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg2y4c6gk37qt9pkqb5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg2y4c6gk37qt9pkqb5p.png" alt="Security Rules" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; First, we need to move the keypair file from the download folder into the .ssh folder; &lt;br&gt;
 &lt;code&gt;cp ~/Downloads/jodinho-kp.pem ~/.ssh/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The private SSH key that got downloaded has now been moved, the permission was changed for the private key file and then used to connect to the instance by running the following commands;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chmod 400 ~/.ssh/jodinho-kp.pem&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh -i ~/.ssh/jodinho-kp.pem ubuntu@54.212.87.210&lt;/code&gt;&lt;br&gt;
Where &lt;strong&gt;username=ubuntu&lt;/strong&gt; and &lt;strong&gt;public ip address=54.212.87.210&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxs2wznmfjlvkaift3myx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxs2wznmfjlvkaift3myx.png" alt="Connect to instance" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  🟩 Step 2: Update &amp;amp; Install Nginx
&lt;/h3&gt;
&lt;h2&gt;
  
  
  Step 1 - Install Nginx web server
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Update and upgrade the server’s package index&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run a sudo apt update to download package information from all configured sources.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6ez6x6mldy1ppsiqcvy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6ez6x6mldy1ppsiqcvy.png" alt="Update Packages" width="502" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run a sudo apt upgrade to upgrade the package&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt upgrade -y&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4k61aat01qmd1rcr2kq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4k61aat01qmd1rcr2kq.png" alt="Upgrade Packages" width="585" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Install nginx&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run a sudo apt install nginx -y to install nginx &lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt install nginx -y&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7prnzznu6egqw3wtvqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7prnzznu6egqw3wtvqm.png" alt="Install Nginx" width="666" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Verify that nginx is active and running&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To verify Nginx server has been installed and is running, we will run the following command&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl status nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If it's green and running, then nginx is correctly installed&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn4l1ndmdc0oru5q82pw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn4l1ndmdc0oru5q82pw.png" alt="Nginx Status" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Access nginx locally on the Ubuntu shell&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accessing the default nginx web server block to see if everything works correctly. curl the local IP address of our local machine, which in most cases is 127.0.0.1 or the DNS name localhost, on any web browser on our local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://54.212.87.210
curl http://localhost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The below result shows Nginx has been properly set up, and we can deploy our web application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmx1eomy7oyv6zgdsx8w2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmx1eomy7oyv6zgdsx8w2.png" alt="Local URL" width="520" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Test with the public IP address if the Nginx server can respond to requests from the internet using the URL in a browser.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://54.212.87.210&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0un1o3nvaly8s2xadlo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0un1o3nvaly8s2xadlo.png" alt="Nginx Default Page" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shows that the web server is correctly installed and is accessible through the firewall.&lt;/p&gt;

&lt;h3&gt;
  
  
  🟩 Step 3: Upload Static Website Files
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; So we will clone the website from our Gitlab repo here using the command below:&lt;br&gt;
Git clone &lt;a href="https://gitlab.com/uwadon1-group/jodinho-digital-website.git" rel="noopener noreferrer"&gt;https://gitlab.com/uwadon1-group/jodinho-digital-website.git&lt;/a&gt; Next, we will change directory into the just cloned repo using the command cd jodinho-digital-website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fek35p72m033mlla0e50c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fek35p72m033mlla0e50c.png" alt="Clone repo from Gitlab" width="753" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Nginx has its default page where it serves its contents. We can move into the folder for the Nginx default page to check it out using the command: cd /var/www/html. When we type LS, we can see the Nginx default HTML page, e.g index.nginx-debian.html. To see the content, we type in cat index.nginx-debian.html and see the exact content we saw on the browser earlier, but in HTML format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xo35ut48owdsmyqa3so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xo35ut48owdsmyqa3so.png" alt="Nginx default html page" width="547" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Now, we will copy all our files nginx /var/www/html directory to replace the default page that was initially served. To do that, we will use the following command: &lt;br&gt;
&lt;code&gt;sudo cp -r jodinho-digital-website/* /var/www/html&lt;/code&gt;. But before then, we will have to remove the default file nginx index page, using the command: &lt;code&gt;sudo rm index.nginx-debian.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cgtxwyfm957x2djoxzj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cgtxwyfm957x2djoxzj.png" alt="Replace Nginx Default Page" width="743" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; We will input our IP address into the browser again, other things being equal, the website we replaced on Nginx should reflect this time, even without restarting the Nginx server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq0z94fnml9gyhssv0gn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq0z94fnml9gyhssv0gn.png" alt="The New Nginx Default Page" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  🟩 Step 4: Point Route 53 Domain to EC2
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; What we want to do now is to link our IP address to our domain name, so instead of sharing IP addresses with visitors of your website, the best practice is to give them your domain name to input into the browser. We already have a domain name, so what we will do now is to map it to the IP address. If you need guidance on creating a domain on Route 53, this guide should help you&lt;/p&gt;

&lt;p&gt;We will search for Route 53 service from the AWS search bar, and click on hosted zone, you will see your domain name, click on it and select create record. Input your record name, e.g, &lt;code&gt;jodinho.uwhadone.click&lt;/code&gt;, Record Type: &lt;code&gt;A&lt;/code&gt;, in the space of values, input your IP address, e.g, 54.212.87.210, leave the other options as default and click create record.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm78vgyq48tayywjpwdjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm78vgyq48tayywjpwdjd.png" alt="Create a new DNS record" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will wait a few minutes, then visit our domain via the browser &lt;code&gt;http://jodinho.uwhadone.click&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Now, we have to make our website more secure via HTTPS rather than HTTP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; We will head back to our terminal and go to the directory serving our nginx configuration file located at /etc using the command:&lt;br&gt;
cd /etc/nginx. Type LS to see a list of all the files and folders here. Our major concern here would be sites-enabled, that's where we can find the list of sites. We want our Nginx server to serve visitors. We will cd into this directory and delete the default configuration file there and create a new one to replace it, using this command: &lt;code&gt;sudo rm default&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8pdvq5o1azdh6u00kbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8pdvq5o1azdh6u00kbv.png" alt="The Nginx /etc-sites" width="712" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will create a new nginx config file via the vim editor using the command below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo vim default&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And paste the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;   &lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;jodinho.uwhadone.click&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

       &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

       &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10c5jyrkt2vpezthxa7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10c5jyrkt2vpezthxa7n.png" alt="Nginx Config file" width="425" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; We can verify the syntax of our nginx configuration file is correct and also reload the nginx server using the commands below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt; 
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp92ubrjfrfgocbz3gfor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp92ubrjfrfgocbz3gfor.png" alt="Verify and Reload The Nginx Config File" width="564" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🟩 Step 6: Install Certbot &amp;amp; Enable HTTPS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Now we need to get rid of HTTP and make use of HTTPS in order to make our website more secure. We will have to install certbot (this is a free software that enables us to configure nginx to use TLS &amp;amp; SSL certificates for HTTPS)&lt;/p&gt;

&lt;p&gt;We will install certbot using the following command:&lt;br&gt;
&lt;code&gt;sudo apt install certbot python3-certbot-nginx -y&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfa9mc2f72d9zgnqdjer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfa9mc2f72d9zgnqdjer.png" alt="Install Certbot" width="738" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will type in this command &lt;code&gt;sudo certbot --nginx -d jodinho.uwhadone.click&lt;/code&gt;.  (What this command would do is to look through the Nginx configuration file and enable HTTPS. &lt;br&gt;
A prompt will come up to type in your email address, type in yes for the remaining options, and you will see an update that it is requesting a certificate for your domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcykknr6fs9uvrdhb16tv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcykknr6fs9uvrdhb16tv.png" alt="Certificate obtained" width="643" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Now we will navigate back to our nginx config file to observe some changes in it. You will observe that certbot has made some adjustments to our nginx config file. You will also observe the SSL keys placed beside the nginx configuration&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqroxvfdlldr53yto5by.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqroxvfdlldr53yto5by.png" alt="Install Certbot" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Now we will have to restart nginx to observe the change in our website from being unsecured to HTTPS secured.&lt;/p&gt;

&lt;p&gt;Run the command: &lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9qbami4b76q2epdbjc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9qbami4b76q2epdbjc7.png" alt="Access secure-website" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Deployment Complete!
&lt;/h3&gt;

&lt;p&gt;🎉 Final Result&lt;br&gt;
Static site hosted on AWS EC2&lt;br&gt;
Custom domain via Route 53&lt;br&gt;
Free SSL (HTTPS) via Certbot&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>route</category>
      <category>domainname</category>
      <category>aws</category>
    </item>
    <item>
      <title>MEAN Stack (WEB STACK) Implementation in AWS</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Fri, 25 Apr 2025 07:29:48 +0000</pubDate>
      <link>https://dev.to/uwadon1/mean-stack-web-stack-implementation-in-aws-4dcb</link>
      <guid>https://dev.to/uwadon1/mean-stack-web-stack-implementation-in-aws-4dcb</guid>
      <description>&lt;h2&gt;
  
  
  MEAN WEB STACK IMPLEMENTATION IN AWS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv1jbz045kn0hzs6i1vu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv1jbz045kn0hzs6i1vu.png" alt="Mean Stack" width="318" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The MEAN stack is a popular JavaScript stack used for building web applications. It stands for MongoDB, Express.js, AngularJS (or Angular), and Node.js. Here's a brief overview of each component:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MongoDB:&lt;/strong&gt; MongoDB is a NoSQL database that stores data in a flexible, JSON-like format. It is a popular choice for web applications because of its scalability, flexibility, and performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Express.js:&lt;/strong&gt; Express.js is a web application framework for Node.js. It provides a set of features for building web applications and APIs, including routing, middleware support, and templating engines. Express.js simplifies the process of building web applications with Node.js by providing a high-level abstraction over the HTTP protocol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AngularJS (or Angular):&lt;/strong&gt; AngularJS is a JavaScript framework maintained by Google for building dynamic web applications. It extends HTML with additional attributes and provides a set of built-in directives for creating interactive user interfaces. AngularJS follows the Model-View-Controller (MVC) architecture, making it easy to organize code and build complex web applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js:&lt;/strong&gt; Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It allows developers to run JavaScript code outside of a web browser, making it possible to build server-side applications with JavaScript. Node.js is known for its event-driven, non-blocking I/O model, which makes it well-suited for building scalable and high-performance web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Launched an Ubuntu EC2 Instance named “Mean_Stack_Server” with AMI of 22.04 LTS (HVM) in the us-west-2 region using the AWS console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1uaafwqv7p2wsmq4b56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1uaafwqv7p2wsmq4b56.png" alt="Create Server Name" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Gave it the instance type of t3.small. &lt;/p&gt;

&lt;p&gt;The choice of the instance type was based on the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory:&lt;/strong&gt; The t3.small instance offers more memory than the t2.micro, which is advantageous for applications that require more memory to operate efficiently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Burst Capability:&lt;/strong&gt; While both instances offer burstable CPU performance, the t3 instances have a more flexible burst model, allowing for more sustained performance during burst periods. This is important for workloads that require consistent performance over longer periods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt; While both instances offer burstable performance, the t3.small typically provides better baseline performance compared to the t2.micro. This might be necessary for applications that require a bit more processing power.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Created SSH key pair named &lt;strong&gt;mean_stack&lt;/strong&gt; to access the instance on port 22.  The default VPC and Subnet were used for the networking configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0su3lidt0lftvo17t0hy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0su3lidt0lftvo17t0hy.png" alt="Instance Type" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; The security group was configured with the following inbound rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow traffic on port 22 (SSH) with source from any IP address. &lt;/li&gt;
&lt;li&gt;Allow traffic on port 443 (HTTPS) with source from anywhere on the internet.&lt;/li&gt;
&lt;li&gt;Allow traffic on port 80 (HTTP) with source from anywhere on the internet. (All these would be set by default, later we would go into the security group to set the remaining 2 inbound rules manually.)
*- Allow traffic on port 3300 (Custom TCP) with source from anywhere.
*- Allow traffic on port 27017 (Custom TCP) with source from anywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will leave the storage at default; 8gb gp3 volume storage. Then we hit the launch instance button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxp1m02d85bar1di440h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxp1m02d85bar1di440h.png" alt="Security Rules" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90y34vxu1gha93xq8p6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90y34vxu1gha93xq8p6g.png" alt="Security Rules" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; First, we need to move the keypairs file from the download folder into the .ssh folder; &lt;br&gt;
 &lt;code&gt;cp ~/Downloads/mean_stack.pem ~/.ssh/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The private SSH key that got downloaded has now been moved, permission was changed for the private key file and then used to connect to the instance by running the following commands;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chmod 400 ~/.ssh/mean_stack.pem&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh -i ~/.ssh/mean_stack.pem ubuntu@52.32.32.193&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where &lt;strong&gt;username=ubuntu&lt;/strong&gt; and &lt;strong&gt;public ip address=52.32.32.193&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1 - Install Nodejs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bz6sb3oeldhjrj6exbi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bz6sb3oeldhjrj6exbi.png" alt="SSH into Instance" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine. Node.js is used in this tutorial to set up the Express routes and AngularJS controllers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Update and Upgrade ubuntu&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpmk3jm5jrmy5gh9kwws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpmk3jm5jrmy5gh9kwws.png" alt="Update ubuntu" width="698" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Add certificates&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;curl dirmngr apt-transport-https lsb-release ca-certificates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccaumbn9m6cm7w3rxzah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccaumbn9m6cm7w3rxzah.png" alt="Add cert" width="754" height="521"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://deb.nodesource.com/setup_18.x | &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; bash -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqychjghz3bn7isek9c5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqychjghz3bn7isek9c5z.png" alt="Add cert" width="588" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.3&lt;/strong&gt; &lt;strong&gt;Install NodeJS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt-get install -y nodejs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjig7v7bblrda0aqm5poo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjig7v7bblrda0aqm5poo.png" alt="Install nodejs" width="593" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Install MongoDB
&lt;/h2&gt;

&lt;p&gt;For this application, Book records were added to MongoDB that contain books name, ISBN number, author, and number of pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Download the MongoDB public GPG key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl -fsSL https://pgp.mongodb.com/server-7.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-archive-keyring.gpg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Add the MongoDB repository&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;echo "deb [ signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusvniccawaxejkq3uii7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusvniccawaxejkq3uii7.png" alt="Mongo public key" width="800" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Update the package database and install MongoDB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;sudo apt-get update&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivum690qo4pkooe28p5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivum690qo4pkooe28p5j.png" alt="Update server" width="731" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt-get install -y mongodb-org&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xgjfuxq2k01x2sqlnuo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xgjfuxq2k01x2sqlnuo.png" alt="Install mongodb" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Start and enable MongoDB&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl start mongod

sudo systemctl enable mongod

sudo systemctl status mongod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftedpauwedjvagq8476xk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftedpauwedjvagq8476xk.png" alt="Start Mongodb" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Install body-parser package&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;body-parser&lt;/strong&gt; package is needed to help process JSON files passed in requests to the server.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo npm install body-parser&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewgh3xalovn4wfe5rkgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewgh3xalovn4wfe5rkgs.png" alt="Install body parser" width="547" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;Create the project root folder named ‘Books’&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir Books &amp;amp;&amp;amp; cd Books&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Initialize the root folder&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zcdwg0wh30ogxkngwa2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zcdwg0wh30ogxkngwa2.png" alt="Init folder" width="781" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add file named server.js to Books folder&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim server.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the web server code below into the server.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose'); // Make sure mongoose is installed and required
const path = require('path'); // To handle static file serving
const app = express();

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/test')
  .then(() =&amp;gt; console.log('MongoDB connected'))
  .catch(err =&amp;gt; console.error('MongoDB connection error:', err));


// Middleware
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));

// Routes
require('./apps/routes')(app);

// Start the server
app.set('port', 3300);
app.listen(app.get('port'), () =&amp;gt; {
  console.log('Server up: http://localhost:' + app.get('port'));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rhvfaum23z9n7sj35mc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rhvfaum23z9n7sj35mc.png" alt="Server.js" width="589" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Install Express and set up routes to the server
&lt;/h2&gt;

&lt;p&gt;Express was used to pass book information to and from our MongoDB database.&lt;br&gt;
Mongoose package provides a straightforward schema-based solution to model the application data. Mongoose was used to establish a schema for the database to store data of the book register.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Install express and mongoose&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo npm install express mongoose&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76p9rehydcorkadz5wxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76p9rehydcorkadz5wxk.png" alt="Install express" width="462" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;In Books folder, create a folder named ‘apps’&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir apps &amp;amp;&amp;amp; cd apps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In apps, create a file named routes.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim routes.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the code below into routes.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Book = require('./models/book');
const path = require('path');

module.exports = function(app) {
  // Get all books
  app.get('/book', async (req, res) =&amp;gt; {
    try {
      const books = await Book.find({});
      res.json(books);
    } catch (err) {
      console.error(err);
      res.status(500).json({ error: 'Internal Server Error' });
    }
  });

  // Add a new book
  app.post('/book', async (req, res) =&amp;gt; {
    try {
      const book = new Book({
        name: req.body.name,
        isbn: req.body.isbn,
        author: req.body.author,
        pages: req.body.pages
      });
      const result = await book.save();
      res.json({
        message: "Successfully added book",
        book: result
      });
    } catch (err) {
      console.error(err);
      res.status(500).json({ error: 'Internal Server Error' });
    }
  });

  // Update a book
  app.put('/book/:isbn', async (req, res) =&amp;gt; {
    try {
      const updatedBook = await Book.findOneAndUpdate(
        { isbn: req.params.isbn },
        req.body,
        { new: true }
      );
      if (!updatedBook) {
        return res.status(404).json({ error: 'Book not found' });
      }
      res.json({
        message: "Successfully updated the book",
        book: updatedBook
      });
    } catch (err) {
      console.error(err);
      res.status(500).json({ error: 'Internal Server Error' });
    }
  });

  // Delete a book
  app.delete('/book/:isbn', async (req, res) =&amp;gt; {
    try {
      const result = await Book.findOneAndRemove({ isbn: req.params.isbn });
      if (!result) {
        return res.status(404).json({ error: 'Book not found' });
      }
      res.json({
        message: "Successfully deleted the book",
        book: result
      });
    } catch (err) {
      console.error(err);
      res.status(500).json({ error: 'Internal Server Error' });
    }
  });

  // Serve static files
  app.get('*', (req, res) =&amp;gt; {
    res.sendFile(path.join(__dirname, '../public', 'index.html'));
  });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vta3y07wd06u3jgrq0y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vta3y07wd06u3jgrq0y.png" alt="Routes" width="606" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;In the ‘apps’ folder, create a folder named models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir models &amp;amp;&amp;amp; cd models&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In models, create a file named book.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim book.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmeh7j5cxgg2fzfd7p65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmeh7j5cxgg2fzfd7p65.png" alt="Create Models file and change directory" width="381" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the code below into book.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');

const bookSchema = new mongoose.Schema({
  name: { type: String, required: true },
  isbn: { type: String, required: true, unique: true },
  author: { type: String, required: true },
  pages: { type: Number, required: true }
});

module.exports = mongoose.model('Book', bookSchema);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4z8shg2w1m9vg6bhcd3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4z8shg2w1m9vg6bhcd3f.png" alt="Books" width="423" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Access the routes with AngularJS
&lt;/h2&gt;

&lt;p&gt;In this project, AngularJS was used to connect the web page with Express and perform actions on the book register.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Change the directory back to ‘Books’ and create a folder named ‘public’&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ../..

mkdir public &amp;amp;&amp;amp; cd public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add a file named script.js into public folder&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim script.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the code below (controller configuration defined) into the script.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var app = angular.module('myApp', []);

app.controller('myCtrl', function($scope, $http) {
  // Get all books
  function getAllBooks() {
    $http({
      method: 'GET',
      url: '/book'
    }).then(function successCallback(response) {
      $scope.books = response.data;
    }, function errorCallback(response) {
      console.log('Error: ' + response.data);
    });
  }

  // Initial load of books
  getAllBooks();

  // Add a new book
  $scope.add_book = function() {
    var body = {
      name: $scope.Name,
      isbn: $scope.Isbn,
      author: $scope.Author,
      pages: $scope.Pages
    };
    $http({
      method: 'POST',
      url: '/book',
      data: body
    }).then(function successCallback(response) {
      console.log(response.data);
      getAllBooks();  // Refresh the book list
      // Clear the input fields
      $scope.Name = '';
      $scope.Isbn = '';
      $scope.Author = '';
      $scope.Pages = '';
    }, function errorCallback(response) {
      console.log('Error: ' + response.data);
    });
  };

  // Update a book
  $scope.update_book = function(book) {
    var body = {
      name: book.name,
      isbn: book.isbn,
      author: book.author,
      pages: book.pages
    };
    $http({
      method: 'PUT',
      url: '/book/' + book.isbn,
      data: body
    }).then(function successCallback(response) {
      console.log(response.data);
      getAllBooks();  // Refresh the book list
    }, function errorCallback(response) {
      console.log('Error: ' + response.data);
    });
  };

  // Delete a book
  $scope.delete_book = function(isbn) {
    $http({
      method: 'DELETE',
      url: '/book/' + isbn
    }).then(function successCallback(response) {
      console.log(response.data);
      getAllBooks();  // Refresh the book list
    }, function errorCallback(response) {
      console.log('Error: ' + response.data);
    });
  };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w9dqx5jdlrrshp9rlq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w9dqx5jdlrrshp9rlq4.png" alt="Script.js" width="582" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;In ‘public’ folder, create a file named index.html&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the code below into &lt;em&gt;index.html&lt;/em&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html ng-app="myApp" ng-controller="myCtrl"&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src="script.js"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;style&amp;gt;
    /* Add your custom CSS styles here */
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;table&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Name:&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;input type="text" ng-model="Name"&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Isbn:&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;input type="text" ng-model="Isbn"&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Author:&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;input type="text" ng-model="Author"&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Pages:&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;input type="number" ng-model="Pages"&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
    &amp;lt;/table&amp;gt;
    &amp;lt;button ng-click="add_book()"&amp;gt;Add&amp;lt;/button&amp;gt;
    &amp;lt;div ng-if="successMessage"&amp;gt;{{ successMessage }}&amp;lt;/div&amp;gt;
    &amp;lt;div ng-if="errorMessage"&amp;gt;{{ errorMessage }}&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;hr&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;table&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Isbn&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Author&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Page&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Action&amp;lt;/th&amp;gt;
      &amp;lt;/tr&amp;gt;
      &amp;lt;tr ng-repeat="book in books"&amp;gt;
        &amp;lt;td&amp;gt;{{ book.name }}&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;{{ book.isbn }}&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;{{ book.author }}&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;{{ book.pages }}&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;button ng-click="del_book(book)"&amp;gt;Delete&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
    &amp;lt;/table&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok0dk144wowbj11yu9we.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok0dk144wowbj11yu9we.png" alt="HTML" width="590" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Change the directory back up to ‘Books’ and start the server&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ..

node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mi1w70azvndecicczoj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mi1w70azvndecicczoj.png" alt="Run server" width="294" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The server is now up and running, Connection to it is via port 3300. A separate Putty or SSH console to test what curl command returns locally can be launched.&lt;/p&gt;

&lt;p&gt;The Book Register web application can now be accessed from the internet with a browser using the Public IP address or Public DNS name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f8of5yqtav8zq9njua4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f8of5yqtav8zq9njua4.png" alt="Book register" width="732" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add more books to the register&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdokcezaoe9mvrk3mqj09.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdokcezaoe9mvrk3mqj09.png" alt="Book register" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get the JSON view&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fft2hu2l06iwh1n8gn9r0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fft2hu2l06iwh1n8gn9r0.png" alt="Book register" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The MEAN stack—comprising MongoDB, Express.js, AngularJS (or Angular), and Node.js—provides a powerful and cohesive set of technologies for building modern web applications.&lt;/p&gt;

&lt;p&gt;Together, these technologies allow developers to use JavaScript throughout the entire development process, from front-end to back-end, promoting a unified and streamlined development workflow.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>LEMP Stack (WEB STACK) Implementation in AWS</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Mon, 21 Apr 2025 00:16:12 +0000</pubDate>
      <link>https://dev.to/uwadon1/lemp-stack-web-stack-implementation-in-aws-jmo</link>
      <guid>https://dev.to/uwadon1/lemp-stack-web-stack-implementation-in-aws-jmo</guid>
      <description>&lt;h2&gt;
  
  
  WEB STACK IMPLEMENTATION (LEMP STACK) IN AWS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introduction:
&lt;/h3&gt;

&lt;p&gt;The LEMP Stack is a popular open-source web development platform that consists of four main components: Linux, (E)Nginx, MySQL, and PHP (or sometimes Perl or Python). This documentation outlines the setup, configuration, and usage of the LEMP stack.&lt;/p&gt;

&lt;p&gt;A LEMP Stack application is an application which as opposed to a LAMP Stack Application makes use of Nginx as the web server for hosting the web application. NGINX is an open source software for web serving, reverse proxying, caching, load balancing, media streaming, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Launched an Ubuntu EC2 Instance named “Lemp_Stack_Server” with AMI of 24.04 LTS (HVM) in the us-west-2 region using the AWS console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft79q39a544em7lu94zgh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft79q39a544em7lu94zgh.png" alt="Create Server Name" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Gave it the instance type of t2.micro which is within the free-tier. Created SSH key pair named &lt;strong&gt;lemp_stack&lt;/strong&gt; to access the instance on port 22.  The default VPC and Subnet were used for the networking configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsghwrecbc7ppd19814np.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsghwrecbc7ppd19814np.png" alt="Instance Type" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; The security group was configured with the following inbound rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow traffic on port 22 (SSH) with source from any IP address. This is opened by default.&lt;/li&gt;
&lt;li&gt;Allow traffic on port 443 (HTTPS) with source from anywhere on the internet.&lt;/li&gt;
&lt;li&gt;Allow traffic on port 80 (HTTP) with source from anywhere on the internet.
And will leave the storage at default; 8gb gp3 volume storage. Then we hit the launch instance button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqh92tj5bt9ehlvhunop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqh92tj5bt9ehlvhunop.png" alt="Security Rules" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; First, we need to move the keypair file from the download folder into the .ssh folder; &lt;br&gt;
 cp ~/Downloads/lemp_stack.pem ~/.ssh/&lt;/p&gt;

&lt;p&gt;The private ssh key that got downloaded has now been moved, permission was changed for the private key file and then used to connect to the instance by running the following commands;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 400 ~/.ssh/lemp_stack.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i ~/.ssh/lemp_stack.pem ubuntu@35.95.39.71
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;strong&gt;username=ubuntu&lt;/strong&gt; and &lt;strong&gt;public ip address=35.95.39.71&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptm3pvo6blld9s57544e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptm3pvo6blld9s57544e.png" alt="Connect to instance" width="672" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - Install Nginx web server
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Update and upgrade the server’s package index&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run a sudo apt update to download package information from all configured sources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fij9mns16y0nf8wli8i42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fij9mns16y0nf8wli8i42.png" alt="Update Packages" width="690" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run a sudo apt upgrade to upgrade the package&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`sudo apt upgrade -y
``

![Upgrade Packages](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pss8cqig7yruyt72fxvj.png)


__2.__ __Install nginx__

Run a sudo apt install nginx -y to install nginx 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sudo apt install nginx -y&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
![Install Nginx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9ir8e2e9azspo1uuf5y.png)


__3.__ __Spin up Nginx and verify that nginx is active and running__

Spin up the nginx server and ensure it automatically starts on system reboot by running the following commands

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sudo systemctl start nginx&lt;br&gt;
sudo systemctl enable nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;And 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sudo systemctl status nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
If it's green and running, then nginx is correctly installed

![Nginx Status](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/va11jjkb611955fe4bvn.png)

__4.__ __Access nginx locally on the Ubuntu shell__

Accessing the default nginx web server block to see if everything works correctly. curl the local IP address of our local machine which in most cases is 127.0.0.1 or the DNS name localhost on any web browser on our local machine:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;curl &lt;a href="http://127.0.0.1:80" rel="noopener noreferrer"&gt;http://127.0.0.1:80&lt;/a&gt;&lt;br&gt;
curl &lt;a href="http://localhost:80" rel="noopener noreferrer"&gt;http://localhost:80&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

The below result shows Nginx has been properly set up and we can deploy our web application.



![[Local URL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5xcqw2qptno8yxg81z5h.png)

__5.__ __Test with the public IP address if the Nginx server can respond to requests from the internet using the URL on a browser.__

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="http://35.95.39.71:80" rel="noopener noreferrer"&gt;http://35.95.39.71:80&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
![Nginx Default Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cx4ajxm3lvgl40478dkv.png)

This shows that the web server is correctly installed and it is accessible through the firewall.


__6.__ __Another way to retrieve the public IP address rather than check the aws console__
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TOKEN=$(curl -X PUT "&lt;a href="http://169.254.169.254/latest/api/token" rel="noopener noreferrer"&gt;http://169.254.169.254/latest/api/token&lt;/a&gt;" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")&lt;br&gt;
curl -H "X-aws-ec2-metadata-token: $TOKEN" -s &lt;a href="http://169.254.169.254/latest/meta-data/public-ipv4" rel="noopener noreferrer"&gt;http://169.254.169.254/latest/meta-data/public-ipv4&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
![Obtain-ip](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsebn8h939ci4utf8cfz.png)

Or enable IMDSv1 in your instance settings:
Go to EC2 Console → Instances → Select your instance.
Actions → Instance Settings → Modify Metadata Options.
Set Metadata version to V1 and V2.
Change the __IMDSv2__ from __Required__ to __Optional__.

The command was run,and the public IP address was displayed. Thing is AWS now defaults to IMDSv2 (Instance Metadata Service Version 2), which requires token.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 - Install MySQL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Install a relational database (RDB)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have succeeded in setting up our nginx webserver and ensured its accessible over the internet. Next is to install mySQL which is a relational database management server to help store data and manage content on our web application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install mysql-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4nf8gjf2tepm64ep9ej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4nf8gjf2tepm64ep9ej.png" alt="Install MySQL" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Log in to mysql console&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This connects to the MySQL server as the administrative database user &lt;strong&gt;root&lt;/strong&gt; inferred by the use of &lt;strong&gt;sudo&lt;/strong&gt; when running the command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyhkyet4tl2cgaj9klo7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyhkyet4tl2cgaj9klo7.png" alt="MySQL console" width="518" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Set a password for root user using mysql_native_password as default authentication method.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here, the user's password was defined as "Admin007$"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Admin007$';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65s859zfpm0hbvfco5us.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65s859zfpm0hbvfco5us.png" alt="Root Password" width="591" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exit the MySQL shell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Run an Interactive script to secure MySQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The security script comes pre-installed with mysql. This script removes some insecure settings and locks down access to the database system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql_secure_installation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5eyp3s6rsgkcq8o4emt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5eyp3s6rsgkcq8o4emt.png" alt="Change root password" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;After changing root user password, log in to MySQL console.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A command prompt for password was noticed after running the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql -p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figyfathjjah2v6tkiz1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figyfathjjah2v6tkiz1c.png" alt="MySQL login with password" width="553" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exit MySQL shell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 - Install PHP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Install php&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install php-fpm (PHP fastCGI process manager) and tell nginx to pass PHP requests to this software for processing. Also, install php-mysql, a php module that allows PHP to communicate with MySQL-based databases. Core PHP packages will automatically be installed as dependencies.&lt;/p&gt;

&lt;p&gt;We use php to dynamically display contents of our webpage to users who make requests to the webserver.&lt;br&gt;
php-fpm : which stands for PHP FastCGI Process Manager is a web tool used for speeding up the performance of a website by handling tremendous amounts of load simultaneously.&lt;/p&gt;

&lt;p&gt;The following were installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;php-fpm (PHP fastCGI process manager)&lt;/li&gt;
&lt;li&gt;php-mysql
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install php-fpm php-mysql -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo98scow0yelwe3d6p9ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo98scow0yelwe3d6p9ss.png" alt="Install PHP" width="446" height="159"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4 - Configure nginx to use PHP processor
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Create a root web directory for your_domain&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To serve our web content on our web server, we create a directory for our project inside the /var/www/ directory.&lt;br&gt;
sudo mkdir /var/www/projectlemp Then we change permissions of the projectlemp directory to the current user system&lt;br&gt;
sudo chown -R $USER:$USER /var/www/projectlemp&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir /var/www/projectlemp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Assign the directory ownership with $USER which will reference the current system user&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo chown -R $USER:$USER /var/www/projectlemp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5ikzr7zfbd125w8c7ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5ikzr7zfbd125w8c7ra.png" alt="Web root dir" width="501" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Create a new configuration file in Nginx’s “sites-available” directory&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/nginx/sites-available/projectlemp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste in the following bare-bones configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
  listen 80;
  server_name projectlemp www.projectlemp;
  root /var/www/projectlemp;

  index index.html index.htm index.php;

  location / {
    try_files $uri $uri/ =404;
  }

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
  }

  location ~ /\.ht {
    deny all;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b4km4ww1lcfs4d1lix6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b4km4ww1lcfs4d1lix6.png" alt="Nginx config in Nano" width="466" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Here’s what each directive and location block does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;listen&lt;/strong&gt; - Defines what port nginx listens on. In this case, it will listen on port 80, the default port for HTTP.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;root&lt;/strong&gt; - Defines the document root where the files served by this website are stored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;index&lt;/strong&gt; - Defines in which order Nginx will prioritize the index files for this website. It is a common practice to list index.html files with a higher precedence than index.php files to allow for quickly setting up a maintenance landing page for PHP applications. You can adjust these settings to better suit your application needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;server_name&lt;/strong&gt; - Defines which domain name and/or IP addresses the server block should respond for. Point this directive to your domain name or public IP address.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;location /&lt;/strong&gt; - The first location block includes the try_files directive, which checks for the existence of files or directories matching a URI request. If Nginx cannot find the appropriate result, it will return a 404 error.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;location ~ .php$&lt;/strong&gt; - This location handles the actual PHP processing by pointing Nginx to the fastcgi-php.conf configuration file and the php7.4-fpm.sock file, which declares what socket is associated with php-fpm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;location ~ /.ht&lt;/strong&gt; - The last location block deals with .htaccess files, which Nginx does not process. By adding the deny all directive, if any .htaccess files happen to find their way into the document root, they will not be served to visitors.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Activate the configuration by linking to the config file from Nginx’s sites-enabled directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ln -s /etc/nginx/sites-available/projectlemp /etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k7ihojma1yq6fvd5u99.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k7ihojma1yq6fvd5u99.png" alt="Link config" width="660" height="64"&gt;&lt;/a&gt;&lt;br&gt;
This will tell Nginx to use this configuration when next it is reloaded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Test the configuration for syntax error&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nginx -t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13tm1esm1f721hqxepza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13tm1esm1f721hqxepza.png" alt="Test syntax" width="452" height="89"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;Disable the default Nginx host that currently configured to listen on port 80&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Currently, our new server block has been created and configured but the default server block is the default block that comes with nginx install. To unlink it we run the command: sudo unlink /etc/sites-available/default.&lt;br&gt;
We then reload nginx for all configurations to take effect sudo reload nginx.&lt;br&gt;
Create an index.html file inside projectlemp directory and write in contents to be accessed over the internet. Paste public IP address on a browser to see contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo unlink /etc/nginx/sites-enabled/default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; &lt;strong&gt;Reload Nginx to apply the changes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshom2r7ybbwhr6b7af9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshom2r7ybbwhr6b7af9r.png" alt="Disable Default and Reload nginx" width="463" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8.&lt;/strong&gt; &lt;strong&gt;The new website is now active but the web root /var/www/projectlemp is still empty. Create an index.html file in this location so to test the virtual host work as expected.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo echo ‘Hello LEMP from hostname’ $(curl -s http://169.254.169.254/latest/meta-data/public-hostname) ‘with public IP’ $(curl -s http://169.254.169.254/latest/meta-data/public-ipv4) &amp;gt; /var/www/projectlemp/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bash -c "echo 'Hello LEMP from hostname $PUBLIC_HOSTNAME with public IP $PUBLIC_IP' &amp;gt; /var/www/projectlemp/index.html"

TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

PUBLIC_HOSTNAME=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/public-hostname)
PUBLIC_IP=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/public-ipv4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fja9hcivu2nz0hsht4w8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fja9hcivu2nz0hsht4w8z.png" alt="Site content" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Open the website on a browser using IP address
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://35.95.39.71:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs78c53qvo24tbsx886vu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs78c53qvo24tbsx886vu.png" alt="Site with ip-address" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Open it with public DNS name (port is optional)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;public-DNS-name&amp;gt;:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyg965crctunvu0h7d52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyg965crctunvu0h7d52.png" alt="Site with dns name" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file can be left in place as a temporary landing page for the application until an index.php file is set up to replace it. Once this is done, remove or rename the index.html file from the document root as it will take precedence over index.php file by default.&lt;/p&gt;

&lt;p&gt;The LEMP stack is now fully configured.&lt;br&gt;
At this point, the LEMP stack is completely installed and fully operational.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5 - Test PHP with Nginx
&lt;/h2&gt;

&lt;p&gt;Test the LEMP stack to validate that Nginx can handle the .php files off to the PHP processor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Create a test PHP file in the document root. Open a new file called info.php within the document root.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an info.php file inside the /var/www/projectlemp directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /var/www/projectlemp/info.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste in the command below;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
phpinfo();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Access the page on the browser and attach /info.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://18.209.18.61/info.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxxmsorvoaqvn24cj998.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxxmsorvoaqvn24cj998.png" alt="PHP page" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After checking the relevant information about the server through this page, It’s best to remove the file created as it contains sensitive information about the PHP environment and the ubuntu server. It can always be recreated if the information is needed later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rm /var/www/projectlemp/info.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6 - Retrieve Data from MySQL database with PHP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a new user with the mysql_native_password authentication method in order to be able to connect to MySQL database from PHP.
&lt;/h3&gt;

&lt;p&gt;Create a database named todo_database and a user named todo_user&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;First, connect to the MySQL console using the root account.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql -p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Create a new database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE DATABASE todo_database;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Create a new user and grant the user full privileges on the new database.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE USER 'todo_user'@'%' IDENTIFIED WITH mysql_native_password BY 'Admin123$';

GRANT ALL ON todo_database.* TO 'todo_user'@'%';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rv4b583v6cd26w3lzn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rv4b583v6cd26w3lzn5.png" alt="Create database" width="677" height="437"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Login to MySQL console with the user custom credentials and confirm that you have access to todo_database.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql -u todo_user -p

SHOW DATABASES;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bnr3p5sbgir6p3bty7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bnr3p5sbgir6p3bty7t.png" alt="Show database" width="580" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The -p flag will prompt for passwords used when creating the example_user&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Create a test table named todo_list&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;From MySQL console, run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE todo_database.todo_list (
  item_id INT AUTO_INCREMENT,
  content VARCHAR(255),
  PRIMARY KEY(item_id)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;Insert a few rows of content to the test table&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO todo_database.todo_list (content) VALUES ("My first important item");

INSERT INTO todo_database.todo_list (content) VALUES ("My second important item");

INSERT INTO todo_database.todo_list (content) VALUES ("My third important item");

INSERT INTO todo_database.todo_list (content) VALUES ("and this one more thing");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ibqyeaoebefz6zxzb1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ibqyeaoebefz6zxzb1n.png" alt="Insert rows" width="656" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; &lt;strong&gt;To confirm that the data was successfully saved to the table run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM todo_database.todo_list;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ztmk307cfyotibbpc85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ztmk307cfyotibbpc85.png" alt="Query table" width="358" height="170"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a PHP script that will connect to MySQL and query the content.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Create a new PHP file in the custom web root directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /var/www/projectlemp/todo_list.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PHP script connects to MySQL database and queries for the content of the todo_list table, displays the results in a list. If there’s a problem with the database connection, it will throw an exception.&lt;/p&gt;

&lt;p&gt;Copy the content below into the todo_list.php script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
$user = "todo_user";
$password = "Admin123$";
$database = "todo_database";
$table = "todo_list";

try {
  $db = new PDO("mysql:host=localhost;dbname=$database", $user, $password);
  echo "&amp;lt;h2&amp;gt;TODO&amp;lt;/h2&amp;gt;&amp;lt;ol&amp;gt;";
  foreach($db-&amp;gt;query("SELECT content FROM $table") as $row) {
    echo "&amp;lt;li&amp;gt;" . $row['content'] . "&amp;lt;/li&amp;gt;";
  }
  echo "&amp;lt;/ol&amp;gt;";
} catch (PDOException $e) {
    print "Error!: " . $e-&amp;gt;getMessage() . "&amp;lt;br/&amp;gt;";
    die();
}
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuckghubk78e8lwihyhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuckghubk78e8lwihyhy.png" alt="PHP Script" width="499" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Now access this page on the browser by using the domain name or public IP address followed by /todo_list.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://35.95.39.71/todo_list.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg349bx10leuyf44k0wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg349bx10leuyf44k0wg.png" alt="Site with IP" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access this page on the browser by using the domain name followed by /todo_list.php&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr19ew731cc88m7oin6l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr19ew731cc88m7oin6l.png" alt="Site with dns" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshoot
&lt;/h3&gt;

&lt;p&gt;One of the major errors I encountered when implementing this project was after I adjusted my PHP file and wanted to view my IP address with the path /info.php. I got a 502 error, but after much back-and-forth troubleshooting, I realized where the issue was from. I didn't take note of the PHP version that was installed, hence, the exact version was not referenced while I was populating this file ‘/etc/nginx/sites-available/projectlemp’ so I kept getting 502 error until I corrected this line ‘fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;’&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The LEMP stack provides a robust platform for hosting and serving web applications. By leveraging the power of Linux, Nginx, MySQL (or MariaDB), and PHP, developers can deploy scalable and reliable web solutions.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>LAMP Stack (WEB STACK) Implementation in AWS</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Wed, 16 Apr 2025 10:38:43 +0000</pubDate>
      <link>https://dev.to/uwadon1/lamp-stack-web-stack-implementation-in-aws-54h3</link>
      <guid>https://dev.to/uwadon1/lamp-stack-web-stack-implementation-in-aws-54h3</guid>
      <description>&lt;p&gt;WEB STACK IMPLEMENTATION (LAMP STACK) IN AWS&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The LAMP stack is a popular group of open-source software that consists of four main components: Linux, Apache, MySQL, and PHP (or sometimes Perl or Python). It is typically installed together in order to enable a server to host dynamic websites and web apps written in PHP. &lt;br&gt;
This term is an acronym which represents the Linux operating system with the Apache web server.&lt;br&gt;
The site data is stored in a MySQL database, and dynamic content is processed by PHP. This documentation outlines the setup, configuration, and usage of the LAMP stack.&lt;/strong&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;



&lt;p&gt;Linux is the foundational layer of the LAMP stack, providing the operating system on which all the other components run. As an open-source, Unix-like operating system, &lt;br&gt;
Linux offers a highly customizable and secure platform that powers most of the world's servers. &lt;br&gt;
Its compatibility with other open-source software and widespread community support make it the preferred choice for web hosting environments.&lt;br&gt;
Popular Linux distributions used in LAMP stacks include Ubuntu, CentOS, and Debian.&lt;/p&gt;
&lt;h3&gt;
  
  
  Apache
&lt;/h3&gt;



&lt;p&gt;Apache is the web server software that handles serving web pages to users. &lt;br&gt;
It processes HTTP requests from client browsers and delivers content such as HTML pages, images, and scripts. &lt;br&gt;
Apache also supports advanced features including virtual hosting, secure connections (SSL/TLS), and URL rewriting.&lt;br&gt;
Key Features of Apache:&lt;br&gt;
Modular Design: Apache allows administrators to enable or disable different modules, such as SSL for encryption or mod_rewrite for URL manipulation.&lt;br&gt;
Virtual Hosting: Apache can host multiple websites on a single server, each with its own domain name and directory.&lt;br&gt;
SSL/TLS Support: Apache can secure connections between the server and clients using SSL (Secure Sockets Layer) and TLS (Transport Layer Security).&lt;br&gt;
Cross-Platform: Although it runs best on Linux, Apache is also compatible with other operating systems like Windows and macOS.&lt;/p&gt;
&lt;h3&gt;
  
  
  MySQL (or MariaDB)
&lt;/h3&gt;



&lt;p&gt;MySQL is a relational database management system (RDBMS) used for storing and managing structured data in web applications. &lt;br&gt;
Its client-server architecture supports multiple clients performing operations such as data retrieval, manipulation, and deletion. &lt;br&gt;
MariaDB, a fork of MySQL, provides additional features and performance enhancements while maintaining compatibility with MySQL.&lt;/p&gt;
&lt;h3&gt;
  
  
  PHP (or Perl/Python)
&lt;/h3&gt;

&lt;p&gt;PHP is a server-side scripting language designed to create dynamic web content. &lt;br&gt;
Embedded within HTML code, PHP executes on the web server to generate content dynamically before sending it to the client. &lt;br&gt;
It interacts with databases, processes forms, and performs various tasks necessary for developing interactive web applications. &lt;br&gt;
Alternative scripting languages like Perl and Python can also be used in place of PHP, depending on the specific needs of the application.&lt;/p&gt;


&lt;h3&gt;
  
  
  Use Cases for LAMP Stack
&lt;/h3&gt;



&lt;p&gt;Content Management Systems (CMS): Platforms like WordPress, Drupal, and Joomla run on the LAMP stack.&lt;br&gt;
E-commerce Websites: Many online stores use the LAMP stack to manage dynamic content, handle payments, and process user data.&lt;br&gt;
Web Applications: From social networking sites to business applications, the LAMP stack provides the necessary infrastructure to support complex web-based platforms.&lt;br&gt;
Custom Web Development: Developers can use the LAMP stack for custom web applications that require robust back-end support with PHP and MySQL, such as blogs, forums, or project management tools.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 0: Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Launched an Ubuntu EC2 Instance named “Lamp_Stack_Server” with AMI of 24.04 LTS (HVM) in the us-west-2 region using the AWS console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fserver-name.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fserver-name.png" alt="Create Server Name" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Gave it the instance type of t2.micro which is within the free-tier. Created SSH key pair named &lt;strong&gt;lamp_stack&lt;/strong&gt; to access the instance on port 22.  The default VPC and Subnet were used for the networking configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Ft2-micro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Ft2-micro.png" alt="Instance Type" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; The security group was configured with the following inbound rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow traffic on port 22 (SSH) with source from any IP address. This is opened by default.&lt;/li&gt;
&lt;li&gt;Allow traffic on port 443 (HTTPS) with source from anywhere on the internet.&lt;/li&gt;
&lt;li&gt;Allow traffic on port 80 (HTTP) with source from anywhere on the internet.
And will leave the storage at default; 8gb gp3 volume storage. Then we hit the launch instance button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsecurity-group.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsecurity-group.png" alt="Security Rules" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; First, we need to move the keypair file from the download folder into the .ssh folder; &lt;br&gt;
 cp ~/Downloads/lamp_stack.pem ~/.ssh/&lt;/p&gt;

&lt;p&gt;The private ssh key that got downloaded has now been moved, permission was changed for the private key file and then used to connect to the instance by running the following commands;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 400 ~/.ssh/lamp_stack.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i ~/.ssh/lamp_stack.pem ubuntu@35.93.146.45
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;strong&gt;username=ubuntu&lt;/strong&gt; and &lt;strong&gt;public ip address=35.93.146.45&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fssh-instance.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fssh-instance.png" alt="Connect to instance" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - Install Apache and Update the Firewall
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Update and upgrade list of packages in package manager&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update

![Update Packages](./images/apt-update.png)

sudo apt upgrade -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapt-upgrade.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapt-upgrade.png" alt="Upgrade Packages" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Run apache2 package installation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install apache2 -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapache-install.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapache-install.png" alt="Instal Apache" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Enable and verify that apache is running on as a service on the OS.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl enable apache2
sudo systemctl status apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sudo systemctl enable apache2: Configures Apache to start on boot (so it survives a restart).&lt;/p&gt;

&lt;p&gt;If it green and running, then apache2 is correctly installed&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fenable-systemctl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fenable-systemctl.png" alt="Systemctl Status" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;The server is running and can be accessed locally in the ubuntu shell by running the command below:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:80
OR
curl http://127.0.0.1:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fcurl-localhost.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fcurl-localhost.png" alt="Local URL" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Test with the public IP address if the Apache HTTP server can respond to request from the internet using the url on a browser.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://35.93.146.45:80

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapache-browser.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapache-browser.png" alt="Apache Default Page" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
This shows that the web server is correctly installed and it is accessible through the firewall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;Another way to retrieve the public ip address rather than check the aws console&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/public-ipv4

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fabstract-ip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fabstract-ip.png" alt="imds option" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or enable IMDSv1 in your instance settings:&lt;br&gt;
Go to EC2 Console → Instances → Select your instance.&lt;br&gt;
Actions → Instance Settings → Modify Metadata Options.&lt;br&gt;
Set Metadata version to V1 and V2.&lt;br&gt;
Change the &lt;strong&gt;IMDSv2&lt;/strong&gt; from &lt;strong&gt;Required&lt;/strong&gt; to &lt;strong&gt;Optional&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The command was run,and the public IP address was displayed. Thing is AWS now defaults to IMDSv2 (Instance Metadata Service Version 2), hich requires token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/public-ipv4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 - Install MySQL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Install a relational database (RDB)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MySQL was installed in this project. It is a popular relational database management system used within PHP environments. We use MySQl as a relational database to store and manage data on our website.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install mysql-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fmysql-install.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fmysql-install.png" alt="Install MySQL" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
When prompted, install was confirmed by typing y and then Enter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Enable and verify that mysql is running with the commands below&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl enable --now mysql
sudo systemctl status mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: sudo systemctl enable --now mysql: --now starts MySQL immediately, and enable ensures it runs at boot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsystemctl-mysql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsystemctl-mysql.png" alt="MySQL Status" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Log in to mysql console&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This connects to the MySQL server as the administrative database user &lt;strong&gt;root&lt;/strong&gt; infered by the use of &lt;strong&gt;sudo&lt;/strong&gt; when running the command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Set a password for root user using mysql_native_password as default authentication method.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here, the user's password was defined as "Admin007$"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Admin007$';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fmysql-login.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fmysql-login.png" alt="User Password" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
Exit the MySQL shell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Run an Interactive script to secure MySQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The security script comes pre-installed with mysql. This script removes some insecure settings and lock down access to the database system.&lt;/p&gt;

&lt;p&gt;NB: The command below launches an interactive script that:&lt;br&gt;
Sets password validation rules (if chosen).&lt;/p&gt;

&lt;p&gt;Removes test users and databases.&lt;/p&gt;

&lt;p&gt;Disables root login remotely (optional).&lt;/p&gt;

&lt;p&gt;Reloads privilege tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql_secure_installation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fiteractive-change.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fiteractive-change.png" alt="Remove Insecure Access" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use the sudo mysql_secure_installation command to remove insecure default settings and enable protection for the database.&lt;/p&gt;

&lt;p&gt;Regardless of whether the VALIDATION PASSWORD PLUGIN is set up, the server will ask to select and confirm a password for MySQL root user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;After changing root user password, log in to MySQL console.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A command prompt for password was noticed after running the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql -p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fpassword-change.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fpassword-change.png" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
Exit MySQL shell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 - Install PHP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Install php&lt;/strong&gt;&lt;br&gt;
Apache is installed to serve the content and MySQL is installed to store and manage data.&lt;br&gt;
PHP is the component of the set up that processes code to display dynamic content to the end user.&lt;/p&gt;

&lt;p&gt;The following were installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;php: The scripting language.&lt;/li&gt;
&lt;li&gt;php-mysql: PHP module that allows PHP to communicate with MySQL-based databases.&lt;/li&gt;
&lt;li&gt;libapache2-mod-php: Module to run PHP with Apache and enable Apache to handle PHP files.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install php libapache2-mod-php php-mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Finstall-php.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Finstall-php.png" alt="Install PHP" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Confirm the PHP version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimages%2Fconfirm-php.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimages%2Fconfirm-php.png" alt="Confirm php version" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, the LAMP stack is completely installed and fully operational.&lt;/p&gt;

&lt;p&gt;To test the setup with a PHP script, it's best to set up a proper Apache Virtual Host to hold the website files and folders. Virtual host allows to have multiple websites located on a single machine and it won't be noticed by the website users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Create a virtual host for the website using Apache
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;The default directory serving the apache default page is /var/www/html. Create your document directory next to the default one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apache webserver serves a website by the way of server blocks inside its /var/www/ directory, and it can support multiple of this server blocks to host other websites.&lt;/p&gt;

&lt;p&gt;Here we create a new directory called ‘projectlamp’ inside the /var/www/ directory using "mkdir" command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir /var/www/projectlamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Assign the directory ownership with $USER environment variable which references the current system user, i.e we change the permissions of the projectlamp directory to the current user system..&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo chown -R $USER:$USER /var/www/projectlamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: This command changes ownership to your user (so you can easily modify files).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fmkdir-chown.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fmkdir-chown.png" alt="Projectlamp Root Directory" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; __ The projectlamp directory represents the directory which will contain files related to our website as it represents a new server block on the apache webserver. In order to spin up this server block we need to configure it by creating a .conf file.&lt;/p&gt;

&lt;p&gt;Create and open a new configuration file in apache’s “sites-available” directory using vim.__&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vim /etc/apache2/sites-available/projectlamp.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following represents the configuration needed to spin up the server block. Copy and paste in the bare-bones configuration below into the editor.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
  ServerName projectlamp
  ServerAlias www.projectlamp
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/projectlamp
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fpaste-select.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fpaste-select.png" alt="Virtual Host" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Show the new file in sites-available&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ls /etc/apache2/sites-available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Output:
000-default.conf default-ssl.conf projectlamp.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsudo-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsudo-list.png" alt="Projectlamp config file" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the VirtualHost configuration, Apache will serve projectlamp using /var/www/projectlamp as its web root directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Enable the new virtual host&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo a2ensite projectlamp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we run sudo a2ensite projectlamp to activate the server block.&lt;br&gt;
NB: Activates your config by creating a symbolic link in sites-enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fa2ensite.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fa2ensite.png" alt="Enable virtual host" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Disable apache’s default website.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is because Apache’s default configuration will overwrite the virtual host if not disabled. This is required if a custom domain is not being used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo a2dissite 000-default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We run ‘sudo a2dissite 000-default’ to deactivate the default webserver block that comes with apache on default.&lt;br&gt;
NB: Prevents Apache from using the default config, this is important to avoid conflicts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fa2dissite-default.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fa2dissite-default.png" alt="Disable Apache default" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;Ensure the configuration does not contain syntax error&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The command below was used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apache2ctl configtest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsyntax-confirm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fsyntax-confirm.png" alt="Check syntax error" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; &lt;strong&gt;Reload apache for changes to take effect.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8.&lt;/strong&gt; &lt;strong&gt;The new website is now active but the web root /var/www/projectlamp is still empty. Create an index.html file in this location, so as to test the virtual host work as expected.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo echo 'Hello LAMP from hostname' $(curl -s http://169.254.169.254/latest/meta-data/public-hostname) 'with public IP' $(curl -s http://169.254.169.254/latest/meta-data/public-ipv4) &amp;gt; /var/www/projectlamp/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bash -c "echo 'Hello LAMP from hostname' \$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/public-hostname) 'with public IP' \$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/public-ipv4) &amp;gt; /var/www/projectlamp/index.html"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapache-before.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapache-before.png" alt="Root dir content" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9.&lt;/strong&gt; &lt;strong&gt;Open the website on a browser using the public IP address.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://35.93.146.45:80

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapachelocal-after.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapachelocal-after.png" alt="URL public IP" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10.&lt;/strong&gt; Open the website with public dns name (port is optional)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;public-DNS-name&amp;gt;:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapachedns-after.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fapachedns-after.png" alt="URL public DNS" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file can be left in place as a temporary landing page for the application until an index.php file is set up to replace it. Once this is done, the index.html file should be renamed or removed from the document root as it will take precedence over index.php file by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Enable PHP on the website
&lt;/h2&gt;

&lt;p&gt;With the default DirectoryIndex setting on Apache, index.html file will always take precedence over index.php file. This is useful for setting up maintenance page in PHP applications, by creating a temporary index.html file containing an informative message for visitors. The index.html then becomes the landing page for the application. Once maintenance is over, the index.html is renamed or removed from the document root bringing back the regular application page.&lt;br&gt;
If the behaviour needs to be changed, /etc/apache2/mods-enabled/dir.conf file should be edited and the order in which the index.php file is listed within the DirectoryIndex directive should be changed.&lt;/p&gt;

&lt;p&gt;NB: By default, the webserver has a preference for serving an index.html file based on the order of precedence by default in the DirectoryIndex settings of Apache.&lt;br&gt;
To serve an index.php containing the server-side code, you’ll need to edit the /etc/apache2/mods-enabled/dir.conf file and change the order in which the index.php file is listed within the DirectoryIndex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Open the dir.conf file with vim to change the behaviour&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vim /etc/apache2/mods-enabled/dir.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_dir.c&amp;gt;
  # Change this:
  # DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm
  # To this:
  DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: We want to prioritize index.php over index.html&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fchangevim-php.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fchangevim-php.png" alt="Change file list order" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Reload Apache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apache is reloaded so the changes takes effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Create a php test script to confirm that Apache is able to handle and process requests for PHP files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A new index.php file was created inside the custom web root folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim /var/www/projectlamp/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add the text below in the index.php file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
phpinfo();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: phpinfo() shows your PHP environment info in browsers, this is useful for confirming PHP is working correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fvi-php.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fvi-php.png" alt="php text" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Now refresh the page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fpage-reload.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fimg%2Fpage-reload.png" alt="PHP page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This page provides information about the server from the perspective of PHP. It is useful for debugging and to ensure the settings are being applied correctly.&lt;/p&gt;

&lt;p&gt;After checking the relevant information about the server through this page, It’s best to remove the file created as it contains sensitive information about the PHP environment and the ubuntu server. It can always be recreated if the information is needed later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rm /var/www/projectlamp/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The LAMP stack provides a robust and flexible platform for developing and deploying web applications. By following the guidelines outlined in this documentation, It was possible to set up, configure, and maintain a LAMP environment effectively, enabling the creation of powerful and scalable web solutions.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>LAMP Stack (WEB STACK) Implementation in AWS</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Wed, 16 Apr 2025 09:57:50 +0000</pubDate>
      <link>https://dev.to/uwadon1/lamp-stack-web-stack-implementation-in-aws-2a66</link>
      <guid>https://dev.to/uwadon1/lamp-stack-web-stack-implementation-in-aws-2a66</guid>
      <description>&lt;p&gt;WEB STACK IMPLEMENTATION (LAMP STACK) IN AWS&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The LAMP stack is a popular group of open-source software that consists of four main components: Linux, Apache, MySQL, and PHP (or sometimes Perl or Python). It is typically installed together in order to enable a server to host dynamic websites and web apps written in PHP. &lt;br&gt;
This term is an acronym which represents the Linux operating system with the Apache web server.&lt;br&gt;
The site data is stored in a MySQL database, and dynamic content is processed by PHP. This documentation outlines the setup, configuration, and usage of the LAMP stack.&lt;/strong&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;

&lt;p&gt;Linux is the foundational layer of the LAMP stack, providing the operating system on which all the other components run. As an open-source, Unix-like operating system, &lt;br&gt;
Linux offers a highly customizable and secure platform that powers most of the world's servers. &lt;br&gt;
Its compatibility with other open-source software and widespread community support make it the preferred choice for web hosting environments.&lt;br&gt;
Popular Linux distributions used in LAMP stacks include Ubuntu, CentOS, and Debian.&lt;/p&gt;
&lt;h3&gt;
  
  
  Apache
&lt;/h3&gt;

&lt;p&gt;Apache is the web server software that handles serving web pages to users. &lt;br&gt;
It processes HTTP requests from client browsers and delivers content such as HTML pages, images, and scripts. &lt;br&gt;
Apache also supports advanced features including virtual hosting, secure connections (SSL/TLS), and URL rewriting.&lt;br&gt;
Key Features of Apache:&lt;br&gt;
Modular Design: Apache allows administrators to enable or disable different modules, such as SSL for encryption or mod_rewrite for URL manipulation.&lt;br&gt;
Virtual Hosting: Apache can host multiple websites on a single server, each with its own domain name and directory.&lt;br&gt;
SSL/TLS Support: Apache can secure connections between the server and clients using SSL (Secure Sockets Layer) and TLS (Transport Layer Security).&lt;br&gt;
Cross-Platform: Although it runs best on Linux, Apache is also compatible with other operating systems like Windows and macOS.&lt;/p&gt;
&lt;h3&gt;
  
  
  MySQL (or MariaDB)
&lt;/h3&gt;

&lt;p&gt;MySQL is a relational database management system (RDBMS) used for storing and managing structured data in web applications. &lt;br&gt;
Its client-server architecture supports multiple clients performing operations such as data retrieval, manipulation, and deletion. &lt;br&gt;
MariaDB, a fork of MySQL, provides additional features and performance enhancements while maintaining compatibility with MySQL.&lt;/p&gt;
&lt;h3&gt;
  
  
  PHP (or Perl/Python)
&lt;/h3&gt;

&lt;p&gt;PHP is a server-side scripting language designed to create dynamic web content. &lt;br&gt;
Embedded within HTML code, PHP executes on the web server to generate content dynamically before sending it to the client. &lt;br&gt;
It interacts with databases, processes forms, and performs various tasks necessary for developing interactive web applications. &lt;br&gt;
Alternative scripting languages like Perl and Python can also be used in place of PHP, depending on the specific needs of the application.&lt;/p&gt;


&lt;h3&gt;
  
  
  Use Cases for LAMP Stack
&lt;/h3&gt;

&lt;p&gt;Content Management Systems (CMS): Platforms like WordPress, Drupal, and Joomla run on the LAMP stack.&lt;br&gt;
E-commerce Websites: Many online stores use the LAMP stack to manage dynamic content, handle payments, and process user data.&lt;br&gt;
Web Applications: From social networking sites to business applications, the LAMP stack provides the necessary infrastructure to support complex web-based platforms.&lt;br&gt;
Custom Web Development: Developers can use the LAMP stack for custom web applications that require robust back-end support with PHP and MySQL, such as blogs, forums, or project management tools.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 0: Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Launched an Ubuntu EC2 Instance named “Lamp_Stack_Server” with AMI of 24.04 LTS (HVM) in the us-west-2 region using the AWS console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3miggmwvkyob29iuhj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3miggmwvkyob29iuhj2.png" alt="Launch Instance" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Gave it the instance type of t2.micro which is within the free-tier. Created SSH key pair named &lt;strong&gt;lamp_stack&lt;/strong&gt; to access the instance on port 22.  The default VPC and Subnet were used for the networking configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11asucfaix12twep0myk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11asucfaix12twep0myk.png" alt="Set Instance Type" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; The security group was configured with the following inbound rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow traffic on port 22 (SSH) with source from any IP address. This is opened by default.&lt;/li&gt;
&lt;li&gt;Allow traffic on port 443 (HTTPS) with source from anywhere on the internet.&lt;/li&gt;
&lt;li&gt;Allow traffic on port 80 (HTTP) with source from anywhere on the internet.
And will leave the storage at default; 8gb gp3 volume storage. Then we hit the launch instance button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99w0utee26ori6lc143h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99w0utee26ori6lc143h.png" alt="Security Rules" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; First, we need to move the keypair file from the download folder into the .ssh folder; &lt;br&gt;
 cp ~/Downloads/lamp_stack.pem ~/.ssh/&lt;/p&gt;

&lt;p&gt;The private ssh key that got downloaded has now been moved, permission was changed for the private key file and then used to connect to the instance by running the following commands;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 400 ~/.ssh/lamp_stack.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i ~/.ssh/lamp_stack.pem ubuntu@35.93.146.45
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;strong&gt;username=ubuntu&lt;/strong&gt; and &lt;strong&gt;public ip address=35.93.146.45&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x3n2e2vl1013pnj58sy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x3n2e2vl1013pnj58sy.png" alt="Connect to instance" width="620" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - Install Apache and Update the Firewall
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Update and upgrade list of packages in package manager&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update


![Update Packages](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0zxegjkabpl6ti9ixmn6.png)

sudo apt upgrade -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcpn976i15q1j6p3tqry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcpn976i15q1j6p3tqry.png" alt="Upgrade Packages" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Run apache2 package installation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install apache2 -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff23m6cze8tery3wbsvew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff23m6cze8tery3wbsvew.png" alt="Install Apache" width="494" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Enable and verify that apache is running on as a service on the OS.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl enable apache2
sudo systemctl status apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sudo systemctl enable apache2: Configures Apache to start on boot (so it survives a restart).&lt;/p&gt;

&lt;p&gt;If it green and running, then apache2 is correctly installed&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4bgxjcr0tiocfbogk6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4bgxjcr0tiocfbogk6x.png" alt="Apache Status" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;The server is running and can be accessed locally in the ubuntu shell by running the command below:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:80
OR
curl http://127.0.0.1:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0y9dbm16utkjbnmngfk8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0y9dbm16utkjbnmngfk8.png" alt="Curl Local Host" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Test with the public IP address if the Apache HTTP server can respond to requests from the internet using the url on a browser.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://35.93.146.45:80

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqhpwxq1r5q7jju63e6y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqhpwxq1r5q7jju63e6y.png" alt="Apache Default Page" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shows that the web server is correctly installed and it is accessible through the firewall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;Another way to retrieve the public IP address other than check the aws console&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/public-ipv4

![Obtain IP via the CLI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zrhwd5jhuq74uf7qq21t.png)![imds option](./images/imds-option.png)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or enable IMDSv1 in your instance settings:&lt;br&gt;
Go to EC2 Console → Instances → Select your instance.&lt;br&gt;
Actions → Instance Settings → Modify Metadata Options.&lt;br&gt;
Set Metadata version to V1 and V2.&lt;br&gt;
Change the &lt;strong&gt;IMDSv2&lt;/strong&gt; from &lt;strong&gt;Required&lt;/strong&gt; to &lt;strong&gt;Optional&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The command was run,and the public IP address was displayed. Thing is AWS now defaults to IMDSv2 (Instance Metadata Service Version 2), which requires token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/public-ipv4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 - Install MySQL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Install a relational database (RDB)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MySQL was installed in this project. It is a popular relational database management system used within PHP environments. We use MySQl as a relational database to store and manage data on our website.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install mysql-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprwk2xc5kzbk5ys4nfmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprwk2xc5kzbk5ys4nfmx.png" alt="Install MySQL" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When prompted, install was confirmed by typing y and then Enter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Enable and verify that mysql is running with the commands below&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl enable --now mysql
sudo systemctl status mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: sudo systemctl enable --now mysql: --now starts MySQL immediately, and enable ensures it runs at boot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvao1miuvp1yqy3w08ux3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvao1miuvp1yqy3w08ux3.png" alt="MySQL Status" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Log in to mysql console&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This connects to the MySQL server as the administrative database user &lt;strong&gt;root&lt;/strong&gt; inferred by the use of &lt;strong&gt;sudo&lt;/strong&gt; when running the command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Set a password for root user using mysql_native_password as default authentication method.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here, the user's password was defined as "Admin007$"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Admin007$';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75pi97c7xwj1uq37s1eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75pi97c7xwj1uq37s1eg.png" alt="User Password/MyQL login" width="783" height="333"&gt;&lt;/a&gt;&lt;br&gt;
Exit the MySQL shell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Run an Interactive script to secure MySQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The security script comes pre-installed with mysql. This script removes some insecure settings and lock down access to the database system.&lt;/p&gt;

&lt;p&gt;NB: The command below launches an interactive script that:&lt;br&gt;
Sets password validation rules (if chosen).&lt;/p&gt;

&lt;p&gt;Removes test users and databases.&lt;/p&gt;

&lt;p&gt;Disables root login remotely (optional).&lt;/p&gt;

&lt;p&gt;Reloads privilege tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql_secure_installation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmidq5gw659vply4y9dtr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmidq5gw659vply4y9dtr.png" alt="Iteractive Change" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use the sudo mysql_secure_installation command to remove insecure default settings and enable protection for the database.&lt;/p&gt;

&lt;p&gt;Regardless of whether the VALIDATION PASSWORD PLUGIN is set up, the server will ask to select and confirm a password for MySQL root user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;After changing root user password, log in to MySQL console.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A command prompt for password was noticed after running the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysql -p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm21owxqqv4zzgyksfd02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm21owxqqv4zzgyksfd02.png" alt="Password Change" width="528" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exit MySQL shell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 - Install PHP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Install php&lt;/strong&gt;&lt;br&gt;
Apache is installed to serve the content and MySQL is installed to store and manage data.&lt;br&gt;
PHP is the component of the set-up that processes code to display dynamic content to the end user.&lt;/p&gt;

&lt;p&gt;The following were installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;php: The scripting language.&lt;/li&gt;
&lt;li&gt;php-mysql: PHP module that allows PHP to communicate with MySQL-based databases.&lt;/li&gt;
&lt;li&gt;libapache2-mod-php: Module to run PHP with Apache and enable Apache to handle PHP files.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install php libapache2-mod-php php-mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q41dsnypx5lfkggeatw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q41dsnypx5lfkggeatw.png" alt="Install PHP" width="581" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Confirm the PHP version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ln8j0ccuctuk6m6imy4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ln8j0ccuctuk6m6imy4.png" alt="Confirm php version" width="526" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, the LAMP stack is completely installed and fully operational.&lt;/p&gt;

&lt;p&gt;To test the setup with a PHP script, it's best to set up a proper Apache Virtual Host to hold the website files and folders. Virtual host allows to have multiple websites located on a single machine and it won't be noticed by the website users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Create a virtual host for the website using Apache
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;The default directory serving the apache default page is /var/www/html. Create your document directory next to the default one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apache webserver serves a website by way of server blocks inside its /var/www/ directory, and it can support multiple of this server blocks to host other websites.&lt;/p&gt;

&lt;p&gt;Here we create a new directory called ‘projectlamp’ inside the /var/www/ directory using "mkdir" command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir /var/www/projectlamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Assign the directory ownership with $USER environment variable which references the current system user, i.e we change the permissions of the projectlamp directory to the current user system..&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo chown -R $USER:$USER /var/www/projectlamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: This command changes ownership to your user (so you can easily modify files).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjo4vlgh8jmz6cmvc9u6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjo4vlgh8jmz6cmvc9u6.png" alt="MKDIR CHOWN" width="564" height="38"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; __ The projectlamp directory represents the directory which will contain files related to our website as it represents a new server block on the apache webserver. In order to spin up this server block we need to configure it by creating a .conf file.&lt;/p&gt;

&lt;p&gt;Create and open a new configuration file in apache’s “sites-available” directory using vim.__&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vim /etc/apache2/sites-available/projectlamp.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following represents the configuration needed to spin up the server block. Copy and paste in the bare-bones configuration below into the editor.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
  ServerName projectlamp
  ServerAlias www.projectlamp
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/projectlamp
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kst8lz2g11rsrbw074s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kst8lz2g11rsrbw074s.png" alt="Virtual Host in VI" width="589" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Show the new file in sites-available&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ls /etc/apache2/sites-available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Output:
000-default.conf default-ssl.conf projectlamp.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk6ka9148mfdt37u1rs4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk6ka9148mfdt37u1rs4.png" alt="Projectlamp config file" width="604" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the VirtualHost configuration, Apache will serve projectlamp using /var/www/projectlamp as its web root directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Enable the new virtual host&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo a2ensite projectlamp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we run sudo a2ensite projectlamp to activate the server block.&lt;br&gt;
NB: Activates your config by creating a symbolic link in sites-enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1yyewjiun512yhp2oz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1yyewjiun512yhp2oz0.png" alt="Enable virtual host" width="426" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;Disable apache’s default website.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is because Apache’s default configuration will overwrite the virtual host if not disabled. This is required if a custom domain is not being used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo a2dissite 000-default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We run ‘sudo a2dissite 000-default’ to deactivate the default webserver block that comes with apache on default.&lt;br&gt;
NB: Prevents Apache from using the default config, this is important to avoid conflicts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzzmbb5oezr9cosytc1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzzmbb5oezr9cosytc1f.png" alt="Disable Apache default" width="444" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;Ensure the configuration does not contain syntax error&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The command below was used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apache2ctl configtest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93somnz9rx03s7beo3qq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93somnz9rx03s7beo3qq.png" alt="Check syntax error" width="450" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; &lt;strong&gt;Reload apache for changes to take effect.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The new website is now active but the web root /var/www/projectlamp is still empty. Create an index.html file in this location, so as to test the virtual host work as expected.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo echo 'Hello LAMP from hostname' $(curl -s http://169.254.169.254/latest/meta-data/public-hostname) 'with public IP' $(curl -s http://169.254.169.254/latest/meta-data/public-ipv4) &amp;gt; /var/www/projectlamp/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bash -c "echo 'Hello LAMP from hostname' \$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/public-hostname) 'with public IP' \$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/public-ipv4) &amp;gt; /var/www/projectlamp/index.html"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0pf24xx0qt8hobaq2mnd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0pf24xx0qt8hobaq2mnd.png" alt="Root dir content" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the website on a browser using the public IP address.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://35.93.146.45:80" rel="noopener noreferrer"&gt;http://35.93.146.45:80&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frigt8rmns7ebr3safd12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frigt8rmns7ebr3safd12.png" alt="URL public IP" width="800" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10.&lt;/strong&gt; Open the website with public dns name (port is optional)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;public-DNS-name&amp;gt;:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuaf8nonhdrdb3vldzok4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuaf8nonhdrdb3vldzok4.png" alt="URL public DNS" width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file can be left in place as a temporary landing page for the application until an index.php file is set up to replace it. Once this is done, the index.html file should be renamed or removed from the document root as it will take precedence over index.php file by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Enable PHP on the website
&lt;/h2&gt;

&lt;p&gt;With the default DirectoryIndex setting on Apache, index.html file will always take precedence over index.php file. This is useful for setting up maintenance page in PHP applications, by creating a temporary index.html file containing an informative message for visitors. The index.html then becomes the landing page for the application. Once maintenance is over, the index.html is renamed or removed from the document root bringing back the regular application page.&lt;br&gt;
If the behaviour needs to be changed, /etc/apache2/mods-enabled/dir.conf file should be edited and the order in which the index.php file is listed within the DirectoryIndex directive should be changed.&lt;/p&gt;

&lt;p&gt;NB: By default, the webserver has a preference for serving an index.html file based on the order of precedence by default in the DirectoryIndex settings of Apache.&lt;br&gt;
To serve an index.php containing the server-side code, you’ll need to edit the /etc/apache2/mods-enabled/dir.conf file and change the order in which the index.php file is listed within the DirectoryIndex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Open the dir.conf file with vim to change the behaviour&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vim /etc/apache2/mods-enabled/dir.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_dir.c&amp;gt;
  # Change this:
  # DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm
  # To this:
  DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: We want to prioritize index.php over index.html&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu44v5qyw8so7cso5kxz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu44v5qyw8so7cso5kxz9.png" alt="Change file list order" width="626" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Reload Apache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apache is reloaded so the changes takes effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Create a php test script to confirm that Apache is able to handle and process requests for PHP files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A new index.php file was created inside the custom web root folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim /var/www/projectlamp/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add the text below in the index.php file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;?php&lt;br&gt;
phpinfo();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;NB: phpinfo() shows your PHP environment info in browsers, this is useful for confirming PHP is working correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqown8qbjvm8v1pcvae3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqown8qbjvm8v1pcvae3m.png" alt="Php Text" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Now refresh the page&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2s21b900hjg0bnqqbg1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2s21b900hjg0bnqqbg1.png" alt="Page Reload" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This page provides information about the server from the perspective of PHP. It is useful for debugging and to ensure the settings are being applied correctly.&lt;/p&gt;

&lt;p&gt;After checking the relevant information about the server through this page, It’s best to remove the file created as it contains sensitive information about the PHP environment and the ubuntu server. It can always be recreated if the information is needed later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo rm /var/www/projectlamp/index.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The LAMP stack provides a robust and flexible platform for developing and deploying web applications. By following the guidelines outlined in this documentation, It was possible to set up, configure, and maintain a LAMP environment effectively, enabling the creation of powerful and scalable web solutions.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>aws</category>
      <category>devops</category>
      <category>webserver</category>
    </item>
    <item>
      <title>Build and Deploy a C.R.U.D REST API on Lambda using DynamoDB</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Tue, 17 Dec 2024 15:37:23 +0000</pubDate>
      <link>https://dev.to/uwadon1/build-and-deploy-a-crud-rest-api-on-lambda-using-dynamodb-4fo1</link>
      <guid>https://dev.to/uwadon1/build-and-deploy-a-crud-rest-api-on-lambda-using-dynamodb-4fo1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz164b65yci9pbpc9kwhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz164b65yci9pbpc9kwhp.png" alt="Architectural Diagram" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, I will walk you through the process of building a serverless API that enables the creates, reads, updates, and deletes of items stored in a DynamoDB table. By following the steps outlined below, you will be able to develop a scalable and efficient API using AWS Lambda, API Gateway, and DynamoDB.&lt;br&gt;
You can do it within the AWS Free Tier.&lt;/p&gt;

&lt;p&gt;Here are the high-level steps we’ll follow:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Step 1: Create a DynamoDB table&lt;br&gt;
Step 2: Create a Lambda function&lt;br&gt;
Step 3: Create an API gateway&lt;br&gt;
Step 4: Test your API&lt;br&gt;
Step 5: Monitor your Logs and Insights&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is a link to my github repo: &lt;a href="https://github.com/Uwadon1/AWS_RestLambdaAPI" rel="noopener noreferrer"&gt;https://github.com/Uwadon1/AWS_RestLambdaAPI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Step-by-Step Tutorial: Build a REST API (CRUD)&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Step ONE: Create a DynamoDB table&lt;/p&gt;

&lt;p&gt;Set Up the Environment&lt;/p&gt;

&lt;p&gt;Sign in to the AWS Management Console, we will be brought to the aws homepage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2yzc3hv5vk47ys71ydt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2yzc3hv5vk47ys71ydt.png" alt="Image description" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Create a DynamoDB Table&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;From the AWS dashboard, search for DynamoDb, then click on the DynamoDB service to navigate into the dynamo db dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvcrmjfmqip6azy2jb9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvcrmjfmqip6azy2jb9j.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the “create table icon&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt1na5gbr2b985n5d3yq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt1na5gbr2b985n5d3yq.png" alt="Image description" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in the necessary details and give your table a name (e.g &lt;code&gt;employee_info&lt;/code&gt; or any name of your choice). You can specify the partition key as &lt;code&gt;employeeid&lt;/code&gt; (string). Let the table setting remain as default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjrjdbxcmq7mr165u6qo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjrjdbxcmq7mr165u6qo.png" alt="Image description" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leave the remaining options as default and click “create table.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fodx7byezazme5zmygdoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fodx7byezazme5zmygdoy.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By following these steps, you will successfully create a DynamoDB table named “employee_info” with the partition key set to “employeeid”.&lt;/p&gt;

&lt;p&gt;Step TWO: Create a Lambda function&lt;br&gt;
Create Lambda Functions&lt;/p&gt;

&lt;p&gt;For this project, we will be using AWS Lambda for our backend logic:&lt;br&gt;
From the AWS Management Console, search for AWS Lambda service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvocvxae3pi47ohbxbsr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvocvxae3pi47ohbxbsr.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on “create a function”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh4aev0gi5v7o54zpxsl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh4aev0gi5v7o54zpxsl.png" alt="Image description" width="800" height="388"&gt;&lt;/a&gt;&lt;br&gt;
'&lt;/p&gt;

&lt;p&gt;In the “create a function” dashboard, select “author from scratch.” In the basic information section, give your lambda a function name e.g &lt;code&gt;api_processing&lt;/code&gt;, we will select Python 3.13 as our runtime&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmu2ubvyyuntzvm06u5df.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmu2ubvyyuntzvm06u5df.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Permission, in the execution role section, we will opt for the third/last option: “create a new role from AWS policy templates.” &lt;br&gt;
This new role should give us the opportunity to attach policy that grants full acces to DynamoDb and Cloudwatch or a custom policy with limited access to dynamo db. Afterwards, we will click on ‘create function’&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1kmnnl49gfklc8o3apl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1kmnnl49gfklc8o3apl.png" alt="Image description" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will be brougth to the lambda dashboard, showing function successfully created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmnv05d1f92eqhtqwbx5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmnv05d1f92eqhtqwbx5i.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right now, we’ll need to tweak the permission for our IAM role. Navigate to the configuration section, and select the permission button. Next you’ll need to click on the link in the role name section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6pginbfqd4o4y2ptyn0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6pginbfqd4o4y2ptyn0.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be redirected to the IAM service tab, you will notice by default we already have a policy that has AWSLambdaBasicExecutionRole, we will need to attach more policies like Dynamodb full access and Cloudwatchlog full access&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjoafllliknc5udl9gizf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjoafllliknc5udl9gizf.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we will need to attach our desired policies to this role, first we’ll add “AwsDynamoDBFullAccess”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3llps098630po2kkn5gi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3llps098630po2kkn5gi.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will add the next policy to this role, which is:  “CloudWatchLogsFullAccess”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlnjdl64l18pspvtxqcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlnjdl64l18pspvtxqcj.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Policies have been added, hence our lambda now has the required access to interact with DynamoDB and to get logs from out Cloudwatch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg0gbiirqw2efoupk4zu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg0gbiirqw2efoupk4zu.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By following these steps, you will have created a Lambda function named “api_processing” and set up a new role with the appropriate permissions to interact with DynamoDB.&lt;br&gt;
Step THREE: Create an  API gateway&lt;/p&gt;

&lt;p&gt;In the AWS dashboard, search for API Gateway and click on it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2izp6u8l1bme41sl768q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2izp6u8l1bme41sl768q.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be brought straight to Create API dashboard, choose REST API and click on build&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3lyoalt580a3t5j0xgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3lyoalt580a3t5j0xgj.png" alt="Image description" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose “new API” and give it a name (e.g., serverless-demo`).&lt;br&gt;
Leave the description section blank and select regional as the API endpoint type. Then click on create api&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwwrhf70e25uwp1htj52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwwrhf70e25uwp1htj52.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we are going to create resources: Click on “Create Resource”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazjahu3oiolokgll944u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazjahu3oiolokgll944u.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll need to give a resource a name, in the resource name section, write &lt;code&gt;status&lt;/code&gt; and in the resource path select &lt;code&gt;/&lt;/code&gt;. Ensure to check the button to enable CORS for cross-origin requests. And click create resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F126hi5jluzirs45vszup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F126hi5jluzirs45vszup.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As seen below, the resource has been successfully created, next we’ll create methods for the status resource:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0vpi8krw0m6kq6pv40s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0vpi8krw0m6kq6pv40s.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click on the “Create Method” icon, you will be brought to the tab below, select the method “get” and click the checkmark. Select lambda function as the Integration type. Ensure to click on the button to turn on lambda proxy integration. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frw3v3lymfrugqwptf3kh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frw3v3lymfrugqwptf3kh.png" alt="Image description" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify your Lambda function name (&lt;code&gt;api_processing&lt;/code&gt;), leave the other options as default. Click ‘create method”. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpxxpc0cdd81h4vukbdx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpxxpc0cdd81h4vukbdx.png" alt="Image description" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The get method for resource status has been successfully created. &lt;/p&gt;

&lt;p&gt;We’ll need to create a new resource and give it the name &lt;code&gt;employee&lt;/code&gt; and in the resource path select &lt;code&gt;/&lt;/code&gt;. Ensure to check the button to enable CORS for cross-origin requests. And click create resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vigu8il6jcq85uqvtel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vigu8il6jcq85uqvtel.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly created resource should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcqau6v01elx66ee1whv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcqau6v01elx66ee1whv.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll need to create a new resource and give it the name &lt;code&gt;employees&lt;/code&gt; and in the resource path select &lt;code&gt;/&lt;/code&gt;. Ensure to check the button to enable CORS for cross-origin requests. And click create resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6cr0jg6j4r9t820hdmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6cr0jg6j4r9t820hdmb.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly created resource should look like this, next we’ll create ‘get’ method  for the employees resource:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm108suuwmei2nt176wp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm108suuwmei2nt176wp.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the “Create Method” icon, you will be brought to the tab below, select the method “get” and click the checkmark. Select lambda function as the Integration type. Ensure to click on the button to turn on lambda proxy integration. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo25yepmrnolybvuxwvft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo25yepmrnolybvuxwvft.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify your Lambda function name (&lt;code&gt;api_processing&lt;/code&gt;), leave the other options as default. Click ‘create method’, then confirm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0qz6vzu7tu5prfc35s5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0qz6vzu7tu5prfc35s5.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly created get method for the /employees resource should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhlnjb79dlu3f0l27ee9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhlnjb79dlu3f0l27ee9.png" alt="Image description" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly we will need to create the CRUD methods for the employee resource. For each HTTP method (GET, POST, DELETE, PATCH):&lt;br&gt;
“Click on create Method” icon, you will be brought to the tab below, select the method “get” and click the checkmark. Select lambda function as the Integration type. Ensure to click on the button to turn on lambda proxy integration. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3qkbc13b71h45elbm3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3qkbc13b71h45elbm3m.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify your Lambda function name (&lt;code&gt;api_processing&lt;/code&gt;), leave the other options as default. Click ‘create method’, then confirm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkt38a1pqpcapqp8q0pba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkt38a1pqpcapqp8q0pba.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly created get method should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxx102ampt5njjk8904b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxx102ampt5njjk8904b.png" alt="Image description" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the “Create Method” icon, you will be brought to the tab below, select the method “post” and click the checkmark. Select lambda function as the Integration type. Ensure to click on the button to turn on lambda proxy integration. Specify your Lambda function name (&lt;code&gt;api_processing&lt;/code&gt;), leave the other options as default. Click ‘create method’, then confirm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawi2qjehqxvnpneytdqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawi2qjehqxvnpneytdqq.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly created post method should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy28cfketjsa6fjdvrfxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy28cfketjsa6fjdvrfxh.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the “Create Method” icon, you will be brought to the tab below, select the method “delete” and click the checkmark. Select lambda function as the Integration type. Ensure to click on the button to turn on lambda proxy integration. Specify your Lambda function name (&lt;code&gt;api_processing&lt;/code&gt;), leave the other options as default. Click ‘create method’, then confirm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3loj0etahl4hprp3q4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3loj0etahl4hprp3q4r.png" alt="Image description" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly created delete method should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9ybl82rjmyks0x6doma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9ybl82rjmyks0x6doma.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the “Create Method” icon, you will be brought to the tab below, select the method “patch” and click the checkmark. Select lambda function as the Integration type. Ensure to click on the button to turn on lambda proxy integration. Specify your Lambda function name (&lt;code&gt;api_processing&lt;/code&gt;), leave the other options as default. Click ‘create method’, then confirm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fus5mt2ik78oaq10fsrra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fus5mt2ik78oaq10fsrra.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly created patch method should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4lzmc50iocil3u0w9e3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4lzmc50iocil3u0w9e3.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resources: These are endpoints in your API (e.g., /employee or /status). They represent logical containers for HTTP methods and map directly to backend operations.&lt;br&gt;
Methods: These are the HTTP operations (like GET, POST, PUT, DELETE) applied to a resource. They determine what action is performed on the resource. For example:&lt;br&gt;
GET: Fetch data.&lt;br&gt;
POST: Create data.&lt;br&gt;
PUT: Update existing data.&lt;br&gt;
DELETE: Remove data.&lt;br&gt;
API Gateway integrates these resources and methods with AWS Lambda to execute backend logic or interact with a database like DynamoDB&lt;/p&gt;

&lt;p&gt;Click on deploy API&lt;br&gt;
In the deploy API overview, a box would pop up for you to choose a stage (New Stage), and then type in a stage name (dev), you can fill in the description box or leave it blank, it is optional. Then click on deploy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83bg727a3n80vu4nwcd3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83bg727a3n80vu4nwcd3.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By following these steps, you will have successfully created a REST API named “serverless-demo” that serves as an HTTP endpoint for your Lambda function. In the subsequent steps. Take note of the invoke URL, we will need it later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk844rk9t7u4v1f1lbri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk844rk9t7u4v1f1lbri.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step FOUR: Test your API&lt;/p&gt;

&lt;p&gt;This right here is the code editor overview, and we have the default lambda code, so we will try to run the invoke url code to test its functionality. You can use tools like Postman or a browser to make API requests. We should get the response “Hello from Lambda!” on our screen. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv72av1rnppackyambzq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv72av1rnppackyambzq.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the invoke url code on our browser, we will include the pathway to our status resource (e.g /status) at the end of the URL code. The essence of the status resource is to test the functionality..&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6u45m0g7dfr0i6d5mjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6u45m0g7dfr0i6d5mjj.png" alt="Image description" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what we got on browser, “Hello from Lambda!” which shows that everything in our application and code is working fine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcmnbdvdscpausqec46s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcmnbdvdscpausqec46s.png" alt="Image description" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Preferably we will also try the invoke url code on postman, we will also include the pathway to our status resource (e.g /status) at the end of the URL code. We will also select the “get” option and click on send..&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl765lewldaqtakcv47c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl765lewldaqtakcv47c.png" alt="Image description" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the output on lambda: “Hello from Lambda!”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyviuo57fshbthbl29et8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyviuo57fshbthbl29et8.png" alt="Image description" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we will need to open the lambda dashboard and navigate to the code editor’s tab and replace the existing code with the following code snippet:&lt;br&gt;
Here, we will write a logic for each CRUD operation:&lt;/p&gt;

&lt;p&gt;POST: Insert a new record in DynamoDB.&lt;br&gt;
GET: Fetch all or a specific record from DynamoDB.&lt;br&gt;
UPDATE: Update a record.&lt;br&gt;
DELETE: Remove a record.&lt;/p&gt;

&lt;p&gt;You can write or upload your code on the console editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F43akprl4td36r6eza6dt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F43akprl4td36r6eza6dt.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the link to the &lt;a href="https://github.com/Uwadon1/AWS_RestLambdaAPI/blob/main/lambda_function.py" rel="noopener noreferrer"&gt;Code on my github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This function serves as a robust backbone for employee management, leveraging the power of AWS Lambda and DynamoDB in a RESTful architecture.&lt;/p&gt;

&lt;p&gt;Next we hit the deploy button to update our new python code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj2ylwj526pyslgwgpch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj2ylwj526pyslgwgpch.png" alt="Image description" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will move, right away to test our Lambda function. We will need to choose our test event e.g: “test-crud” and save&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv38sc30l9efg2cull224.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv38sc30l9efg2cull224.png" alt="Image description" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will retest the /status ‘get’  API endpoint with Postman. Using the invoke url code on our browser, we will include the pathway to our status resource (e.g /status) at the end of the URL code. We will get the output below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgi0m7e1rrgcydxsxfj06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgi0m7e1rrgcydxsxfj06.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the browser, we got this output. “Service is operational” which shows that everything in our application and code is working fine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdt5yq95w6e7utnnapqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdt5yq95w6e7utnnapqo.png" alt="Image description" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will test the /employee ‘post’ API endpoint with Postman. Using the invoke url code on our browser, we will include the pathway to our employee resource (e.g employee) at the end of the URL code. We will choose the following options as shown below, choose ‘post’ option, and select body, then raw, and json format to insert in our command as json.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
{&lt;br&gt;
“Employeeid”: “102”,&lt;br&gt;
“job_title”: “CEO”,&lt;br&gt;
“full_name”: “John Tom”,&lt;br&gt;
“salary”: “1000000”&lt;br&gt;
}.&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note we changed the last endpoint from /status to /employee. We should see ‘200 okay’. Which shows everything is functional. We should also see our output in the down box.&lt;br&gt;
We will follow the same steps to input two other values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0rzdhorl0e4n8or62ae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0rzdhorl0e4n8or62ae.png" alt="Image description" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwb7vmumhpokuit9qieg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwb7vmumhpokuit9qieg.png" alt="Image description" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will test the /employee ‘delete’ API endpoint with Postman. Using the invoke url code on our browser, we will include the pathway to our employee resource (e.g /employee) at the end of the URL code. We will choose the following options as shown below, choose ‘delete’ option, and type in our command as json: &lt;br&gt;
&lt;code&gt;{&lt;br&gt;
“Employee”: “102”&lt;br&gt;
}. &lt;/code&gt;&lt;br&gt;
We should see the output below “Operation”: “DELETE”, and ‘200 okay’. Which shows everything is functional.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgovbq4581pnjwmer71x2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgovbq4581pnjwmer71x2.png" alt="Image description" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will test the /employee ‘patch’ API endpoint with Postman. Using the invoke url code on our browser, we will include the pathway to our employee resource (e.g /employee) at the end of the URL code. We will choose the following options as shown below, choose patch’ option, and type in our command as json: &lt;br&gt;
&lt;code&gt;{&lt;br&gt;
“EmployeeId”: “103”,&lt;br&gt;
“updateKey”: “full_name”,&lt;br&gt;
“updateValue”: “Chioma Chukwu”&lt;br&gt;
}.&lt;/code&gt;&lt;br&gt;
We should see the output below “Operation”: “UPDATE”, and ‘200 okay’. Which shows everything is functional.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd9gc0b0sw7ch777j6dy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd9gc0b0sw7ch777j6dy.png" alt="Image description" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we will test the /employees ‘get’  API endpoint with Postman. Using the invoke url code on our browser, we will include the pathway to our employees resource (e.g /employees) at the end of the URL code. We will get the info output of all the employees in the company .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dq34hdr9c10qw6zjy2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dq34hdr9c10qw6zjy2g.png" alt="Image description" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will go into our Dynamo DB dashboard to verify if all we have created using our API and lambda would reflect inside our database&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9267okynaonzse3545y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9267okynaonzse3545y.png" alt="Image description" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step FIVE: Monitoring the logs and insights&lt;br&gt;
Using cloudwatch we can monitor the logs for insights to check for errors and troubleshoot where necessary&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam6tix3u3td4iws324pc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam6tix3u3td4iws324pc.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy an EC2 instance inside a custom VPC using Terraform.</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Fri, 08 Nov 2024 13:43:10 +0000</pubDate>
      <link>https://dev.to/uwadon1/deploy-an-ec2-instance-inside-a-custom-vpc-using-terraform-26e9</link>
      <guid>https://dev.to/uwadon1/deploy-an-ec2-instance-inside-a-custom-vpc-using-terraform-26e9</guid>
      <description>&lt;p&gt;Deploy an EC2 instance inside a custom VPC using Terraform.&lt;/p&gt;

&lt;p&gt;This guide will set up the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A VPC with one Availability Zones (AZs).&lt;/li&gt;
&lt;li&gt;In the AZ, there will be:&lt;/li&gt;
&lt;li&gt;A public subnet for resources like NAT gateway and EC2 instance.&lt;/li&gt;
&lt;li&gt;Internet Gateway for outbound internet traffic from public subnets.&lt;/li&gt;
&lt;li&gt;Route Tables to handle routing within the subnets.&lt;/li&gt;
&lt;li&gt;Security Groups to control traffic to/from instances.
In this project, you will learn how to automatically deploy an EC2 instance inside a custom VPC using Terraform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;Prerequisites&lt;/u&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An active AWS account with an IAM user already created&lt;/li&gt;
&lt;li&gt;Text editor of your choice (VSCode Recommended)&lt;/li&gt;
&lt;li&gt;Terraform Installed: Make sure you have Terraform installed on your machine, you should also have a basic knowledge of how it works.&lt;/li&gt;
&lt;li&gt;AWS credentials: You should have AWS credentials configured locally using AWS CLI or through environment variables.&lt;/li&gt;
&lt;li&gt;AWS Provider: This guide uses the AWS provider.&lt;/li&gt;
&lt;li&gt;Bash scripting knowledge&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you should know by now, Terraform is an IaC tool that helps to automate processes which increase delivery time of software. In this tutorial, Terraform will be employed in setting up an ec2 instance in a VPC and all of its components&lt;/p&gt;

&lt;p&gt;Setting up the project environment&lt;br&gt;
The first step is to create a folder on your device and open it up in VSCode. We will be creating 4 terraform files for this project;&lt;br&gt;
Your project directory can be structured like this:&lt;br&gt;
terraform/&lt;br&gt;
├── provider.tf&lt;br&gt;
├── variables.tf&lt;br&gt;
├── main.tf&lt;br&gt;
├── outputs.tf&lt;/p&gt;

&lt;p&gt;Here is the outline of all the resources, we will be creating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a VPC folder and files&lt;/li&gt;
&lt;li&gt;Define the Provider Block&lt;/li&gt;
&lt;li&gt;Create the VPC Block&lt;/li&gt;
&lt;li&gt;Create the Subnet(s)&lt;/li&gt;
&lt;li&gt;Create an Internet Gateway&lt;/li&gt;
&lt;li&gt;Create Route Tables&lt;/li&gt;
&lt;li&gt;Associate Subnet with Route Tables&lt;/li&gt;
&lt;li&gt;Create Security Groups&lt;/li&gt;
&lt;li&gt;Create KeyPairs&lt;/li&gt;
&lt;li&gt;Create EC2 Instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Terraform Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Creating your Provider Configuration&lt;/strong&gt;&lt;br&gt;
The first step is to configure the AWS provider on your provider.tf file&lt;br&gt;
hcl&lt;br&gt;
&lt;code&gt;#Create a Terraform Provider Block&lt;br&gt;
terraform {&lt;br&gt;
required_providers {&lt;br&gt;
aws = {&lt;br&gt;
source = “hashicorp/aws”&lt;br&gt;
version = “~&amp;gt;5.68.0”&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
provider “aws” {&lt;br&gt;
region = “us-east-1” # Select your desired region&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlyo2u64fl7foy8sf6wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlyo2u64fl7foy8sf6wd.png" alt="Provider Block" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Creating your VPC Block&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a VPC using the following block.&lt;br&gt;
hcl&lt;br&gt;
&lt;code&gt;#Create the VPC Block&lt;br&gt;
resource"aws_vpc" "my_vpc" {&lt;br&gt;
cidr_block = var.vpc_cidr&lt;br&gt;
enable_dns_support = true&lt;br&gt;
enable_dns_hostnames = true&lt;br&gt;
tags = {&lt;br&gt;
Name = "my-vpc"&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmik3uqr89x0klld57c2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmik3uqr89x0klld57c2h.png" alt="VPC Block" width="793" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Creating your Subnet Block&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this demo, we will create only one subnet in one availability zone.&lt;br&gt;
hcl&lt;br&gt;
&lt;code&gt;#Create the Subnet(s)&lt;br&gt;
resource "aws_subnet" "public_subnet" {&lt;br&gt;
vpc_id = aws_vpc.my_vpc.id&lt;br&gt;
cidr_block = var.public_subnet_cidr&lt;br&gt;
availability_zone = var.availability_zone&lt;br&gt;
map_public_ip_on_launch = true&lt;br&gt;
tags = {&lt;br&gt;
Name = "my-pub-sub"&lt;br&gt;
}&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhi6569p07zfc56ktc7ve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhi6569p07zfc56ktc7ve.png" alt="Subnet Block" width="770" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Internet Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An Internet Gateway will allow public subnets to have access to the internet.&lt;br&gt;
hcl&lt;br&gt;
&lt;code&gt;#Create an Internet Gateway&lt;br&gt;
resource "aws_internet_gateway" "igw" {&lt;br&gt;
vpc_id = aws_vpc.my_vpc.id&lt;br&gt;
tags = {&lt;br&gt;
Name = "my-internet-gateway"&lt;br&gt;
}&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhwuiht2kz1nfqg6s63f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhwuiht2kz1nfqg6s63f.png" alt="Internet Gateway" width="632" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Route Tables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need a route table for both public and private subnets. Public subnets route through the Internet Gateway, while private subnets route through a NAT Gateway.&lt;/p&gt;

&lt;p&gt;hcl&lt;br&gt;
&lt;code&gt;#Create Route Tables&lt;br&gt;
resource "aws_route_table" "public_rt" {&lt;br&gt;
vpc_id = aws_vpc.my_vpc.id&lt;br&gt;
route {&lt;br&gt;
cidr_block = "0.0.0.0/0"&lt;br&gt;
gateway_id = aws_internet_gateway.igw.id&lt;br&gt;
}&lt;br&gt;
tags = {&lt;br&gt;
Name = "public-rt"&lt;br&gt;
}&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feypmg74mpaflsrokxum8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feypmg74mpaflsrokxum8.png" alt="Route Table Resource Block" width="800" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Associate public subnets with the public route table&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;hcl&lt;br&gt;
&lt;code&gt;#Associate Public Subnet with the Public Route Table&lt;br&gt;
resource "aws_route_table_association" "public_rt_association" {&lt;br&gt;
subnet_id = aws_subnet.public_subnet.id&lt;br&gt;
route_table_id = aws_route_table.public_rt.id&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdssiv4jt37j64fp4742k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdssiv4jt37j64fp4742k.png" alt="Route Table Association" width="680" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Security Groups&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s a basic security group allowing inbound SSH access from your IP and allowing all outbound traffic.&lt;/p&gt;

&lt;p&gt;hcl&lt;br&gt;
&lt;code&gt;#Create Security Groups&lt;br&gt;
resource "aws_security_group" "my-sg" {&lt;br&gt;
vpc_id = aws_vpc.my_vpc.id # Ensure the security group is created in the same VPC&lt;br&gt;
name = "my security group"&lt;br&gt;
description = "my security group"&lt;br&gt;
ingress {&lt;br&gt;
description = "HTTP"&lt;br&gt;
from_port = 80&lt;br&gt;
to_port = 80&lt;br&gt;
protocol = "tcp"&lt;br&gt;
cidr_blocks = ["0.0.0.0/0"] # Allow traffic from anywhere&lt;br&gt;
}&lt;br&gt;
ingress {&lt;br&gt;
description = "HTTPS"&lt;br&gt;
from_port = 443&lt;br&gt;
to_port = 443&lt;br&gt;
protocol = "tcp"&lt;br&gt;
cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
}&lt;br&gt;
ingress {&lt;br&gt;
description = "SSH"&lt;br&gt;
from_port = 22&lt;br&gt;
to_port = 22&lt;br&gt;
protocol = "tcp"&lt;br&gt;
cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
}&lt;br&gt;
egress {&lt;br&gt;
from_port = 0&lt;br&gt;
to_port = 0&lt;br&gt;
protocol = "-1"&lt;br&gt;
cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
}&lt;br&gt;
tags = {&lt;br&gt;
Name = "my-sg"&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flw1pqnnkune3gp5lumt7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flw1pqnnkune3gp5lumt7.png" alt="Security Group" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxn9n97n1agl8d4xckhxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxn9n97n1agl8d4xckhxa.png" alt="Security Group Contd" width="729" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Key Pairs&lt;/strong&gt;&lt;br&gt;
A key pair is a set of cryptographic keys used for authentication and encryption. It consists of a public key and a private key.&lt;/p&gt;

&lt;p&gt;Public Key: This key is freely shared and can be used to encrypt data. Only the corresponding private key can decrypt the data.&lt;br&gt;
Private Key: This key is kept secret and should never be shared. It's used to decrypt data encrypted with the public key.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hcl&lt;br&gt;
Generate a new private key&lt;br&gt;
resource "tls_private_key" "terraform_kp" {&lt;br&gt;
algorithm = "RSA"&lt;br&gt;
rsa_bits = 4096&lt;br&gt;
}&lt;br&gt;
Create AWS Key Pair using the public key generated above&lt;br&gt;
resource "aws_key_pair" "my-terraform-kp" {&lt;br&gt;
key_name = "terraform-kp" # New Key Pair Name&lt;br&gt;
public_key = tls_private_key.terraform_kp.public_key_openssh&lt;br&gt;
}&lt;br&gt;
To create a file or folder to save your Private Key&lt;br&gt;
resource "local_file" "terraform_kp" {&lt;br&gt;
content = tls_private_key.terraform_kp.private_key_pem&lt;br&gt;
filename = "terraform-kp.pem" # Save as a .pem file&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27ab8edf3qtty0t3aw7i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27ab8edf3qtty0t3aw7i.png" alt="Key Pair Resource Block" width="789" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Create an EC Instance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#Create EC2 Instance with NGINX installation via user_data&lt;br&gt;
resource "aws_instance" "project_server" {&lt;br&gt;
depends_on = [aws_security_group.my-sg, aws_subnet.public_subnet]&lt;br&gt;
ami = "ami-0e86e20dae9224db8" # Amazon Ubuntu AMI&lt;br&gt;
instance_type = "t2.micro"&lt;br&gt;
subnet_id = aws_subnet.public_subnet.id&lt;br&gt;
associate_public_ip_address = true&lt;br&gt;
key_name = "terraform-kp"&lt;br&gt;
vpc_security_group_ids = [aws_security_group.my-sg.id]&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8u85w91f6dgwopg69e43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8u85w91f6dgwopg69e43.png" alt="EC2 Resource Block" width="770" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Outputs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can create an &lt;code&gt;outputs.tf&lt;/code&gt; to display useful information like the VPC ID and subnet IDs after deployment.&lt;br&gt;
&lt;code&gt;outputs.tf&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hcl&lt;br&gt;
Output Public IP&lt;br&gt;
output "project_server_public_ip" {&lt;br&gt;
value = aws_instance.project_server.public_ip&lt;br&gt;
}&lt;br&gt;
Output Public DNS&lt;br&gt;
output "aws_instance_public_dns" {&lt;br&gt;
value = aws_instance.project_server.public_dns&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4iujyav3n1c8mw9tn7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4iujyav3n1c8mw9tn7z.png" alt="Output.tf" width="717" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Variables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can create a &lt;code&gt;variables.tf&lt;/code&gt; file to display your variables like the VPC ID and subnet IDs after deployment.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;variable "vpc_cidr" {&lt;br&gt;
default = "10.0.0.0/16"&lt;br&gt;
}&lt;br&gt;
variable "public_subnet_cidr" {&lt;br&gt;
default = "10.0.1.0/24"&lt;br&gt;
}&lt;br&gt;
variable "private_subnet_cidr" {&lt;br&gt;
default = "10.0.3.0/24"&lt;br&gt;
}&lt;br&gt;
variable "availability_zone" {&lt;br&gt;
default = "us-east-1a"&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcohu7irj0gn0dq9ejr9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcohu7irj0gn0dq9ejr9g.png" alt="Variable.tf" width="800" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. How to Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ø Initialize Terraform:&lt;br&gt;
Navigate to your project directory and run:&lt;br&gt;
bash&lt;br&gt;
&lt;em&gt;terraform init&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjkk60w7hyrlv1erhyjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjkk60w7hyrlv1erhyjl.png" alt="Terraform Init" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ø Plan the infrastructure:&lt;br&gt;
Review the changes that Terraform will make:&lt;br&gt;
bash&lt;br&gt;
&lt;em&gt;terraform plan&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhr18jipk92cqp9jcc3iq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhr18jipk92cqp9jcc3iq.png" alt="Terrform Plan" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmakrh7uivfzjdpdtt1rl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmakrh7uivfzjdpdtt1rl.png" alt="Terrform Plan Contd" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ø Apply the configuration:&lt;br&gt;
Deploy the resources by running:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
&lt;em&gt;terraform apply&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhzq89if77elky7alkon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhzq89if77elky7alkon.png" alt="Terrform Apply" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbnsfu84h1aqc2tpja1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbnsfu84h1aqc2tpja1n.png" alt="Terrform apply Contd" width="714" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ø Confirm:&lt;br&gt;
Type &lt;code&gt;yes&lt;/code&gt; when prompted to confirm the creation of resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xz3tbkrf2wvt1jv87sf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xz3tbkrf2wvt1jv87sf.png" alt="Confirm Terrform Apply" width="800" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;13. Verify the Resources Created:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate to your AWS management console and search for &lt;strong&gt;VPC&lt;/strong&gt; to see the newly created &lt;strong&gt;VPC via terraform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdbpbdmivdkkmtzxeczx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdbpbdmivdkkmtzxeczx.png" alt="VPC resource" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From your AWS management console dashboard, search for &lt;strong&gt;EC2&lt;/strong&gt; to see the newly created &lt;strong&gt;EC2 via terraform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjws4930r39ic5v3l9lba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjws4930r39ic5v3l9lba.png" alt="EC2 Resource" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;14. Clean Up Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re done and no longer need your resources, you can terminate them to avoid incurring charges.&lt;br&gt;
Run the following command to clean your resources&lt;br&gt;
bash&lt;br&gt;
terraform destroy&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid5np2pv0e96wo0jd47a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid5np2pv0e96wo0jd47a.png" alt="Terraform Destroy" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see a prompt to type YES in order to confirm your destroy action. Type YES, and your resources would be deleted completely as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44yr0lfzeppxicdxnnxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44yr0lfzeppxicdxnnxy.png" alt="Confirm Terraform Destroy" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
By following these steps and customizing the Terraform configuration to your specific needs, you can effectively launch EC2 instances in a VPC using Terraform, and you should be able to SSH into your website using the EC2 instance’s public IP.&lt;/p&gt;

&lt;p&gt;If you find this helpful, please click the clap 👏 button below a few times to show your support for the author 👇&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>infrastructureascode</category>
      <category>ec2</category>
      <category>vpc</category>
    </item>
    <item>
      <title>Launch an EC2 instance in a custom-made VPC using cloud formation</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Fri, 08 Nov 2024 10:44:42 +0000</pubDate>
      <link>https://dev.to/uwadon1/step-by-step-guide-to-launch-ec2-instance-in-a-vpc-using-cloud-formation-311d</link>
      <guid>https://dev.to/uwadon1/step-by-step-guide-to-launch-ec2-instance-in-a-vpc-using-cloud-formation-311d</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl804864qf3emiis675xv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl804864qf3emiis675xv.png" alt="Architectural Diagram of Deploying EC2 in a Custom-made VPC using Cloud Formation" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure as Code (IaC):&lt;/strong&gt; is a practice of managing and provisioning infrastructure through code instead of manual processes. By treating infrastructure as code, organizations can automate the creation, modification, and deletion of infrastructure resources, such as servers, networks, and storage e.t.c.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problems Solved by IaC:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual Error Reduction:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistency: IaC ensures that infrastructure is provisioned consistently, reducing the risk of human error.&lt;/li&gt;
&lt;li&gt;Repeatable Deployments: IaC scripts can be run multiple times to create identical environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Increased Efficiency:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automation: IaC automates the provisioning process, saving time and effort.&lt;/li&gt;
&lt;li&gt;Faster Time to Market: Infrastructure can be deployed quickly and efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Improved Collaboration:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control: IaC uses version control systems like Git to track changes, enabling collaboration and rollback.&lt;/li&gt;
&lt;li&gt;Shared Understanding: Code-based infrastructure is easier to understand and collaborate on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Enhanced Security:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuration Drift Prevention: IaC helps maintain consistent configurations, reducing security vulnerabilities.&lt;/li&gt;
&lt;li&gt;Auditing and Compliance: IaC provides a clear audit trail for compliance and security audits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Popular IaC Tools:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Terraform:&lt;/em&gt; A popular open-source tool for managing infrastructure across multiple cloud providers.&lt;br&gt;
&lt;em&gt;Ansible:&lt;/em&gt; A configuration management tool that can be used for infrastructure automation.&lt;br&gt;
&lt;em&gt;Puppet:&lt;/em&gt; A configuration management tool for automating server and system administration tasks.&lt;br&gt;
&lt;em&gt;Chef:&lt;/em&gt; A configuration management tool for automating infrastructure and applications.&lt;br&gt;
&lt;em&gt;AWS Cloud Formation:&lt;/em&gt; This is an infrastructure-as-code tool that defines resources and their configurations in a standardized template -- either a JavaScript Object Notation (JSON) or YAML format. In general, YAML is the preferable option, as it's more concise; JSON requires a much higher number of characters. YAML also supports the ability to add comments, which JSON does not.&lt;/p&gt;

&lt;p&gt;By adopting IaC, organizations can significantly improve their infrastructure management practices, reduce operational costs, and accelerate application delivery.&lt;/p&gt;

&lt;p&gt;Alright! Let’s dive right into how to launch an EC2 instance in a VPC using AWS CloudFormation. &lt;/p&gt;

&lt;p&gt;This guide covers creating a basic CloudFormation stack to provision a VPC, subnets, security groups, and an EC2 instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Prepare Your CloudFormation Template&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So the next thing we will need to do is, we’ll want to do is to create a CloudFormation template file (in YAML format) named &lt;code&gt;ec2_vpc.yaml&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We will be using the below template to create an EC2 Instance by replacing the following defaults of SubnetId, SecurityGroupId, and ImageId with actual values that exist&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;`AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2010-09-09&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My first Cloud Formation Template with YAML comments.&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;MyVPC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::VPC&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CidrBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.0.0.0/16&lt;/span&gt;
      &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MyVPC&lt;/span&gt;

  &lt;span class="na"&gt;PublicSubnet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::Subnet&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CidrBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.0.1.0/24&lt;/span&gt;
      &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;MyVPC&lt;/span&gt;
      &lt;span class="na"&gt;MapPublicIpOnLaunch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublicSubnet&lt;/span&gt;

  &lt;span class="na"&gt;InternetGateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::InternetGateway&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MyInternetGateway`&lt;/span&gt;

&lt;span class="na"&gt;`AttachGateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::VPCGatewayAttachment&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;MyVPC&lt;/span&gt;
      &lt;span class="na"&gt;InternetGatewayId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;InternetGateway&lt;/span&gt;

  &lt;span class="na"&gt;PublicRouteTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::RouteTable&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;MyVPC&lt;/span&gt;
      &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublicRouteTable&lt;/span&gt;

  &lt;span class="na"&gt;PublicRoute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::Route&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;RouteTableId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PublicRouteTable&lt;/span&gt;
      &lt;span class="na"&gt;DestinationCidrBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
      &lt;span class="na"&gt;GatewayId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;InternetGateway&lt;/span&gt;

  &lt;span class="na"&gt;SubnetRouteTableAssociation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SubnetRouteTableAssociation&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;SubnetId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PublicSubnet&lt;/span&gt;
      &lt;span class="na"&gt;RouteTableId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PublicRouteTable`&lt;/span&gt;

 &lt;span class="na"&gt;`MySecurityGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SecurityGroup&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GroupDescription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow SSH and HTTP access&lt;/span&gt;
      &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;MyVPC&lt;/span&gt;
      &lt;span class="na"&gt;SecurityGroupIngress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
          &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22&lt;/span&gt;
          &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22&lt;/span&gt;
          &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
          &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
          &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
          &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
          &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
          &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
          &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
      &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MySecurityGroup`&lt;/span&gt;

&lt;span class="na"&gt;`MyEC2Instance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::Instance&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;InstanceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t2.micro&lt;/span&gt;
      &lt;span class="na"&gt;KeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2-CTF-VPC&lt;/span&gt;  &lt;span class="c1"&gt;# Ensure this key pair exists in your AWS account&lt;/span&gt;
      &lt;span class="na"&gt;ImageId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ami-06b21ccaeff8cd686&lt;/span&gt;  &lt;span class="c1"&gt;# Confirm this is valid for your target region&lt;/span&gt;
      &lt;span class="na"&gt;NetworkInterfaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AssociatePublicIpAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;SubnetId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PublicSubnet&lt;/span&gt;
          &lt;span class="na"&gt;DeviceIndex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
          &lt;span class="na"&gt;GroupSet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;MySecurityGroup&lt;/span&gt;
      &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MyEC2Instance&lt;/span&gt;
&lt;span class="err"&gt;`&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hvxk6tf794vp7u596q5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hvxk6tf794vp7u596q5.png" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqf50wmdnz6inlepkap80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqf50wmdnz6inlepkap80.png" alt="Image description" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6d0uuze5ai1ams1go1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6d0uuze5ai1ams1go1b.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmko6ludlscy86dl97w3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmko6ludlscy86dl97w3.png" alt="Image description" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2: Create the CloudFormation Stack:&lt;br&gt;
 After you input your login details, you will be brought to the dashboard, observe the search button at the top.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqmewfy8dikc25allrwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqmewfy8dikc25allrwp.png" alt="Image description" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we’ll click on the search bar, and type “CLOUD FORMATION” you will see the Cloudformation resource as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a2lmyvasdu35doz3a6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a2lmyvasdu35doz3a6c.png" alt="Image description" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you clicked on the Cloudformation, you will be brought to the cloudformation dashboard, click on the “Create Stack"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1szfnlkxfksb65765l7q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1szfnlkxfksb65765l7q.png" alt="Image description" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating a New Stack, inside the stack section, you will see 3 options: “Choose an existing template, Use a sample template and Build from Infrastructure Composer.” &lt;br&gt;
But for the sake of this projec, we will select the first option “Choose an existing template”. &lt;br&gt;
Scroll down and specify the template to choose the file from. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5rdq68mv579mjg4g2l1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5rdq68mv579mjg4g2l1.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will choose the “upload a template file” option. Then click on choose file to upload our YAML file from our local machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faecxaz4dgzw9rwj8j2j5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faecxaz4dgzw9rwj8j2j5.png" alt="Image description" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upload your &lt;code&gt;ec2_vpc.yaml&lt;/code&gt; template file from your computer. Select the file and click open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fse8a6rgko7r2o990s7yd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fse8a6rgko7r2o990s7yd.png" alt="Image description" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As seen below, after uploading your preferred file, click the next button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmc0dgkap7wcafae03jv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmc0dgkap7wcafae03jv.png" alt="Image description" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next would be to enter a Stack name (e.g., &lt;code&gt;EC2InVPCStack&lt;/code&gt;) and click on the next button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fretfjo6ie8tqrn830yuq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fretfjo6ie8tqrn830yuq.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure Stack Options: Choose any additional options if necessary (tags, permissions, etc.), or leave as default. We will give our stack a tag key-value pair as shown below and scroll down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fec1pu3wpw9vrln1gkgh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fec1pu3wpw9vrln1gkgh1.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And leave the rest as default and click next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyvp7mdjqyy64fb45xhs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyvp7mdjqyy64fb45xhs.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Review and Create Stack: Review the details and check if all the configurations are set properly. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrovvv49exkxfnla6ini.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrovvv49exkxfnla6ini.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything is properly set, click on the ‘submit’ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtukblwnxvlms8fqx6jb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtukblwnxvlms8fqx6jb.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Wait for the Stack to Complete:&lt;/strong&gt; CloudFormation will begin creating the resources. You can monitor the progress in the “Events” tab. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nat0bf6fyzvor4fpr1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nat0bf6fyzvor4fpr1w.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the ‘Status’ shows CREATE_COMPLETE, your EC2 instance and VPC and other resources have been successfully launched.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7rpw7ha9m0wr6ti1d69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7rpw7ha9m0wr6ti1d69.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Verify the Resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;View Resources in CloudFormation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the CloudFormation console, select your stack and go to the Resources tab to see the created resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jingoc83nsvdehs5meh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jingoc83nsvdehs5meh.png" alt="Image description" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check in EC2 and VPC Consoles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the EC2 console to see the running instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6770stjki02awd77kost.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6770stjki02awd77kost.png" alt="Image description" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the VPC console to verify the VPC, subnet, and security group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl612bvrrh9dksm0sw02t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl612bvrrh9dksm0sw02t.png" alt="Image description" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This template creates a basic setup with a VPC, subnet, internet gateway, route table, security group, and an EC2 instance. You can customize the configurations further based on your requirements.&lt;/p&gt;

&lt;p&gt;I also want to express that your feedback is always welcome. As I strive to provide accurate information and insights, I acknowledge that there’s always room for improvement. If you notice any mistakes or have suggestions for enhancement, I sincerely invite you to share them with me.&lt;/p&gt;

&lt;p&gt;🤩 Thanks for being patient and following me. Keep supporting 🙏&lt;br&gt;
Share a reaction 👏 if you liked this article.&lt;/p&gt;

&lt;p&gt;For more exercises — please follow me below ✅!&lt;br&gt;
&lt;a href="https://dev.to/uwadon1"&gt;https://dev.to/uwadon1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cloudformation</category>
      <category>aws</category>
      <category>devops</category>
      <category>cloudengineering</category>
    </item>
    <item>
      <title>Step-by-step guide to containerize your full-stack MERN application, using Docker Compose.</title>
      <dc:creator>Uwadone Joshua</dc:creator>
      <pubDate>Tue, 05 Nov 2024 15:57:48 +0000</pubDate>
      <link>https://dev.to/uwadon1/step-by-step-guide-to-containerize-your-full-stack-mern-application-using-docker-compose-3a8f</link>
      <guid>https://dev.to/uwadon1/step-by-step-guide-to-containerize-your-full-stack-mern-application-using-docker-compose-3a8f</guid>
      <description>&lt;p&gt;Here’s a step-by-step guide to containerize your full-stack MERN application, building each stack component locally first and then moving to Docker Compose.&lt;/p&gt;

&lt;p&gt;Step 1: Clone Your GitHub Repository and Navigate to Local Directories&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone your GitHub repository: Copy your code from your github repository as shown below &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6zz9mv76sbp9rl055pi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6zz9mv76sbp9rl055pi.png" alt="github" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Go to your terminal and run:&lt;br&gt;
&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
   git clone https://github.com/Uwadon1/dockerize-a-mern-stack-app.git&lt;br&gt;
&lt;/code&gt;``&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ru47a3no5d6ie90c1bt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ru47a3no5d6ie90c1bt.png" alt="gitclone" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next you’ll have to move into the newly cloned directory&lt;/p&gt;

&lt;p&gt;cd dockerize-a-mern-stack-app&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Directory structure check: Ensure your project folders has the Frontend/Web-tier, Backend/app-tier and Database. If it has, our final set would most likely look like this, please note because we are deploying our database directly from the backend:
`&lt;code&gt;&lt;/code&gt;
project-directory/
├── frontend/
├── backend/
├── database/
└── docker-compose.yml (this will be created later)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Best Practices: Consider using a .dockerignore file to exclude unnecessary files from the image&lt;/p&gt;

&lt;p&gt;Step 2: Create Dockerfiles for Each Stack Component&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Frontend (React)

&lt;ul&gt;
&lt;li&gt;Navigate to the &lt;code&gt;frontend&lt;/code&gt; folder and create a &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`dockerfile&lt;br&gt;
     # Dockerfile for frontend&lt;/p&gt;

&lt;p&gt;Use the official image as a parent image&lt;br&gt;
Description: Dockerfile for the client side of the MERN stack application&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the official image as a parent image
&lt;/h3&gt;

&lt;p&gt;FROM node:18.9.1&lt;/p&gt;

&lt;h3&gt;
  
  
  Set the working directory
&lt;/h3&gt;

&lt;p&gt;WORKDIR /app&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy the file from your host to your current location
&lt;/h3&gt;

&lt;p&gt;COPY package.json .&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the command inside your image filesystem
&lt;/h3&gt;

&lt;p&gt;RUN npm install&lt;/p&gt;

&lt;h3&gt;
  
  
  Inform Docker that the container is listening on the specified port at runtime
&lt;/h3&gt;

&lt;p&gt;EXPOSE 5173&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy the rest of your app's source code from your host to your image filesystem
&lt;/h3&gt;

&lt;p&gt;COPY . .&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the specified command within the container
&lt;/h3&gt;

&lt;p&gt;CMD ["npm", "run", "dev"]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwd7jrhdi9ylp7laib7uq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwd7jrhdi9ylp7laib7uq.png" alt="Frontend Dockerfile" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explanation: This Dockerfile installs dependencies, builds the frontend code, and uses &lt;code&gt;serve&lt;/code&gt; to host the static files.
Dockerfile Breakdown
This Dockerfile builds a container image for a React frontend application, leveraging the Node.js environment. Let's break down each line:

&lt;ol&gt;
&lt;li&gt;FROM node:18.9.1:
This line specifies the base image for the container. node:18.9.1 indicates that we're using the official Node.js 18.9.1 image as the starting point.&lt;/li&gt;
&lt;li&gt;WORKDIR /app:
This sets the working directory within the container to /app. This is where all subsequent commands will be executed.&lt;/li&gt;
&lt;li&gt;COPY package.json .:
This copies the package.json file from the host machine to the /app directory within the container. This file contains the project's dependencies and configuration.&lt;/li&gt;
&lt;li&gt;RUN npm install:
Executes the npm install command within the container to install all the dependencies listed in the package.json file.&lt;/li&gt;
&lt;li&gt;EXPOSE 5173:
Informs Docker that the container will listen on port 5173. This port is often used by development servers like Create React App.&lt;/li&gt;
&lt;li&gt;COPY . .:
Copies all the remaining files and directories from the host machine to the /app directory within the container. This includes the source code for your React application.&lt;/li&gt;
&lt;li&gt;CMD ["npm", "run", "dev"]:
Specifies the default command to be executed when the container starts. In this case, it runs the dev script defined in the package.json file. This script typically starts the development server for your React app.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building and Running the Image: To build the Docker image, you would use the following command:&lt;br&gt;
Bash&lt;br&gt;
docker build -t mern-frontend .&lt;/p&gt;

&lt;p&gt;This command will create an image named mern-frontend based on the Dockerfile in the current directory. NB: Please ensure your docker desktop is running before you build your docker image.&lt;br&gt;
As shown below, you can see that our front end image has been built successfully&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhfk80xfxbpudgas5osy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhfk80xfxbpudgas5osy.png" alt="Frontend Image Build" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyuj57p6vwdhx3mul6dhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyuj57p6vwdhx3mul6dhx.png" alt="Frontend Dockerdesktop Image Build" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we run, we need to create a network so that our containers can communicate among themselves seamlessly. To create our docker network, we would use:&lt;br&gt;
Bash&lt;br&gt;
docker network create mern&lt;/p&gt;

&lt;p&gt;Next, we will have to run our container, To run our container, we would use:&lt;br&gt;
Bash&lt;br&gt;
docker run --name=frontend --network=mern -d -p 5173:5173 mern-frontend&lt;/p&gt;

&lt;p&gt;This command will start a container based on the mern-frontend image, mapping port 5173 of the container to port 5173 of your host machine. This allows you to access your React app in the browser at &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4bdb4fdmqfkpgy1fs3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4bdb4fdmqfkpgy1fs3q.png" alt="Frontend App" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Backend (Node.js &amp;amp; Express)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is best practice to always start a database container first, to avoid error. &lt;br&gt;
Database (MongoDB)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For MongoDB, you don’t need a Dockerfile, as MongoDB has an official image available on Docker Hub. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run our database container, we would use:&lt;br&gt;
Bash&lt;br&gt;
docker run --name=mongodb --network=mern -d -p 27017:27017 -v ~/opt/data:data/db mongo:latest&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Navigate to the &lt;code&gt;backend&lt;/code&gt; folder and create a &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;dockerfile&lt;br&gt;
 # Dockerfile for backend&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FROM node:18.9.1&lt;/p&gt;

&lt;p&gt;WORKDIR /app&lt;/p&gt;

&lt;p&gt;COPY package.json .&lt;/p&gt;

&lt;p&gt;RUN npm install&lt;/p&gt;

&lt;p&gt;COPY . .&lt;/p&gt;

&lt;p&gt;EXPOSE 5050&lt;/p&gt;

&lt;p&gt;CMD ["npm", "start"]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ofxz9n36o0dso4j4cl1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ofxz9n36o0dso4j4cl1.png" alt="Backend Dockerfile" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explanation: This sets up the backend service to listen on port 5000 and use &lt;code&gt;npm start&lt;/code&gt; to initiate.
Dockerfile Breakdown for the Backend
This Dockerfile is designed to build a container image for a Node.js backend application. Let's break down each line:

&lt;ol&gt;
&lt;li&gt;FROM node:18.9.1:
This line specifies the base image for the container. node:18.9.1 indicates that we're using the official Node.js 18.9.1 image as the starting point.&lt;/li&gt;
&lt;li&gt;WORKDIR /app:
Sets the working directory within the container to /app. This is where all subsequent commands will be executed.&lt;/li&gt;
&lt;li&gt;COPY package.json .:
Copies the package.json file from the host machine to the /app directory within the container. This file contains the project's dependencies and configuration.&lt;/li&gt;
&lt;li&gt;RUN npm install:
Executes the npm install command within the container to install all the dependencies listed in the package.json file.&lt;/li&gt;
&lt;li&gt;COPY . .:
Copies all the remaining files and directories from the host machine to the /app directory within the container. This includes the source code for your Node.js backend application.&lt;/li&gt;
&lt;li&gt;EXPOSE 5050:
Informs Docker that the container will listen on port 5050. This is the port that your Node.js server will be listening on.&lt;/li&gt;
&lt;li&gt;CMD ["npm", "start"]:
Specifies the default command to be executed when the container starts. In this case, it runs the start script defined in the package.json file. This script typically starts your Node.js server.
Building and Running the Image: To build the Docker image, you would use the following command:
Bash
docker build mern-backend .&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This command will create an image named mern-backend based on the Dockerfile in the current directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9tz9wfxjfkc4jwpyqjjs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9tz9wfxjfkc4jwpyqjjs.png" alt="Backend Image Build" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5qn7dlrczu0qnysom51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5qn7dlrczu0qnysom51.png" alt="Backend Image DockerDesktop Build" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run the container, you would use:&lt;br&gt;
Bash&lt;br&gt;
docker run --name=backend --network=mern -d -p 5050:5050 mern-backend&lt;/p&gt;

&lt;p&gt;This command will start a container based on the mern-backend image, mapping port 5050 of the container to port 5050 of your host machine. This allows you to access your Node.js backend application at &lt;a href="http://localhost:5050" rel="noopener noreferrer"&gt;http://localhost:5050&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8q4deerp3nn1i6vlvkh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8q4deerp3nn1i6vlvkh.png" alt="Image description" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Haven built our containers and deployed our MERN stack locally, which really isn’t best practice, I’ll like to show how you can run all the commands in one single file and with just one command.:&lt;br&gt;
Create a &lt;code&gt;docker-compose.yml&lt;/code&gt; File&lt;/p&gt;

&lt;p&gt;In your project root directory, create a &lt;code&gt;docker-compose.yml&lt;/code&gt; to orchestrate all services together.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`yaml&lt;br&gt;
services:&lt;br&gt;
  frontend:&lt;br&gt;
    build: ./mern/frontend&lt;br&gt;
    ports:&lt;br&gt;
      - "5173:5173"&lt;br&gt;&lt;br&gt;
    networks:&lt;br&gt;
      - mern_network&lt;br&gt;
    environment:&lt;br&gt;
      REACT_APP_API_URL: &lt;a href="http://backend:5050" rel="noopener noreferrer"&gt;http://backend:5050&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;backend:&lt;br&gt;
    build: ./mern/backend&lt;br&gt;
    ports:&lt;br&gt;
      - "5050:5050"&lt;br&gt;
    networks:&lt;br&gt;
      - mern_network&lt;br&gt;
    environment:&lt;br&gt;
      MONGO_URI: mongodb://mongo:27017/mydatabase&lt;br&gt;&lt;br&gt;
    depends_on:&lt;br&gt;
      - mongodb&lt;/p&gt;

&lt;p&gt;mongodb:&lt;br&gt;
    image: mongo:latest&lt;br&gt;&lt;br&gt;
    ports:&lt;br&gt;
      - "27017:27017"&lt;br&gt;&lt;br&gt;
    networks:&lt;br&gt;
      - mern_network&lt;br&gt;
    volumes:&lt;br&gt;
      - mongo-data:/data/db  &lt;/p&gt;

&lt;p&gt;networks:&lt;br&gt;
  mern_network:&lt;br&gt;
    driver: bridge&lt;/p&gt;

&lt;p&gt;volumes:&lt;br&gt;
  mongo-data:&lt;br&gt;
    driver: local  # Persist MongoDB data locally&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xrz2f76xgszobv8k2uq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xrz2f76xgszobv8k2uq.png" alt="Docker Compose" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtv97xq3f0zt4igompzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtv97xq3f0zt4igompzd.png" alt="Docker Compose2" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run Docker Compose&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the root project directory, run:
&lt;code&gt;`bash
docker-compose up -d
`&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwo8imrl3ufruuie3718.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwo8imrl3ufruuie3718.png" alt="Docker Compose up" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthi9evbrcr8ff84rl67m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthi9evbrcr8ff84rl67m.png" alt="Docker Compose up2" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This setup should provide a fully functional MERN application running in Docker! &lt;/p&gt;

&lt;p&gt;Let me know if you run into any issues or if you'd like more detail on specific parts of this process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access your services:

&lt;ul&gt;
&lt;li&gt;Frontend: &lt;code&gt;http://localhost:3000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Backend: &lt;code&gt;http://localhost:5000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;MongoDB is accessible to the backend container at &lt;code&gt;database:27017&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verify the Connection Between Services&lt;br&gt;
Confirm that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The frontend can send requests to the backend.&lt;/li&gt;
&lt;li&gt;The backend connects to MongoDB using the &lt;code&gt;MONGO_URI&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manage and Stop Containers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To stop containers, press &lt;code&gt;Ctrl + C&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To stop and remove containers, networks, and volumes created by &lt;code&gt;docker-compose up&lt;/code&gt;, run:
 &lt;code&gt;`bash
 docker-compose down
 `&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Step 3: Cleaning Up Your Docker Environment (Optional)&lt;br&gt;
When you're done working with the application, you can clean up your docker environments, using any of these commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`bash&lt;br&gt;
docker image prune -f&lt;br&gt;
`&lt;/code&gt;&lt;br&gt;
This command removes all unused images.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`bash&lt;br&gt;
docker container prune -f&lt;br&gt;
`&lt;/code&gt;&lt;br&gt;
This command removes all unused containers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`bash&lt;br&gt;
docker network prune -f&lt;br&gt;
`&lt;/code&gt;&lt;br&gt;
This command removes all unused network.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`bash&lt;br&gt;
docker compose down –volumes&lt;br&gt;
`&lt;/code&gt;&lt;br&gt;
This command removes the associated volumes, freeing up disk space.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`bash&lt;br&gt;
docker system prune -f&lt;br&gt;
`&lt;/code&gt;&lt;br&gt;
This command removes all unused resources at once.&lt;/p&gt;

&lt;p&gt;Note: The -f flag forces the removal without prompting for confirmation. Use it with caution, as it will remove resources without confirmation.&lt;br&gt;
By following these steps and using the appropriate commands, you can effectively clean up your Docker environment and keep it organized.&lt;/p&gt;

&lt;p&gt;Additional Considerations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Environment Variables: In production, you should use Docker secrets or environment variable files (&lt;code&gt;.env&lt;/code&gt;) to handle sensitive data like database credentials.&lt;/li&gt;
&lt;li&gt;Scaling: You can scale services (like the backend) by modifying your &lt;code&gt;docker-compose.yml&lt;/code&gt;:
&lt;code&gt;`yaml
backend:
 ...
 deploy:
   replicas: 3
`&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Multi-stage Builds: For more complex setups, consider using multi-stage builds in your Dockerfiles to optimize the size of your Docker images.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusion&lt;br&gt;
By following this guide, you now have a fully Dockerized three-tier web application, with the frontend, backend, and database running in isolated containers, all connected via Docker Compose. You can easily scale, share, and deploy your application using this setup.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
