<?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: Bachar Hakam </title>
    <description>The latest articles on DEV Community by Bachar Hakam  (@astroveny).</description>
    <link>https://dev.to/astroveny</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%2F1037305%2F6b9cab3c-414b-4eba-8048-4ed1adab15d2.png</url>
      <title>DEV Community: Bachar Hakam </title>
      <link>https://dev.to/astroveny</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/astroveny"/>
    <language>en</language>
    <item>
      <title>Kids-friendly project: Building your Chatbot Web Application using LLM</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Tue, 03 Sep 2024 13:53:57 +0000</pubDate>
      <link>https://dev.to/astroveny/kids-friendly-project-building-your-chatbot-web-application-using-llm-4p3m</link>
      <guid>https://dev.to/astroveny/kids-friendly-project-building-your-chatbot-web-application-using-llm-4p3m</guid>
      <description>&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
Stage 1: Prerequisite and Dependencies

&lt;ul&gt;
&lt;li&gt;Create a Github Repository&lt;/li&gt;
&lt;li&gt;Set up your workspace on Gitpod&lt;/li&gt;
&lt;li&gt;OpenAI API Key&lt;/li&gt;
&lt;li&gt;
Integrate with Aider Chat (Optional)

&lt;ul&gt;
&lt;li&gt;Install Aider Chat&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

Stage 2: Create the Chatbot Web Application

&lt;ul&gt;
&lt;li&gt;Web Application Workflow&lt;/li&gt;
&lt;li&gt;Diagram&lt;/li&gt;
&lt;li&gt;1. Setting Up the Environment&lt;/li&gt;
&lt;li&gt;2. Understanding the Structure of a React App&lt;/li&gt;
&lt;li&gt;3. Interact with aider-chat or LLM chatbot&lt;/li&gt;
&lt;li&gt;4. Building the User Interface (UI)&lt;/li&gt;
&lt;li&gt;5. Integrating a Basic Chatbot Logic&lt;/li&gt;
&lt;li&gt;6. Connecting the Chatbot to OpenAI&lt;/li&gt;
&lt;li&gt;7. Testing and Debugging&lt;/li&gt;
&lt;li&gt;8. Enhancing the Chatbot&lt;/li&gt;
&lt;li&gt;9. Final Touches&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: You can follow the steps by yourself but will need your parents' help to set up the project.&lt;br&gt;
&lt;strong&gt;NOTE&lt;/strong&gt;: Here is a &lt;a href="https://github.com/astroveny/kids-chatbot-project" rel="noopener noreferrer"&gt;repository&lt;/a&gt; for your reference. Do not clone it as you have to build it from scratch!&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;This project will help you create a &lt;strong&gt;chatbot web application&lt;/strong&gt; tailored to your needs with the help of &lt;a href="https://chatgpt.com" rel="noopener noreferrer"&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;/a&gt; or any other LLM chatbot.&lt;br&gt;&lt;br&gt;
My son used this project to build his own chatbot, so I thought this would be a fantastic opportunity for others to embark on the same journey of learning through hands-on experience. You may follow the steps exactly or make changes as needed. You do not need to clone any repository or code as you will have to create everything yourself by following the instructions and asking ChatGPT.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What is Coding?&lt;/strong&gt; Think of coding like giving instructions to a computer so it can do cool things, like making a game or building a website!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What’s a Web App?&lt;/strong&gt; A web app is something you use on the internet, like a website, but it can do more interactive things, like letting you chat with a bot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tools We’ll Use:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Github repository:&lt;/strong&gt; This is a code version control where you will save your code. It is like a folder of files&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;VSCode&lt;/strong&gt;: This is like a super cool notebook where you write your instructions (code).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Linux&lt;/strong&gt;: The computer system you’re using. It’s a bit different from Windows or Mac, but perfect for coding.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Gitpod*:&lt;/strong&gt; This has the Linux where you will run VScode. Cloud-based, instant access, and pre-configured workspace. It's like Minecraft world&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ChatGPT&lt;/strong&gt;: Your coding buddy! If you get stuck, you can ask ChatGPT for help.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;We will use &lt;strong&gt;VScode&lt;/strong&gt; workspace running on &lt;a href="https://gitpod.io" rel="noopener noreferrer"&gt;&lt;strong&gt;Gitpod&lt;/strong&gt;&lt;/a&gt; as an IDE, you can use VScode on your local machine but you need to skip steps or change some details related to Gitpod. We will begin by setting up the workspace, preparing the requirements, and installing the dependencies. &lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;* You can run VScode on your machine/PC&lt;/p&gt;
&lt;/blockquote&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%2Fj67qs2w1odt5sfitrzv6.png" class="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%2Fj67qs2w1odt5sfitrzv6.png" alt="Image description" width="751" height="554"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: Prerequisites and Dependencies
&lt;/h2&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;p&gt;We will begin by creating a Github repository to host the code. Then, we'll log in to Gitpod to set up the VSCode workspace and create the necessary requirements and dependencies. In this project, we will utilize Aider-chat as the terminal interface to the LLM to assist in building the application and for creating and updating the code directly. Alternatively, you can use the LLM chatbot at chatgpt.com to copy code back and forth.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Github Repository
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login to Github or create an account if you do not have one.&lt;/li&gt;
&lt;li&gt;Create a new repository &lt;/li&gt;
&lt;li&gt;Click on the repository then on the green "Code" button to copy the repository url&lt;/li&gt;
&lt;li&gt;Copy the Https url which is similar to &lt;code&gt;https://github.com/MyAccount/MyRepo.git&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%2Ffs97g1uh8g9leqee4m0k.png" class="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%2Ffs97g1uh8g9leqee4m0k.png" alt="Image description" width="752" height="404"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Set up your workspace on Gitpod
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login to &lt;a href="https://gitpod.io" rel="noopener noreferrer"&gt;Gitpod&lt;/a&gt; or create an account using the Github account.&lt;/li&gt;
&lt;li&gt;Open a &lt;strong&gt;new workspace&lt;/strong&gt; using the Github repository url you have copied before.&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;.gitignore&lt;/strong&gt; file in the navigation panel &lt;/li&gt;
&lt;li&gt;Run the following command from the terminal
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'node_modules/ \n**/.env'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create &lt;strong&gt;.gitpod.yml&lt;/strong&gt; file then add the following
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tasks:
  - name: init
    before: |
      &lt;span class="nb"&gt;cd &lt;/span&gt;my-chatbot-app 
      npm i
      &lt;span class="nb"&gt;cd&lt;/span&gt; ..
      ./envload
      python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;aider-chat
ports: 
  - name: react 
    port: 3000
    onOpen: open-browser
    visibility: public
&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%2F9g51kw8ztyn3vbucdo6b.png" class="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%2F9g51kw8ztyn3vbucdo6b.png" alt="Image description" width="574" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenAI API Key
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;p&gt;In this step, we will generate an API key from OpenAI. ( you can generate API key from any other LLM)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an OpenAI account if you do not have one.&lt;/li&gt;
&lt;li&gt;login to &lt;a href="https://platform.openai.com/assistants" rel="noopener noreferrer"&gt;OpenAI platform&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;a href="https://platform.openai.com/api-keys" rel="noopener noreferrer"&gt;API keys&lt;/a&gt; on the left-side menu&lt;/li&gt;
&lt;li&gt;Generate a new API key. save this key because you'll need it in the next steps.
&amp;gt;&amp;gt; Note: Keep this API key secure and do not share it publicly.&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;OpenAI API Key&lt;/strong&gt; to the workspace Environment Variables

&lt;ul&gt;
&lt;li&gt;Go back to the Gitpod workspace&lt;/li&gt;
&lt;li&gt;Run the following commands in the terminal:
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_api_key_here"&lt;/span&gt;
gp &lt;span class="nb"&gt;env &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_api_key_here"&lt;/span&gt; &lt;span class="c"&gt;# this will save the API key to Gitpod Environment Variables &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Your workspace is ready, to activate these changes start a new workspace after completing step 2 in the next stage.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Integrate with Aider Chat (Optional)
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aider.chat/" rel="noopener noreferrer"&gt;Aider&lt;/a&gt; is AI pair programming in your terminal. Aider lets you pair program with LLMs, to edit code in your local git repository. Start a new project or work with an existing git repo.&lt;br&gt;&lt;br&gt;
Aider works with most of the well-known LLM models.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Google currently offers &lt;a href="https://makersuite.google.com/app/apikey" rel="noopener noreferrer"&gt;free API access to the Gemini 1.5 Pro model&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Install Aider Chat
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Run the following command inside the root directory of the workspace
&lt;code&gt;python -m pip install aider-chat&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set the LLM API key if you have not set it in the previous steps eg: &lt;code&gt;export OPENAI_API_KEY=&amp;lt;key&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Now you can run &lt;code&gt;aider&lt;/code&gt; inside the terminal to star - Aider uses gpt-4o by default&lt;/li&gt;
&lt;li&gt;You can use &lt;code&gt;aider --model &amp;lt;model-name&amp;gt;&lt;/code&gt; to use any other model. For example, if you want to use a specific version of GPT-4 Turbo you could do &lt;code&gt;aider --model gpt-4-0125-preview&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Example using Google Gemini:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;key&amp;gt; &lt;span class="c"&gt;# Mac/Linux&lt;/span&gt;

aider &lt;span class="nt"&gt;--model&lt;/span&gt; gemini/gemini-1.5-pro-latest

&lt;span class="c"&gt;# List models available from Gemini&lt;/span&gt;
aider &lt;span class="nt"&gt;--models&lt;/span&gt; gemini/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Stage 2: Create the Chatbot Web Application
&lt;/h2&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;p&gt;Use the following steps as a guideline, you can work with ChatGPT to change any step, code or details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web Application Workflow
&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%2Fwjghe7u0e53pv8pzwigo.png" class="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%2Fwjghe7u0e53pv8pzwigo.png" alt="Image description" width="717" height="661"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Diagram
&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%2Fksud5t3gxzqg7l49alo8.png" class="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%2Fksud5t3gxzqg7l49alo8.png" alt="Image description" width="711" height="191"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Setting Up the Environment
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install Node.js and npm&lt;/strong&gt;: These are tools that help us build our app. Imagine Node.js as the engine that makes everything run, and npm is a big toolbox with lots of useful tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Go to the &lt;strong&gt;terminal&lt;/strong&gt; inside &lt;strong&gt;VScode&lt;/strong&gt; (kind of like a text box where you type commands).&lt;/li&gt;
&lt;li&gt;  Type: &lt;code&gt;sudo apt install nodejs npm&lt;/code&gt; and press Enter. This will install Node.js and npm.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Install VSCode Extensions&lt;/strong&gt;: Extensions are like superpowers for VSCode that help you write code more easily.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Go to the &lt;strong&gt;Extensions&lt;/strong&gt; tab (it looks like four squares).&lt;/li&gt;
&lt;li&gt;  Search for “JavaScript” and “React” and click “Install” on the ones you find.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Understanding the Structure of a React App
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a New React App&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  In the &lt;strong&gt;terminal&lt;/strong&gt;, type: &lt;code&gt;npx create-react-app my-chatbot-app&lt;/code&gt; and press Enter. This will create a new project folder with all the files you need.&lt;/li&gt;
&lt;li&gt;  Create envload script at the root directory which will generate &lt;strong&gt;.env&lt;/strong&gt; file inside your working directory &lt;strong&gt;"my-chatbot-app"&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;#! /bin/bash&lt;/span&gt;

  &lt;span class="c"&gt;# Create the environment variable file using the local variable&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"REACT_APP_OPENAI_API_KEY=&lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; my-chatbot-app/.env
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;change the mode of envload by running this command: &lt;code&gt;chmod +x envload&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;run envload: &lt;code&gt;./envload&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Key Files in Your Project&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;index.js&lt;/strong&gt;: This is like the main door to your app. It’s where everything starts.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;App.js&lt;/strong&gt;: Think of this as the brain of your app. It decides what’s shown on the screen.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;public/index.html&lt;/strong&gt;: This is the basic page where your app will appear.&lt;/li&gt;
&lt;/ul&gt;


&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%2Fqo8w3lhy9g8ocrmh10m0.png" class="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%2Fqo8w3lhy9g8ocrmh10m0.png" alt="Image description" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Interact with aider-chat or LLM chatbot
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;p&gt;As mentioned earlier, Aider-Chat will assist you in interacting with the LLM. This will enable you to create and update the code directly within the workspace without having to copy the code from ChatGP or any other LLM chatbot. You also have the option to use the LLM chatbot website to interact with the LLM.&lt;/p&gt;

&lt;p&gt;Start by asking the LLM the questions in the following steps to help you create the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Building the User Interface (UI)
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Run the App&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Let's run the application, type this in the terminal: &lt;code&gt;npm start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gitpod&lt;/strong&gt; will open a link to the app in another window (make sure popup-window is allowed) &lt;/li&gt;
&lt;li&gt;You will not see much, but you can refresh the page as you do changes in the code.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Let's start, make the App Look Cool&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Open App.js in VSCode.&lt;/li&gt;
&lt;li&gt;  Create a simple box where people can type something (this is called an “input”) and a button they can press.&lt;/li&gt;
&lt;li&gt;  Add some color and style using CSS. Imagine you’re decorating a cake – CSS makes your app look yummy!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Clear Out Unnecessary Code: If there’s any default code in App.js, you can remove it to start with a blank slate. Your App.js file should look something like this to start:&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Your code will go here */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create an Input box - Add an Input Element: This is where users will type their messages.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// This is where we store what the user types&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; 
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; 
        &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Type your message here...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Send&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;ul&gt;
&lt;li&gt;
&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input is a state variable that holds the current text in the input box.&lt;/li&gt;
&lt;li&gt;setInput is a function that updates the input value whenever the user types something.&lt;/li&gt;
&lt;li&gt;The onChange event handler listens for changes in the input box and updates the input state.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Add a Button to Send the Message

&lt;ul&gt;
&lt;li&gt;Modify the Button: Add a click event to the button that will handle sending the message.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt; &lt;span class="c1"&gt;// This is where we store all messages&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
      &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Clear the input box after sending the message&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; 
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; 
        &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Type your message here...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSend&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Send&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;ul&gt;
&lt;li&gt;
&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;messages is a state variable that holds an array of all the messages in the conversation.&lt;/li&gt;
&lt;li&gt;handleSend is a function that adds the current message to the messages array and clears the input box.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Display the Conversation History

&lt;ul&gt;
&lt;li&gt;Add a Display Area: We’ll add a section to show the messages that have been sent.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
      &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&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;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chat-box&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`message &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; 
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; 
        &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Type your message here...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSend&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Send&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;ul&gt;
&lt;li&gt;
&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The chat-box div will display each message in the messages array.&lt;/li&gt;
&lt;li&gt;We use map to loop over each message and display it in a div.&lt;/li&gt;
&lt;li&gt;The className allows us to style messages differently based on whether they were sent by the user or the chatbot.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt; Add Some Basic CSS for Styling

&lt;ul&gt;
&lt;li&gt;Style the App: You can add CSS in a file like App.css to make the chat box look nice.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.chat-box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow-y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scroll&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f9f9f9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#d1e7dd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.Bot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f8d7da&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#007bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0056b3&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;ul&gt;
&lt;li&gt;
&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.App centers the app and gives it some padding.&lt;/li&gt;
&lt;li&gt;.chat-box styles the area where the conversation is displayed, with a scroll bar for long conversations.&lt;/li&gt;
&lt;li&gt;.message styles each message bubble, and .User and .Bot give different colors to user and bot messages.&lt;/li&gt;
&lt;li&gt;input[type="text"] and button style the input box and send button to make them look nice and clickable.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Integrating a Basic Chatbot Logic
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Making the Chatbot Talk&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We’ll teach the chatbot to respond to what people type.&lt;/li&gt;
&lt;li&gt;  Use something called “state” in React. State is like a memory for your app, where it can remember what the user typed.&lt;/li&gt;
&lt;li&gt;  ChatGPT can help you write a simple script where the chatbot says something back when you type a message.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understanding State in React&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
In React, "state" is a way to keep track of information in your app that can change over time. For a chatbot, we'll use state to store the conversation history (messages) and the user's input.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setting Up State Variables&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We already have two state variables in place: input for the user's current input and messages for the conversation history. Let's review these:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Stores the current input from the user&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt; &lt;span class="c1"&gt;// Stores all the messages in the conversation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Creating a Function to Handle User Input&lt;/strong&gt;
&amp;gt;&amp;gt; Ask ChatGPT to help you with this step!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the user types a message and hits the "Send" button (or presses Enter), we need to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add the User's Message to the Conversation: We'll add the user's message to the messages array.
Generate a Chatbot Response: We'll simulate a chatbot response by adding another message to the messages array.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Creating a Simple Chatbot Response Function&lt;/strong&gt;
Now, let’s create a basic function that simulates a chatbot response. This function can be as simple or complex as you like. For now, we'll keep it simple by making the bot respond with a predefined set of responses based on certain keywords.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateBotResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lowercasedInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lowercasedInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hi there! How can I help you today?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lowercasedInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;how are you&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm just a bot, but I'm doing great! Thanks for asking.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lowercasedInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bye&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Goodbye! Have a great day!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm not sure how to respond to that. Can you ask me something else?&lt;/span&gt;&lt;span class="dl"&gt;"&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;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Explanation of the Chatbot Logic:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;handleSend Function:&lt;/li&gt;
&lt;li&gt;Checks if the input is not empty.&lt;/li&gt;
&lt;li&gt;Adds the user's message to the messages array.&lt;/li&gt;
&lt;li&gt;Generates a response from the bot using generateBotResponse.&lt;/li&gt;
&lt;li&gt;Updates the messages array to include the bot's response.&lt;/li&gt;
&lt;li&gt;Clears the input field.&lt;/li&gt;
&lt;li&gt;generateBotResponse Function:&lt;/li&gt;
&lt;li&gt;Takes the user's input and checks for specific keywords.&lt;/li&gt;
&lt;li&gt;Returns a response based on the keyword found (e.g., "hello", "how are you", "bye").&lt;/li&gt;
&lt;li&gt;If no keyword is matched, it returns a default response.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Connecting the Chatbot to OpenAI
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chatting with ChatGPT&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You’ll learn how to send what you type to OpenAI and get a response back. This is called calling an API (which is just a way to talk to other computers).&lt;/li&gt;
&lt;li&gt;  ChatGPT will help you write this part. You’ll type something in the chatbox, and OpenAI will answer, just like ChatGPT!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Up an API Key&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
React should be able to load the API key saved as REACT_APP_OPENAI_API_KEY in the .env file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install Axios for API Requests&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We'll use Axios, a popular JavaScript library, to make HTTP requests to the ChatGPT API. You can install it using npm:&lt;br&gt;
&lt;code&gt;npm install axios&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set Up the API Call in Your React App&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Now, let's modify the handleSend function to send the user's input to OpenAI and receive a response.&lt;/p&gt;

&lt;p&gt;Here’s how to do it:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Import Axios at the top of your App.js:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&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;- Modify the handleSend Function to include the API call, update the code as required:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="c1"&gt;// Call the ChatGPT API&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.openai.com/v1/chat/completions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Use "gpt-3.5-turbo" if you have access to GPT-4&lt;/span&gt;
        &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// OpenAI API key&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explanation of the API Call&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Endpoint&lt;/strong&gt;: We are sending a POST request to &lt;a href="https://api.openai.com/v1/chat/completions" rel="noopener noreferrer"&gt;https://api.openai.com/v1/chat/completions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt;: The model parameter specifies which version of GPT you are using. You can use "gpt-3.5-turbo" or "gpt-4o-mini" depending on your access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messages&lt;/strong&gt;: This contains the conversation history, with the user’s latest input being sent to the API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt;: The request headers include the - Authorization header with your API key and specify that the content is JSON.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bot Response&lt;/strong&gt;: Once the API responds, we extract the content of the bot’s response and add it to the messages array.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Testing and Debugging
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Test Your Chatbot&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Run your app by typing &lt;code&gt;npm start&lt;/code&gt; in the terminal.&lt;/li&gt;
&lt;li&gt;  Try typing different things in the chatbox to see how it works.&lt;/li&gt;
&lt;li&gt;  If something doesn’t work, don’t worry! Debugging is like solving a mystery. You’ll look for clues (called “errors”) in the console and figure out how to fix them.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. Enhancing the Chatbot
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add More Fun Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Want your chatbot to do more? Maybe show a spinning wheel while it’s thinking or keep a history of the conversation.&lt;/li&gt;
&lt;li&gt;  Ask ChatGPT for help with these ideas. You can keep adding new things to make your chatbot cooler!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  9. Final Touches
&lt;/h3&gt;

&lt;p&gt;Back to ToC&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Polish Your App&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Clean up any messy code, and make sure everything looks just right.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In the next blog post, we will guide you through the steps to deploy the web application on the cloud so you can access it from anywhere.&lt;/p&gt;

</description>
      <category>genai</category>
      <category>coding</category>
      <category>openai</category>
      <category>google</category>
    </item>
    <item>
      <title>Deploying Your App with AWS CloudFormation and CodePipeline - A Comprehensive Guide</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Wed, 03 Jan 2024 15:59:31 +0000</pubDate>
      <link>https://dev.to/aws-builders/deploying-your-app-with-aws-cloudformation-and-codepipeline-eea</link>
      <guid>https://dev.to/aws-builders/deploying-your-app-with-aws-cloudformation-and-codepipeline-eea</guid>
      <description>&lt;p&gt;I wrote a blog post earlier on &lt;a href="https://dev.to/aws-builders/how-to-build-and-deploy-an-api-driven-streamlitpython-microservice-on-aws-3bkj"&gt;how to create and deploy a containerized API-driven Python Streamlit web app using CICD on AWS&lt;/a&gt;. Although the steps I explained using ClickOps "AWS Console" were beginner-friendly, it's best to use a more automated method that's less prone to errors during production or big-scale development stages. That's where Infrastructure as a Code (IaC) comes in.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Infrastructure as Code (IaC)?
&lt;/h2&gt;

&lt;p&gt;IaC refers to the process of managing and provisioning infrastructure through code instead of manual processes. The main benefit of IaC is that it automates the creation and management of infrastructure environments, so developers can focus on building and enhancing applications. This approach helps to control costs, reduce risks, and accelerate the process.&lt;/p&gt;

&lt;p&gt;Another advantage of IaC is that it allows you to replicate the same environment and deploy it in another location using the same code. By designing the IaC in a modular way, it can be used anywhere with fewer restrictions, making deployment more agile. The more you design the IaC to be modular, the more agile the deployment will be.&lt;/p&gt;

&lt;p&gt;IaC is commonly used in software development to build, test, and deploy applications. &lt;/p&gt;

&lt;p&gt;In this article, we will explore a similar concept. I will explain the steps required to build and deploy the same environment and Web App "Streamlit Web App" used in the previous article, using &lt;a href="https://aws.amazon.com/cloudformation/" rel="noopener noreferrer"&gt;AWS CloudFormation&lt;/a&gt; stacks and &lt;a href="https://aws.amazon.com/codepipeline/" rel="noopener noreferrer"&gt;CodePipeline&lt;/a&gt; while increasing the Web App's scalability. &lt;/p&gt;

&lt;p&gt;In my next blog post, I will demonstrate how to utilize this setup to integrate your web app with a GenAI model deployed using Amazon SageMaker JumpStart. &lt;/p&gt;







&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;To begin with, we will create two ECR repositories. The first one will store the base image, while the second will store the web app image. We will then pull the base-image from Docker Hub and push it to the appropriate ECR repository. In this demo, we used the python:3.10-slim-buster as the base-image.  You may follow the steps &lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/guide/Step1-ECR-Repo-Base-Image.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, we need to prepare the content of the GitHub repository. This involves adding the source code, deployment scripts, definition files (such as Dockerfile, buildspec.yml, and appspec.yml), the "cfn" directory that contains all Cloudformation stacks, and the bin directory that contains all bash scripts to deploy the stacks. You can take a look at this &lt;a href="https://github.com/astroveny/WebApp-Iac-CICD" rel="noopener noreferrer"&gt;repository sample&lt;/a&gt; to get an idea of how it should be structured. Each stack will have AWS resources with similar lifecycles and ownership.&lt;/p&gt;

&lt;p&gt;After creating the repository, create a folder for each stack that contains a template.yaml file and parameters.json to define parameter values. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── cfn
│   ├── compute
│   │   ├── parameters.json
│   │   └── template.yaml
│   ├── cdn
│   │   ├── parameters.json
│   │   └── template.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we will create a deployment script for each stack inside the &lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/tree/main/bin" rel="noopener noreferrer"&gt;bin directory&lt;/a&gt; and then deploy them in a specific order.&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%2Fgi0lyjncl3j56ht4qnlx.png" class="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%2Fgi0lyjncl3j56ht4qnlx.png" title="GitHub Repository" alt="GitHub Repository" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While deploying directly to EC2 instances can be suitable for development, testing, or small-scale applications, for production environments, it's generally best to use container orchestration services like ECS or EKS for improved scalability, reliability, and maintainability.&lt;br&gt;&lt;br&gt;
We can discuss how to create a similar environment using either ECS or EKS, but we'll save that for another blog post. The benefit of this setup is that during the development or testing phases, you can deploy a different container using the same resources created by the stacks. You can use the same repository or another one, and you would only need to make a few changes such as updating the allowed ports by the Security Groups, Dockerfile, and the base image.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Now that the structure of the environment is in place, we can proceed to building the stacks.&lt;/p&gt;







&lt;h2&gt;
  
  
  Building The Stacks
&lt;/h2&gt;

&lt;p&gt;We will create the necessary files for each stack, go through the configuration of the resources in each stack then develop the deployment scripts. You can clone the &lt;a href="https://github.com/astroveny/WebApp-Iac-CICD" rel="noopener noreferrer"&gt;repository sample&lt;/a&gt; and update the files to suit your setup. In general, we will start the template by defining the parameters for each resource and use an external parameter file named parameters.json. Next, is the resource section, which will contain the configuration details of each resource. Finally, we will use the output sections to export the resource values that will be used in other stacks.&lt;/p&gt;

&lt;p&gt;Before we proceed to the next steps, take a look at the solution diagram&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%2Fskmldcv6nxzeb4bbipyu.gif" class="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%2Fskmldcv6nxzeb4bbipyu.gif" title="Solution architect" alt="Solution architect" width="716" height="748"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we will start with the Networking stack to lay down the necessary network resources, next is the ALB stack to distribute the traffic to the Web App instances, then the Compute stack and the CDN stack. &lt;br&gt;
Here is a high-level diagram of each stack and the cross-stack references.&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%2Fnajrr3s8v9umxutv1wfo.png" class="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%2Fnajrr3s8v9umxutv1wfo.png" title="AWS CloudFormation Stacks" alt="AWS CloudFormation Stacks" width="606" height="402"&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%2Fcdbsqbmxpwwhe8wfwixt.png" class="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%2Fcdbsqbmxpwwhe8wfwixt.png" title="AWS CloudFormation CICD Stacks" alt="AWS CloudFormation CICD Stacks" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Networking Stack
&lt;/h3&gt;

&lt;p&gt;The Networking stack will create the base networking resources necessary for this environment. This will include the VPC that has an Internet Gateway, Route Table, two Availability Zones for redundancy, and one public subnet per Availability Zone.&lt;br&gt;
To build the stack, create a Cloudformation template file inside the &lt;code&gt;cfn/networking&lt;/code&gt; directory similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/networking/template.yaml" rel="noopener noreferrer"&gt;template.yaml&lt;/a&gt;) file. &lt;/p&gt;

&lt;p&gt;The template description includes a list of the resources that will be generated by it.&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;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;Networking stack Resources:&lt;/span&gt;
  &lt;span class="s"&gt;- VPC&lt;/span&gt;
  &lt;span class="s"&gt;- IGW&lt;/span&gt;
  &lt;span class="s"&gt;- Availability Zone&lt;/span&gt;
  &lt;span class="s"&gt;- Public Route Table&lt;/span&gt;
    &lt;span class="s"&gt;- route to the IGW&lt;/span&gt;
    &lt;span class="s"&gt;- route to Local&lt;/span&gt;
  &lt;span class="s"&gt;- 2 Public Subnets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the resources:&lt;/p&gt;

&lt;h2&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%2Fyebcixi2ex3s5gkk6myi.png" title="AWS VPC Resources" alt="AWS VPC Resources" width="383" height="323"&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2. ALB Stack
&lt;/h3&gt;

&lt;p&gt;The ALB stack will create an Application Load Balancer to decouple the traffic from the Web App and distribute the traffic load across the Web App instances. Additionally, it includes a Target Group that specifies the target instances, and the ALB Security Group manages the traffic security. Create a CloudFormation template file inside the &lt;code&gt;cfn/alb&lt;/code&gt; directory similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/alb/template.yaml" rel="noopener noreferrer"&gt;template.yaml&lt;/a&gt;).  &lt;/p&gt;

&lt;p&gt;The template description includes a list of the resources that will be generated by it.&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;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;WebApp ALB Stack:&lt;/span&gt;
  &lt;span class="s"&gt;- ALB&lt;/span&gt;
    &lt;span class="s"&gt;- ipv4&lt;/span&gt;
    &lt;span class="s"&gt;- Internet facing&lt;/span&gt;
    &lt;span class="s"&gt;- certificate attached from Amazon Certification Manager (ACM)&lt;/span&gt;
  &lt;span class="s"&gt;- HTTPSListener&lt;/span&gt;
    &lt;span class="s"&gt;- HTTPS to WebApp Target Group&lt;/span&gt;
  &lt;span class="s"&gt;- Target Group&lt;/span&gt;
  &lt;span class="s"&gt;- ALB Security Groups&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going forward we will use an external parameters file (parameters.json) to define some parameters, so you will have to create it in the same directory similar to this ALB stack parameter file(&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/alb/parameters.json" rel="noopener noreferrer"&gt;parameters.json&lt;/a&gt;) file.&lt;br&gt;&lt;br&gt;
Update the values for each of the following ParameterKey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebAppPort "The port your Web App will use"&lt;/li&gt;
&lt;li&gt;CertificateArn "ACM certificate Arn"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the resources:&lt;/p&gt;
&lt;h2&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%2Feh6mpfvogkvn21arpybf.png" title="AWS ALB Resources" alt="AWS ALB Resources" width="800" height="268"&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  3. Compute Stack
&lt;/h3&gt;

&lt;p&gt;In the Compute stack, we will create an IAM Role, Launch Template, and an Auto Scaling Group. These will define the EC2 instance configurations and types, as well as the scalability capacity required for the Web App. Additionally, we will create a Security Group that will allow the required traffic.&lt;/p&gt;

&lt;p&gt;Create a template file inside the &lt;code&gt;cfn/compute&lt;/code&gt; directory similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/compute/template.yaml" rel="noopener noreferrer"&gt;template.yaml&lt;/a&gt;) file.  &lt;/p&gt;

&lt;p&gt;The template description includes a list of the resources that will be generated by it.&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;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;WebApp Compute Stack:&lt;/span&gt;
  &lt;span class="s"&gt;- Launch Template&lt;/span&gt;
  &lt;span class="s"&gt;- LT Security Group&lt;/span&gt;
  &lt;span class="s"&gt;- ASG&lt;/span&gt;
  &lt;span class="s"&gt;- IAM Role and Policies&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the Compute stack parameters file inside the same directory, similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/compute/parameters.json" rel="noopener noreferrer"&gt;parameters.json&lt;/a&gt;)file&lt;/p&gt;

&lt;p&gt;The content of the user-data can be changed by encoding the new file using base64 &lt;code&gt;base64 user-data&lt;/code&gt; and updating the parameters.json file with the new value.&lt;/p&gt;

&lt;p&gt;Here are the resources:&lt;/p&gt;

&lt;h2&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%2Fhk9wklow48lmesurkrkb.png" title="AWS Compute Resources" alt="AWS Compute Resources" width="800" height="180"&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4. CDN Stack
&lt;/h3&gt;

&lt;p&gt;In this stack, we will create a CloudFront Distribution with an ALB origin. Assuming that you have already a Domain Name registered in the Route 53 hosted zone, we will create a record to publish the distribution URL for the Web App.&lt;/p&gt;

&lt;p&gt;Create a template file inside the &lt;code&gt;cfn/cdn&lt;/code&gt; directory similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/cdn/template.yaml" rel="noopener noreferrer"&gt;template.yaml&lt;/a&gt;) file.  &lt;/p&gt;

&lt;p&gt;The template description includes a list of the resources that will be generated by it.&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;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;CDN Stack:&lt;/span&gt;
  &lt;span class="s"&gt;- CloudFront Distribution&lt;/span&gt;
  &lt;span class="s"&gt;- Route 53 Hosted Zone Record&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will create the parameters file inside the same directory, similar to this &lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/cdn/parameters.json" rel="noopener noreferrer"&gt;parameters.json&lt;/a&gt; file.&lt;br&gt;&lt;br&gt;
Update the values for each of the following ParameterKey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DomainName&lt;/li&gt;
&lt;li&gt;HostedZoneRecord&lt;/li&gt;
&lt;li&gt;DomainHostedZoneId&lt;/li&gt;
&lt;li&gt;CustomDomainName&lt;/li&gt;
&lt;li&gt;CertificateArn&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  5. CICD Stack
&lt;/h3&gt;

&lt;p&gt;Lastly, we will create a CodePipeline Stack and two nested stacks to create and set up CodeBuild and CodeDeploy. The pipeline will build and then deploy the container image as you update the Web app code inside the GitHub repository. &lt;/p&gt;

&lt;p&gt;First, we need to create a pipeline artifact bucket that will be defined as a parameter. Run the following aws cli to create the bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3api create-bucket &lt;span class="nt"&gt;--bucket&lt;/span&gt; codepipeline-webapp-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d%H%M%S&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, create the main pipeline template file inside the &lt;code&gt;cfn/cicd&lt;/code&gt; directory. The file should be similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/cicd/template.yaml" rel="noopener noreferrer"&gt;template.yaml&lt;/a&gt;) file.  &lt;/p&gt;

&lt;p&gt;The template description includes a list of the resources that will be generated by it.&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;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;WebApp CICD Stack:&lt;/span&gt;
  &lt;span class="s"&gt;- CodePipeline IAM Role&lt;/span&gt;
  &lt;span class="s"&gt;- CodeDeploy IAM Role&lt;/span&gt;
  &lt;span class="s"&gt;- Web App Pipeline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be able to connect to the GitHub repository, we need first to create a CodeStar connection with the GitHub account. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the following command to create a new CodeStar connection:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws codestar-connections create-connection &lt;span class="nt"&gt;--provider-type&lt;/span&gt; GitHub &lt;span class="nt"&gt;--connection-name&lt;/span&gt; MyGitHubConnection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;make sure the repo is public otherwise you need to allow access to the private repo on GitHub&lt;/li&gt;
&lt;li&gt;Go to the AWS CodePipeline console&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Settings&lt;/strong&gt; on from the left-side panel then click on &lt;strong&gt;Connections&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select the connection name "MyGitHubConnection"&lt;/li&gt;
&lt;li&gt;Then click on "&lt;strong&gt;Update pending connection&lt;/strong&gt;"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, we will create the parameters file inside the same directory, similar to this &lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/cicd/parameters.json" rel="noopener noreferrer"&gt;parameters.json&lt;/a&gt; file.&lt;br&gt;&lt;br&gt;
Update the values for each of the following ParameterKey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHubConnectionArn&lt;/li&gt;
&lt;li&gt;GitHubRepo&lt;/li&gt;
&lt;li&gt;GitHubBranch&lt;/li&gt;
&lt;li&gt;GitHubSourceRepo&lt;/li&gt;
&lt;li&gt;ArtifactBucketName&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the 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%2Fi2kozl0f2016mmm0yb4f.png" class="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%2Fi2kozl0f2016mmm0yb4f.png" title="AWS CICD Resources" alt="AWS CICD Resources" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  5.1 CodeBuild Stack
&lt;/h4&gt;

&lt;p&gt;The CodeBuild stack will create a CodeBuild project and the necessary IAM Role to build the container image and then push it to the ECR repository &lt;/p&gt;

&lt;p&gt;Create a template file inside the &lt;code&gt;cfn/cicd/nested&lt;/code&gt; directory similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/cicd/nested/codebuild.yaml" rel="noopener noreferrer"&gt;codebuild.yaml&lt;/a&gt;) file.  &lt;/p&gt;

&lt;p&gt;The template description includes a list of the resources that will be generated by it.&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;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;AWS CodeBuild Project as part of the CICDStack:&lt;/span&gt;
  &lt;span class="s"&gt;- CodeBuild Service Role&lt;/span&gt;
  &lt;span class="s"&gt;- CodeBuild Project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5.2 CodeDeploy Stack
&lt;/h4&gt;

&lt;p&gt;This Stack will create CodeDeploy Application and Deployment Group to deploy the Web app Container. For this demo purposes, we will use (in-place deployment), but it is recommended to create a Blue/Green deployment with multiple compute resources to ensure the availability of the Web App.&lt;/p&gt;

&lt;p&gt;Create a template file inside the &lt;code&gt;cfn/cicd/nested&lt;/code&gt; directory similar to this (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/cfn/cicd/nested/codedeploy.yaml" rel="noopener noreferrer"&gt;codedeploy.yaml&lt;/a&gt;) file.  &lt;/p&gt;

&lt;p&gt;The template description includes a list of the resources that will be generated by it.&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;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;- AWS CodeDeploy Application&lt;/span&gt;
  &lt;span class="s"&gt;- Deployment Group&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deployment Scripts
&lt;/h2&gt;

&lt;p&gt;At this stage we will create the bash deployment script for each stack, we will follow the same order we used to create the stacks by starting with the networking deployment script and so on.&lt;/p&gt;

&lt;p&gt;You will have to define the following variables inside each script:&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="nv"&gt;BUCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="c"&gt;# Cloudformation bucket&lt;/span&gt;
&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt; &lt;span class="c"&gt;# replace with the relevant region&lt;/span&gt;
&lt;span class="nv"&gt;STACK_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: if you change the STACK_NAME then you have to change the relevant stack name example: "NetworkingStack" value, in  parameters.json of the other stacks.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;If you do not have an existing Cloudformation artifact bucket, create a new one using the following aws cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3api create-bucket &lt;span class="nt"&gt;--bucket&lt;/span&gt; cfn-artifact-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d%H%M%S&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we start, we need to install the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/aws-cloudformation/cfn-lint" rel="noopener noreferrer"&gt;AWS CloudFormation Linter&lt;/a&gt; Validate the syntax and properties of resources by running cfn-lint with each template.yaml file. &lt;/li&gt;
&lt;li&gt;Install JQ (JSON Processor) to transform the structure of the parameters.json into key=value structure. We will use jq tool inside the deployment scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Networking Stack Deployment Script
&lt;/h3&gt;

&lt;p&gt;Create a bash file inside the bin directory similar to (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/bin/networking-deploy" rel="noopener noreferrer"&gt;networking-deploy&lt;/a&gt;).&lt;br&gt;
The script will deploy the Networking Stack. &lt;/p&gt;

&lt;h3&gt;
  
  
  ALB Stack Deployment Script
&lt;/h3&gt;

&lt;p&gt;Create a bash file inside the bin directory similar to (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/bin/alb-deploy" rel="noopener noreferrer"&gt;alb-deploy&lt;/a&gt;). This script will deploy the ALB Stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compute Stack Deployment Script
&lt;/h3&gt;

&lt;p&gt;Create a bash file inside the bin directory similar to (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/bin/compute-deploy" rel="noopener noreferrer"&gt;compute-deploy&lt;/a&gt;). This script will deploy the Compute Stack&lt;/p&gt;

&lt;h3&gt;
  
  
  CDN Stack Deployment Script
&lt;/h3&gt;

&lt;p&gt;Create a bash file inside the bin directory similar to (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/bin/cdn-deploy" rel="noopener noreferrer"&gt;cdn-deploy&lt;/a&gt;). This script will deploy the CDN Stack&lt;/p&gt;

&lt;h3&gt;
  
  
  CICD Stack Deployment Script
&lt;/h3&gt;

&lt;p&gt;Create a bash file inside the bin directory similar to (&lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/bin/cicd-deploy" rel="noopener noreferrer"&gt;cicd-deploy&lt;/a&gt;). This script will deploy the CICD Stack&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Build The Container Image
&lt;/h3&gt;

&lt;p&gt;Although CodeBuild can be used to build the first version of the Web App image, the build project stack needs to be created outside the pipeline.&lt;br&gt;
For now, we will just build the image using docker locally and then push it to the ECR repository. &lt;a href="https://github.com/astroveny/WebApp-Iac-CICD/blob/main/guide/Step2-Build-WebApp-Image.md" rel="noopener noreferrer"&gt;Here is an example&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's Recap
&lt;/h3&gt;

&lt;p&gt;We have stored the base-image and Web App image in the appropriate ECR repository. The definition files are ready and located in the root directory. The stack's templates and parameters files are in their corresponding stack folder, and all deployment scripts are available in the bin directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stacks Deployment
&lt;/h3&gt;

&lt;p&gt;We will walk through the steps required to deploy each stack in the right order. Starting with the Networking stack, that will create the necessary networking resources. Next, is the ALB stack which will create the ALB for the EC2 instances. After that, we will deploy the Compute stack to create the EC2 instances. Then, we will deploy the CDN stack which will create a CloudFront distribution and add it to the Route 53 host zone record. Finally, we will deploy the CICD stack which will create the pipeline to build and deploy future changes in the code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Stacks Deployment Order
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Networking Stack: networking-deploy&lt;/li&gt;
&lt;li&gt;ALB Stack: alb-deploy&lt;/li&gt;
&lt;li&gt;Compute Stack: compute-deploy&lt;/li&gt;
&lt;li&gt;CDN Stack: cdn-deploy&lt;/li&gt;
&lt;li&gt;CICD Stack: cicd-deploy
&amp;gt;&amp;gt; Note: Make sure all scripts inside the bin directory are executable &lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Go to bin directory then run the first script &lt;code&gt;./networking-deploy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy the ARN from the output, similar to this
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Waiting &lt;span class="k"&gt;for &lt;/span&gt;changeset to be created..
Changeset created successfully. Run the following &lt;span class="nb"&gt;command &lt;/span&gt;to review changes:
aws cloudformation describe-change-set &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; arn:aws:cloudformation:us-east-1:XXXXXXXXXXXX:changeSet/awscli-cloudformation-package-deploy-XXXXXXXXXX/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To execute the change set, run the command below with the ARN you copied.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudformation execute-change-set &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; arn:aws:cloudformation:us-east-1:XXXXXXXXXXXX:changeSet/awscli-cloudformation-package-deploy-XXXXXXXXXX/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Go to the AWS Cloudformation console &lt;/li&gt;
&lt;li&gt;Select the stack name and then &lt;strong&gt;Event&lt;/strong&gt; tab to check the status of the stack&lt;/li&gt;
&lt;li&gt;Once the status changes to "CREATE_COMPLETE", go to the next step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repeat the above steps for the rest of the stack in the right order using the relevant script. Once all stacks are deployed successfully, try to access the Web App using the domain name you used in the CDN stack.&lt;/p&gt;

</description>
      <category>infrastructureascode</category>
      <category>cicd</category>
      <category>aws</category>
      <category>containers</category>
    </item>
    <item>
      <title>How to Build and Deploy an API-Driven Streamlit Python Microservice on AWS</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Wed, 25 Oct 2023 05:29:02 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-to-build-and-deploy-an-api-driven-streamlitpython-microservice-on-aws-3bkj</link>
      <guid>https://dev.to/aws-builders/how-to-build-and-deploy-an-api-driven-streamlitpython-microservice-on-aws-3bkj</guid>
      <description>&lt;p&gt;I wanted a feature that did not exist in the trading platform I'm using, so I built it as a Web App API-based microservice. To achieve this, I first read through the platform API documentation to gather the necessary parameters. &lt;/p&gt;

&lt;p&gt;I then started building the application by creating a CLI version using Python. To ensure that each API parameter was functional, I tested them separately in a demo environment, followed by testing the entire application in a pre-production environment. &lt;/p&gt;

&lt;p&gt;Recently, I came across several AI workshops that utilized the Streamlit framework for building plotting applications in a simple manner. Given the ease of use of Streamlit, I decided to build the trading web app version using Sreamlit as a microservice.&lt;/p&gt;

&lt;p&gt;In this scenario, the communication between the frontend and the backend is through the API, the frontend is the Web App and the backend is the trading platform.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Streamlit App
&lt;/h3&gt;

&lt;p&gt;Streamlit is an open-source app framework written in Python. It is similar to Flask and is used for creating simple web applications quickly and easily. While it is commonly used for projects related to Machine Learning and Data Science, it works perfectly with major Python libraries and can include HTML code or markdown, making it an excellent choice for building simple applications. &lt;br&gt;
As a beginner to Streamlit, I used GenAI to convert my Python code to Streamlit code. It didn't take long for me to create a functional web app. I then tested and refactored the app until I reached the final version.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the Microservice
&lt;/h2&gt;

&lt;p&gt;During the preparation phase of building the web app microservice, I first created an ECR repository named 'webapp-base-image' to store the container base-image. Then, I pushed the Docker base-image (python:3.10-slim-buster) to it. Next, I created another ECR repository to store the Web App container image. &lt;/p&gt;

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

&lt;p&gt;After that, I created a GitHub repository and pushed the source code and artifacts to the repository directory. Then, I created the Dockerfile required to build the Web App container.  Finally, to build the CICD pipeline using CodePipeline, I created 'buildspec.yml' for CodeBuild and 'appspec.yml' for CodeDeploy.&lt;/p&gt;

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

&lt;p&gt;It's important to note that the usage and content of these files would vary depending on the chosen computing service.&lt;/p&gt;

&lt;p&gt;The following are the available compute options on AWS to deploy the container, each would require a different procedure and minor configuration changes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS App Runner (the fastest option, but limits infrastructure control) &lt;/li&gt;
&lt;li&gt;Fargate (Serverless container service) &lt;/li&gt;
&lt;li&gt;EC2 instance (Compute service with more control, but requires OS/Apps maintenance)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the source code, artifacts, and configuration files were added to the web app repo, the container image was ready for deployment. I deployed the container on a free-tier EC2 instance as explained in the next phase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources Creation
&lt;/h3&gt;

&lt;p&gt;To build and deploy the Web App, I first created the necessary resources using an EC2 instance as the host, an Application Load Balancer to decouple the TLS connection from the EC2 instance and provide load balancing for future scaling, a Build project to package and build the container using CodeBuild, CodeDeploy application to deploy the container on the EC2 instance, and finally CodePipeline to run the CICD pipeline.&lt;/p&gt;

&lt;p&gt;Afterward, I created the remaining resources that are needed to access the Web App via the Internet, including the CloudFront distribution and a Route 53 hosted zone record.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://dev.to/aws-builders/deploying-your-app-with-aws-cloudformation-and-codepipeline-eea"&gt;In an upcoming blog post&lt;/a&gt;, I will explain how to optimize this solution to improve scalability and make it more cost-effective using IaC.&lt;/p&gt;

&lt;p&gt;Next, are the steps required to implement this solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;We will go through the steps required to build and deploy the Web App container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an Amazon Elastic Container Registry and Base-Image.
&lt;/h3&gt;

&lt;p&gt;First, we will create an ECR repository to store the base-image, pull the image from Docker Hub, then push it to the ECR repository.&lt;br&gt;
After that, we will create another ECR repository to store the Web App container image.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1a: Create an ECR repository for the Base-image
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Run the following aws command to create the ECR repository:&lt;/li&gt;
&lt;/ul&gt;

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

aws ecr create-repository &lt;span class="nt"&gt;--repository-name&lt;/span&gt; webapp-base-image &lt;span class="nt"&gt;--image-tag-mutability&lt;/span&gt; MUTABLE


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Step 1b: Create the Base-Image
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Set the Env variable on your machine
```bash
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;export AWS_ACCOUNT_ID=YourAWS-ID&lt;br&gt;
  export AWS_DEFAULT_REGION=AWS-Region&lt;br&gt;
  export ECR_PYTHON_URL="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/webapp-base-image"&lt;/p&gt;


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

  ```bash


  aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com"


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Pull the image from Docker Hub&lt;/li&gt;
&lt;/ul&gt;

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

  docker pull python:3.10-slim-buster


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Tag the image&lt;/li&gt;
&lt;/ul&gt;

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

  docker tag python:3.10-slim-buster &lt;span class="nv"&gt;$ECR_PYTHON_URL&lt;/span&gt;:3.10-slim-buster


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Push the image to ECR repository&lt;/li&gt;
&lt;/ul&gt;

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

  docker push &lt;span class="nv"&gt;$ECR_PYTHON_URL&lt;/span&gt;:3.10-slim-buster


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Step 1c: Create ECR repository for the Web App Container Image
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Run the following aws command to create the ECR repository:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws ecr create-repository &lt;span class="nt"&gt;--repository-name&lt;/span&gt; webapp &lt;span class="nt"&gt;--image-tag-mutability&lt;/span&gt; MUTABLE


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

&lt;/div&gt;




&lt;h3&gt;
  
  
  Step 2: Create a GitHub repository.
&lt;/h3&gt;

&lt;p&gt;We will need to &lt;a href="https://docs.github.com/en/get-started/quickstart/create-a-repo" rel="noopener noreferrer"&gt;create a new GitHub repository&lt;/a&gt; for the Web App. Once done, you can clone the repository on the local machine and move the source code and artifacts to the root directory of the repository. &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2a: Create Python requirements.txt
&lt;/h4&gt;

&lt;p&gt;Next, you need to create the Python requirements.txt file which will include &lt;strong&gt;streamlit&lt;/strong&gt; and other required packages and libraries for your Web App. &lt;/p&gt;


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

&lt;p&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;requirements.txt&lt;br&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'streamlit'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; requirements.txt&lt;/p&gt;

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

&lt;/div&gt;
&lt;h4&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Step 2b: Create Dockerfile&lt;br&gt;
&lt;/h4&gt;

&lt;p&gt;Then create a Dockerfile similar to the following&lt;/p&gt;


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

&lt;p&gt;&lt;span class="c"&gt;# app/Dockerfile&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;# use the ECR repo base-image link&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; [YourAccountID].dkr.ecr.[YourRegion].amazonaws.com/[ECR-repo-base-image]:3.10-slim-buster&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt requirements.txt&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;\&lt;br&gt;
&lt;/span&gt;    apt-get update &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;\&lt;br&gt;
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install &lt;/span&gt;curl &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8501&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;HEALTHCHECK&lt;/span&gt;&lt;span class="s"&gt; CMD curl --fail &lt;a href="http://localhost:8501/_stcore/health" rel="noopener noreferrer"&gt;http://localhost:8501/_stcore/health&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;# replace YourWebApp.py with the relevant file name&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["streamlit", "run", "YourWebApp.py", "--server.port=8501", "--server.address=0.0.0.0"]&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h4&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Step 2c: Create the Deployment Scripts&lt;br&gt;
&lt;/h4&gt;

&lt;p&gt;Then create a 'scripts' directory within the repository's root directory that will contain the deployment scripts, similar to &lt;a href="https://github.com/astroveny/WebApp-Microservice-ST/blob/main/scripts/start_app.sh" rel="noopener noreferrer"&gt;'start_app.sh'&lt;/a&gt; and &lt;a href="https://github.com/astroveny/WebApp-Microservice-ST/blob/main/scripts/stop_app.sh" rel="noopener noreferrer"&gt;'stop_app.sh'&lt;/a&gt;.   &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2d: Create the buildspec.yml
&lt;/h4&gt;

&lt;p&gt;Create the &lt;a href="https://github.com/astroveny/WebApp-Microservice-ST/blob/main/buildspec.yml" rel="noopener noreferrer"&gt;buildspec.yml&lt;/a&gt; at the GitHub repository's root directory. &lt;br&gt;
CodeBuild will use the buidlspec.yml configuration file to build the container image and then store it in the ECR repository.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2e: Create the appspec.yml
&lt;/h4&gt;

&lt;p&gt;Create the &lt;a href="https://github.com/astroveny/WebApp-Microservice-ST/blob/main/appspec.yml" rel="noopener noreferrer"&gt;appspec.yml&lt;/a&gt; at the GitHub repository's root directory. CodeDeploy will use the appspec.yml configuration file to deploy the container on the EC2 instance.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Create the IAM Roles
&lt;/h3&gt;

&lt;p&gt;Before creating the required resources, you will have to create IAM Roles for the EC2 instance and CodeDeploy.&lt;br&gt;
It is recommended to customize each policy and create an inline policy to restrict access to the required resources, but for simplicity, we will use the policies managed by AWS &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3a: IAM Role for EC2 instance
&lt;/h4&gt;

&lt;p&gt;This role has 2 policies to allow EC2 instance access to S3 and ECR ("AmazonEC2ContainerRegistryPowerUser", "AmazonS3ReadOnlyAccess")&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3b: IAM Role for CodeDeploy
&lt;/h4&gt;

&lt;p&gt;This role has 2 policies to allow CodeDeploy access to EC2, ELB, Autoscaling and ECR ("AmazonEC2ContainerRegistryPowerUser", "AWSCodeDeployRole")&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 4: Create an AWS EC2 instance
&lt;/h3&gt;

&lt;p&gt;You will create an instance and attach this &lt;a href="https://github.com/astroveny/WebApp-Microservice-ST/blob/main/user-data" rel="noopener noreferrer"&gt;user-data file&lt;/a&gt; which will install the codedeploy-agent, and docker.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Go To &lt;strong&gt;AWS EC2 console&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Launch Instance&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter the instance &lt;strong&gt;Name&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application and OS Images:&lt;/strong&gt; Choose AMI "eg: Amazon Linux 2023 AMI"
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Instance type&lt;/strong&gt; "eg: t2.micro"&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Key pair (login)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network settings:&lt;/strong&gt; Enter the following details

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPC:&lt;/strong&gt; "eg: default VPC"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subnet:&lt;/strong&gt; "eg: SubnetPub1"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-assign public IP:&lt;/strong&gt; Enable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Group:&lt;/strong&gt; Select Create security group

&lt;ul&gt;
&lt;li&gt;Security group name: "eg: WebApp-SG"&lt;/li&gt;
&lt;li&gt;Skip Inbound rules for now&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure storage:&lt;/strong&gt; add storage volume&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced details:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IAM instance profile:&lt;/strong&gt; Choose the IAM role created in the previous step&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User data:&lt;/strong&gt; upload the &lt;a href="https://github.com/astroveny/WebApp-Microservice-ST/blob/main/user-data" rel="noopener noreferrer"&gt;user-data file&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Launch instance.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Step 5: Create an Application Load Balancer
&lt;/h3&gt;

&lt;p&gt;Before creating the Load Balancer, create a &lt;strong&gt;Security Group&lt;/strong&gt; with an Inbound Rule (&lt;strong&gt;Type:&lt;/strong&gt; HTTPS; &lt;strong&gt;Source:&lt;/strong&gt; Custom 0.0.0.0/0) and note the security group ID.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5a: Configure a target group
&lt;/h4&gt;

&lt;p&gt;Configure a target group then register the EC2 instance as a target&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the AWS EC2 console&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Target Groups&lt;/strong&gt; from the navigation pane&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create target group&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic configuration:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target type:&lt;/strong&gt; Select &lt;strong&gt;Instance&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target group name:&lt;/strong&gt; Enter a name "WebApp-TG"&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Protocol&lt;/strong&gt; &amp;amp;  &lt;strong&gt;Port&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;IP address type:&lt;/strong&gt; IPv4&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;VPC:&lt;/strong&gt; "eg: Default VPC"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health checks:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;Health check protocol:&lt;/strong&gt; HTTP&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Health check path:&lt;/strong&gt; enter the health check route or keep the default / "eg: /HeathCheck"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Next&lt;/strong&gt; to register a target&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Register targets:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Select the instance created before, and the port, and then choose &lt;strong&gt;Include as pending below&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create target group&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 5b: Create a load balancer
&lt;/h4&gt;

&lt;p&gt;Once the target group is ready, set up an application load balancer.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the AWS EC2 console&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Load Balancers&lt;/strong&gt; from the navigation pane&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create Load Balancer&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Application Load Balancer&lt;/strong&gt;, choose &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic configuration:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Load balancer name:&lt;/strong&gt; Enter a name for your load balancer "eg: WebApp-ALB**&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheme:&lt;/strong&gt; choose Internet-facing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP address type:&lt;/strong&gt; IPv4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network mapping&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPC:&lt;/strong&gt; select the VPC "eg: Default VPC"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mappings:&lt;/strong&gt; Choose the subnets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security groups:&lt;/strong&gt; Select the security group created earlier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Listeners and routing:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol:&lt;/strong&gt; HTTPS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port:&lt;/strong&gt; 443&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default action:&lt;/strong&gt; Select the target group created above&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure listener settings:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Default SSL/TLS server certificate:&lt;/strong&gt; Select &lt;strong&gt;Certificate source&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create Load Balancer&lt;/strong&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 5c: Update EC2 instance security group
&lt;/h4&gt;

&lt;p&gt;Now that ALB is ready, update the EC2 instance security group to allow ingress connection from ALB using a specific port&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the AWS EC2 console&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Security Groups&lt;/strong&gt; from the navigation pane&lt;/li&gt;
&lt;li&gt;Choose the security group created for the EC2 instance&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Inbound rules&lt;/strong&gt;  Choose &lt;strong&gt;Edit inbound rules&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Add rule&lt;/strong&gt; 1

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Custom TCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port:&lt;/strong&gt; Enter the web app port&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; Custom - select the ALB security group&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Add rule&lt;/strong&gt; 2

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; ssh&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; select My IP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Save rules&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Step 6: Create a CodeBuild project
&lt;/h3&gt;

&lt;p&gt;The build project will build the container image and then push it to the ECR repository. You will need to follow the steps below to create the build project.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Go to the AWS CodeBuild console&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create build project&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project configuration:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project name:&lt;/strong&gt; Enter the project name&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source provider:&lt;/strong&gt; Select Github&lt;/li&gt;
&lt;li&gt;follow the instructions to connect (or reconnect) to GitHub and authorize access to AWS CodeBuild&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository:&lt;/strong&gt; Select Public repo, or repo in your GitHub account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repository:&lt;/strong&gt; Enter the repo link "eg: &lt;a href="https://github.com/YourGitHubUser/RepoName.git" rel="noopener noreferrer"&gt;https://github.com/YourGitHubUser/RepoName.git&lt;/a&gt;"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source version:&lt;/strong&gt; Enter the branch name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook&lt;/strong&gt; optional: Rebuild every time a code change is pushed to this repository&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Environment image:&lt;/strong&gt; Managed image&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operating system:&lt;/strong&gt; Amazon Linux&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime(s):&lt;/strong&gt; Standard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image:&lt;/strong&gt; 5.0 or latest&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Privileged&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service role:&lt;/strong&gt; select &lt;strong&gt;New service role&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role name:&lt;/strong&gt; Enter a service role name&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buildspec:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build specifications:&lt;/strong&gt; select &lt;strong&gt;Use a buildspec file&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;By default, CodeBuild looks for a file named buildspec.yml in the source code root directory&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Artifacts:&lt;/strong&gt; select &lt;em&gt;No artifacts&lt;/em&gt; for now, it will be updated during the setup of CodePipeline &lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create build project&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to AWS IAM console&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Roles&lt;/strong&gt; from the navigation pane

&lt;ul&gt;
&lt;li&gt;Search &amp;amp; select the service role name you entered while setting up the build project&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Add permissions:&lt;/strong&gt; select &lt;strong&gt;attach policy&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Search &amp;amp; select policy: AmazonEC2ContainerRegistryPowerUser&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Add permission&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Step 7: Create an AWS CodeDeploy Application
&lt;/h3&gt;

&lt;p&gt;In this demo, you will create a CodeDeploy application for an in-place deployment using the CodeDeploy console. Otherwise, it is recommended to create a Blue/Green deployment with multiple compute resources to ensure the availability of the Web App.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Create the Application
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Go to the AWS CodeDeploy console.&lt;/li&gt;
&lt;li&gt;expand &lt;strong&gt;Deploy&lt;/strong&gt;, and then choose &lt;strong&gt;Getting started&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create application&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application configuration:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application name:&lt;/strong&gt; Enter an application name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute platform:&lt;/strong&gt; EC2/On-premises.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create application&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose the application name.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create deployment group&lt;/strong&gt; under &lt;strong&gt;Deployment groups&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment group name:&lt;/strong&gt; Enter a deployment group name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service role:&lt;/strong&gt; Select the service role created previously for CodeDeploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment type:&lt;/strong&gt; In-place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment configuration:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;Amazon EC2 instances&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter the tag key used while creating the EC2 instance.&lt;/li&gt;
&lt;li&gt;Enter the tag value. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install AWS CodeDeploy Agent:&lt;/strong&gt; Never&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment configuration:&lt;/strong&gt; CodeDeployDefault.AllAtOnce&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create deployment group&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Step 8: Create an AWS CodePipeline
&lt;/h3&gt;

&lt;p&gt;Now that build GitHub repository, build project, and CodeDeploy application are ready for the pipeline, you will follow the steps below to configure it.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Step 8a: Setup the Pipeline
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Go to the AWS CodePipeline console.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create pipeline&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline settings:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline name:&lt;/strong&gt; Enter the pipeline name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service role:&lt;/strong&gt; Choose &lt;strong&gt;New service role&lt;/strong&gt; or &lt;strong&gt;Existing service role&lt;/strong&gt; if you have an existing role.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source provider:&lt;/strong&gt; GitHub (version 2)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection:&lt;/strong&gt; Choose exiting Github connection or choose &lt;strong&gt;Connect to Github&lt;/strong&gt; to create a new connection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository name:&lt;/strong&gt; Enter the repository name "eg: YourGitHubUser/WebAppRepo"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch name:&lt;/strong&gt; Enter the branch name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output artifact format:&lt;/strong&gt; CodePipeline default.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build provider:&lt;/strong&gt; AWS CodeBuild.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Region:&lt;/strong&gt; Select your region.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project name&lt;/strong&gt; Choose the project name created earlier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build type:&lt;/strong&gt; Single build.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deploy provider:&lt;/strong&gt; AWS CodeDeploy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Region:&lt;/strong&gt; Enter your region.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application name:&lt;/strong&gt; Choose the application you created earlier. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment group:&lt;/strong&gt; Choose the deployment group you created earlier. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Review the configuration then choose &lt;strong&gt;Create pipeline&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  Step 8b: Run the Pipeline
&lt;/h4&gt;

&lt;p&gt;The pipeline will run once it is created. starting by running the Source stage to get the files from the GitHub repository, then running the Build stage to build the container image then push it to the ECR repository. Finally, run the Deploy stage which will deploy the container on the EC2 instance.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 9: CloudFront Distribution
&lt;/h3&gt;

&lt;p&gt;You may choose to use CloudFront to cache your web app content and bring it closer to your users. This can help reduce the load on the ALB, resulting in lower costs. Additionally, you can add another layer of security by configuring WAF/Shield. However, it's important to note that using CloudFront is an optional step.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 9a: Create a CloudFront Distribution
&lt;/h4&gt;

&lt;p&gt;Follow the steps below to create a CloundFront Distribution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the AWS CloudFront console.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Origin domain:&lt;/strong&gt; Select the ALB name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol:&lt;/strong&gt; HTTPS only&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS port:&lt;/strong&gt; 443&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default cache behavior:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Viewer protocol policy:&lt;/strong&gt; Redirect HTTP to HTTPS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache key and origin requests:&lt;/strong&gt; Cache policy and origin request policy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache policy:&lt;/strong&gt; CachingDisabled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin request policy -:&lt;/strong&gt; AllViewerAndCloudFrontHeaders&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settings:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom SSL certificate:&lt;/strong&gt; Select the ACM certificate&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Step 10: Publish the Web App
&lt;/h3&gt;

&lt;p&gt;After deploying the CloudFront distribution, the final step is to publish your web application using Route 53. If you already have a domain name, you should create a new A record as an Alias and then choose the ALB URL or the CloudFront distribution URL if you have already created it. In case you do not have a domain name, you can create a new one using Route 53 and then add the A record. &lt;/p&gt;

&lt;p&gt;Alternatively, you can use the CloudFront URL or the ALB URL if you are looking for a temporary option.&lt;/p&gt;




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

&lt;p&gt;We have developed a MACH architecture for building and deploying a user-friendly Streamlit web application using AWS services. By utilizing CICD with AWS CodePipeline, we can dynamically build and deploy the web app on a container, which speeds up the process, provides flexibility, agility, and ensures availability. The solution is highly adaptable and can be deployed in any environment. It can also be optimized to scale using Auto-Scaling, which reduces costs based on the required traffic.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>python</category>
      <category>streamlit</category>
      <category>aws</category>
    </item>
    <item>
      <title>AWS CLI — Multiple profiles</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Wed, 23 Aug 2023 19:21:03 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-cli-multiple-profiles-3b51</link>
      <guid>https://dev.to/aws-builders/aws-cli-multiple-profiles-3b51</guid>
      <description>&lt;p&gt;How to take advantage of multiple profiles feature? (with examples and tips)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why and How?
&lt;/h2&gt;

&lt;p&gt;The cloud environment should have multiple accounts, according to AWS best practice "Well-Architected Framework". Based on the security requirements, each account has different groups, roles, and users.&lt;br&gt;
In such a configuration, you may have multiple profiles to use on a daily basis, either between different accounts or even within the same account, with each profile having different permissions or roles.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Multiple profiles
&lt;/h2&gt;

&lt;p&gt;Here is how you can add multiple profiles on AWS CLI&lt;/p&gt;

&lt;p&gt;To create multiple AWS CLI profiles, you can use the aws configure command. This command will prompt you for information such as your AWS Access Key ID and Secret Access Key, as well as the default region and output format for your profile.&lt;/p&gt;

&lt;p&gt;To create a new profile, you can use the --profile option, followed by the name of your profile. For example, if you wanted to create a profile named "dev", you could use the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aws configure --profile dev&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;You can create as many profiles as you need, each with its own set of credentials and configuration options.&lt;/p&gt;

&lt;p&gt;To use a specific profile, you can use the --profile option followed by the name of the profile you want to use. For example, if you wanted to use the "dev" profile you created earlier, you could use the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aws s3 ls --profile dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let's walk through the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open the command line or terminal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type in the following command: &lt;code&gt;aws configure&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When prompted, enter the &lt;strong&gt;access key ID&lt;/strong&gt; and &lt;strong&gt;secret access key&lt;/strong&gt; for the first profile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When prompted for the default region name and output format, enter the desired values for the first profile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repeat steps 2-4 for each additional profile, using a different name and access key ID/secret access key for each one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To switch between profiles, use the --profile flag followed by the profile name in subsequent AWS CLI commands. For example, to use the "dev" profile, you would use the command: aws --profile dev [command] [options]&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;  Here is an example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\&amp;gt; aws configure
AWS Access Key ID [None]: ANY0TH3R4CC3SSK3YL6V
AWS Secret Access Key [None]: 0C+tH1Sc0uLdb3aNYS3CR3tk3YG3n3RAt3d92
Default region name [None]: us-east-1
Default output format [None]: json

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

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;  Add another profile:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\&amp;gt; aws configure --profile userdev2
AWS Access Key ID [None]: ANY0TH3R4CC3SSK3YOOZ
AWS Secret Access Key [None]: cP-0C+tH1Sc0uLdb3aNYS3CR3tk3YG3n3RAt3d6z
Default region name [None]: us-east-1
Default output format [None]: json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;  To list the available profiles, run the this command:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\&amp;gt;  aws configure list-profiles
default
userdev2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;  To view the &lt;strong&gt;default&lt;/strong&gt; profile, run the below command:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\&amp;gt; aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                  userdev              env    ['AWS_PROFILE', 'AWS_DEFAULT_PROFILE']
access_key     ****************YL6V              env
secret_key     ****************3d92              env
    region                us-east-1      config-file    ~/.aws/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;  To view another profile, add "&lt;strong&gt;--profile&lt;/strong&gt;" and the name of the profile to the above command:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\&amp;gt; aws configure list --profile userdev2
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                 userdev2           manual    --profile
access_key     ****************AGGH shared-credentials-file
secret_key     ****************Fpne shared-credentials-file
    region                us-east-1      config-file    ~/.aws/config

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  So what is the default profile?
&lt;/h3&gt;

&lt;p&gt;The default profile is determined by the settings in the ~/.aws/credentials file on your local machine. You do not need to add "&lt;strong&gt;--profile&lt;/strong&gt;" in your AWS CLI command, you can just type: aws [command] [options]&lt;/p&gt;

&lt;p&gt;You can change the default profile manually by editing the ~/.aws/credentials file or you can run this command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Windows - PowerShell:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\&amp;gt; $Env:AWS_PROFILE = 'userdev2'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;  Windows - CMD:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The below command will change the variable in the current CMD session only!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set AWS_PROFILE=userdev2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The below command will change the variable in all NEW CMD sessions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setx AWS_PROFILE userdev2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; make sure that the below variables are not set, otherwise setting AWS_PROFILE to the new profile will not force changing the credentials&lt;/p&gt;

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

&lt;/div&gt;




&lt;ul&gt;
&lt;li&gt;  Linux:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export AWS_PROFILE=userdata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run this command to verify that the default profile has been changed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws configure list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run the following command to check the AWS account and IAM user of the current profile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws sts get-caller-identity
{
    "UserId": "AUs3r1DF0rtH1sUs3rZL",
    "Account": "432109876543",
    "Arn": "arn:aws:iam::432109876543:user/userdev"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;For more details, you may refer to the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html"&gt;AWS CLI - Configuration basics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You may be interested in:&lt;/em&gt;&lt;br&gt;
&lt;a href="https://dev.to/aws-builders/how-to-use-aws-cli-auto-prompt-to-help-you-build-your-command-faster-12l6"&gt;How to use (AWS CLI -- Auto-prompt) to help you build your command faster!&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Please feel free to share your feedback.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>awscli</category>
      <category>multipleprofiles</category>
      <category>awsaccounts</category>
    </item>
    <item>
      <title>How to use (AWS CLI -- Auto-prompt) to help you build your command faster!</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Wed, 23 Aug 2023 19:18:45 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-to-use-aws-cli-auto-prompt-to-help-you-build-your-command-faster-12l6</link>
      <guid>https://dev.to/aws-builders/how-to-use-aws-cli-auto-prompt-to-help-you-build-your-command-faster-12l6</guid>
      <description>&lt;h2&gt;
  
  
  What is auto-prompt mode?
&lt;/h2&gt;

&lt;p&gt;The AWS CLI is a powerful tool for managing and setting up AWS services and automating them through scripting.&lt;/p&gt;

&lt;p&gt;Since we use it in our daily operations, it would be helpful to have a list of the commands for quick reference.&lt;br&gt;
Fortunately, AWS CLI has a handy feature that would be helpful when constructing commands. The auto-prompt mode lists the services or options as you type. This would be very useful, especially if you forget a few options.  &lt;/p&gt;

&lt;p&gt;There are 3 ways to use this feature. I will walk through them with examples.&lt;/p&gt;
&lt;h2&gt;
  
  
  1- Single command option
&lt;/h2&gt;

&lt;p&gt;AWS CLI option &lt;code&gt;--cli-auto-prompt&lt;/code&gt; can be used once per single command. &lt;/p&gt;

&lt;p&gt;Example 1.1:&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="nv"&gt;$ &lt;/span&gt;aws &lt;span class="nt"&gt;--cli-auto-prompt&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; aws
 accessanalyzer                      Access Analyzer
 account                             AWS Account
 acm                                 AWS Certificate Manager
 acm-pca                             AWS Certificate Manager Private Certi...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example 1.2:&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="nv"&gt;$ &lt;/span&gt;aws s3 &lt;span class="nt"&gt;--cli-auto-prompt&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; aws s3
          &lt;span class="nb"&gt;ls
          &lt;/span&gt;website
          &lt;span class="nb"&gt;cp
          mv
          rm
          sync
          &lt;/span&gt;mb
          rb
          presign
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2- Using Environment variables
&lt;/h2&gt;

&lt;p&gt;There are 2 settings that can be used to enable auto-prompt mode inside the environment variables.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;on&lt;/strong&gt; uses the full auto-prompt mode whenever you run aws command. Useful when you are new to aws commands. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;AWS_CLI_AUTO_PROMPT=on&lt;/code&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;on-partial&lt;/strong&gt; uses partial auto-prompt mode. This mode is particular useful if you have pre-existing scripts, runbooks, or you only want to be auto-prompted for commands you are unfamiliar with rather than prompted on every command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;AWS_CLI_AUTO_PROMPT=on-partial&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2.1- How to set auto-prompt inside the environment variables
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMD
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;c:\&amp;gt; set AWS_CLI_AUTO_PROMPT=on-partial
c:\&amp;gt; set AWS_CLI_AUTO_PROMPT
AWS_CLI_AUTO_PROMPT=on-partial
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;PowerShell or Terminal
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\&amp;gt; $Env:AWS_CLI_AUTO_PROMPT = 'on-partial'
&amp;gt; $Env:AWS_CLI_AUTO_PROMPT
on-partial
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terminal
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export AWS_CLI_AUTO_PROMPT="on-partial"
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3-  Shared config files
&lt;/h2&gt;

&lt;p&gt;You can enable auto-prompt mode per each profile by updating the AWS CLI &lt;strong&gt;config&lt;/strong&gt; file located inside &amp;gt;&amp;gt; (~/.aws/).&lt;/p&gt;

&lt;p&gt;Edit the config file then add one of the below settings for each profile.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cli_auto_prompt = on&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```
[profile User1]
region=us-east-1 
cli_auto_prompt = on
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cli_auto_prompt = on-partial&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[profile User2]
region=us-east-1
cli_auto_prompt = on-partial
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;For more details, you may refer to the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-prompting.html"&gt;AWS CLI User Guide - Auto-prompt&lt;/a&gt;&lt;/p&gt;

</description>
      <category>awscli</category>
      <category>devopsautomation</category>
      <category>awsmanagement</category>
      <category>autoprompt</category>
    </item>
    <item>
      <title>How to build a Serverless and cost-effective failover solution using a backup website with traffic monitoring! (part 2/2)</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Thu, 17 Aug 2023 08:53:35 +0000</pubDate>
      <link>https://dev.to/aws-builders/serverless-and-cost-effective-failover-solution-using-backup-website-with-traffic-monitoring-part-22-46ff</link>
      <guid>https://dev.to/aws-builders/serverless-and-cost-effective-failover-solution-using-backup-website-with-traffic-monitoring-part-22-46ff</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/astroveny/serverless-and-cost-effective-failover-solution-using-backup-website-with-traffic-monitoring-part-12-285k"&gt;In the previous article (part 1/2)&lt;/a&gt; we have created an &lt;strong&gt;S3&lt;/strong&gt; static website as an origin to &lt;strong&gt;CloudFront&lt;/strong&gt; distribution, then we updated the &lt;strong&gt;Route 53&lt;/strong&gt; configuration to add a new A record pointing to the static website and enabled failover routing policy.&lt;/p&gt;

&lt;p&gt;In this phase we will continue deploying serverless services to enable traffic monitoring using &lt;strong&gt;S3&lt;/strong&gt; bucket to save the &lt;strong&gt;CloudFront&lt;/strong&gt; access logs, create a &lt;strong&gt;Lambda&lt;/strong&gt; function to reduce the log count and use &lt;strong&gt;Athena&lt;/strong&gt; to query the access logs data.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspv4qoikljcz0eb8r99a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspv4qoikljcz0eb8r99a.png" alt="Serverless Diagram" width="710" height="447"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  Traffic Monitoring
&lt;/h2&gt;

&lt;p&gt;We will create a new S3 bucket to store the CloudFront access logs, and create another bucket to be used by Athena, then we will enable CloudFront standard logging. Next, we will create a new database and table in Athena to query and analyze the access logs. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;AWS S3&lt;/strong&gt; console

&lt;ul&gt;
&lt;li&gt;Create an access log bucket for CloudFront and enable ACL then create a log folder "cf_accesslogs"&lt;/li&gt;
&lt;li&gt;Create another bucket to be used by Athena &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;AWS Cloudfront&lt;/strong&gt; console

&lt;ul&gt;
&lt;li&gt;Select the &lt;strong&gt;distribution&lt;/strong&gt; then click &lt;strong&gt;Edit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Turn On &lt;strong&gt;Standard logging&lt;/strong&gt; then select the access log S3 bucket you have just created&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefix:&lt;/strong&gt; the logs folder "cf_accesslogs"&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save changes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Wait until Cloudfront distribution is deployed&lt;/li&gt;
&lt;li&gt;If the Web App is down, access your web app domain then it will failover to the CloudFront distribution URL &lt;/li&gt;
&lt;li&gt;or access the Cloudfront distribution URL directly &lt;/li&gt;
&lt;li&gt;This will generate logs inside the S3 logs bucket&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;AWS Athena&lt;/strong&gt; console

&lt;ul&gt;
&lt;li&gt;Make sure you are using the same region as the created bucket&lt;/li&gt;
&lt;li&gt;Select the Athena bucket to be used by Athena to store the data&lt;/li&gt;
&lt;li&gt;Add the following to the Query editor to create a &lt;strong&gt;accesslogs&lt;/strong&gt; database &lt;code&gt;create database accesslogs;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Run&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;+&lt;/strong&gt; sign to add a new query tab &lt;/li&gt;
&lt;li&gt;Add the following to create a table (replace YourS3LogsBucket/prefix with the bucket name and prefix)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;EXTERNAL&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;accesslogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cloudfront_logs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;`date`&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;request_ip&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;method&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;host&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;referrer&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;user_agent&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;query_string&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;result_type&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;request_id&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;host_header&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;request_protocol&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;request_bytes&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;time_taken&lt;/span&gt; &lt;span class="nb"&gt;FLOAT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;xforwarded_for&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ssl_protocol&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ssl_cipher&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;response_result_type&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;http_version&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;fle_status&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;fle_encrypted_fields&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;c_port&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;time_to_first_byte&lt;/span&gt; &lt;span class="nb"&gt;FLOAT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;x_edge_detailed_result_type&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;sc_content_type&lt;/span&gt; &lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;sc_content_len&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;sc_range_start&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;sc_range_end&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ROW&lt;/span&gt; &lt;span class="n"&gt;FORMAT&lt;/span&gt; &lt;span class="n"&gt;DELIMITED&lt;/span&gt; 
&lt;span class="n"&gt;FIELDS&lt;/span&gt; &lt;span class="n"&gt;TERMINATED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;LOCATION&lt;/span&gt; &lt;span class="s1"&gt;'s3://YourS3LogsBucket/prefix'&lt;/span&gt;
&lt;span class="n"&gt;TBLPROPERTIES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'skip.header.line.count'&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'2'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run&lt;/strong&gt; the query&lt;/li&gt;
&lt;li&gt;Add another query tab to query the data from the table using the following
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"accesslogs"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"cloudfront_logs"&lt;/span&gt; &lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Or select some of the important columns
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request_ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_agent&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"accesslogs"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"cloudfront_logs"&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;bY&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run&lt;/strong&gt; the query to show the data
&lt;/li&gt;
&lt;li&gt;You will see useful data points such as: Date/time, Location, Request_IP, Method, status, and Host_Header ..&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Table fields description Ref. &lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html#access-logs-choosing-s3-bucket"&gt;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html#access-logs-choosing-s3-bucket&lt;/a&gt;  &lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A Lambda Function to reduce the log files
&lt;/h2&gt;

&lt;p&gt;We will reduce the number of files inside the S3 access logs bucket by creating a lambda function that will keep the latest 5 logs files generated by CloudFront. The function will be triggered once a new log file is generated&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;AWS Lambda&lt;/strong&gt; console&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create function&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; CF-Latest-logs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; Pyhton 3.10&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture:&lt;/strong&gt; x86_64&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create function&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;  Replace the lambda function code with the following
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bucket_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YourBucketName&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;# replace the value &amp;lt;YourBucketName&amp;gt; with the access logs bucket name
&lt;/span&gt;    &lt;span class="n"&gt;folder_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;LogsFolder&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;# replace the value &amp;lt;LogsFolder&amp;gt; with the folder name "cf_accesslogs"
&lt;/span&gt;    &lt;span class="n"&gt;last_x_objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;xlogs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="c1"&gt;# number of the latest log files
&lt;/span&gt;
    &lt;span class="c1"&gt;# Get a list of all objects in the folder
&lt;/span&gt;    &lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_objects_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bucket_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;folder_name&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Contents&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Sort the objects by last modified date, with the most recent objects first
&lt;/span&gt;    &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LastModified&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Keep the last recent x objects
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xlogs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;last_x_objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# Delete all objects in the folder except the last recent x objects
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;last_x_objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bucket_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Objects deleted from S3 folder except the last recent x objects&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Add S3 Bucket Permissions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Configuration&lt;/strong&gt; tab inside the Lambda function&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Permissions&lt;/strong&gt; from the left-side menu&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Role name&lt;/strong&gt; to add new permissions&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add permissions&lt;/strong&gt; then &lt;strong&gt;Create inline policy&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;JSON&lt;/strong&gt; tab then replace the content with the following

&lt;ul&gt;
&lt;li&gt;Replace "CF-ACCESSLOGS-BUCKET" with the respective value
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VisualEditor0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::CF-ACCESSLOGS-BUCKET/*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::CF-ACCESSLOGS-BUCKET"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Review policy&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;Enter a &lt;strong&gt;Name&lt;/strong&gt; then click &lt;strong&gt;Create policy&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trigger The Lambda Function
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;AWS S3&lt;/strong&gt; console&lt;/li&gt;
&lt;li&gt;Select the CloudFront logs bucket you have created previously &lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Properties&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create event notification&lt;/strong&gt; under &lt;strong&gt;Event notifications&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event name:&lt;/strong&gt; cf-latest-logs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event types:&lt;/strong&gt; select &lt;strong&gt;All object create events&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination:&lt;/strong&gt; select Lambda function&lt;/li&gt;
&lt;li&gt;Select the lambda function "CF-Latest-logs" from the drop-down menu&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Save changes&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;While the web app is under maintenance, access to the web app  domain name will be redirected to the static website through CloudFront distribution, which will save the web traffic logs in the access logs bucket. Next, the Lambda function will be triggered, updating the bucket and retaining the latest &lt;em&gt;xlogs&lt;/em&gt; number of log files. Lastly, we can then run Athena query to display the latest logs and analyze the data.&lt;/p&gt;

</description>
      <category>staticwebsitehostings3</category>
      <category>awslambda</category>
      <category>serverlesswebsite</category>
      <category>websitetrafficanalyzer</category>
    </item>
    <item>
      <title>How to build a Serverless and cost-effective failover solution using a backup website with traffic monitoring! (part 1/2)</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Tue, 15 Aug 2023 13:23:30 +0000</pubDate>
      <link>https://dev.to/aws-builders/serverless-and-cost-effective-failover-solution-using-backup-website-with-traffic-monitoring-part-12-285k</link>
      <guid>https://dev.to/aws-builders/serverless-and-cost-effective-failover-solution-using-backup-website-with-traffic-monitoring-part-12-285k</guid>
      <description>&lt;p&gt;Building and maintaining a website or a web app would take time and effort during the development phase or due to a major issue that could cause a downtime that require some time to resolve it.&lt;/p&gt;

&lt;p&gt;We often design and configure our system to reduce or eliminate incidents that could cause a sever impact, by setting up backups and Disaster Recovery setup (Warm Standby or Active/Active) depending on the RPO/RTO requirements and cost implications. Along with this, especially during the development or pre-production stages in the cloud, we could build a serverless cost-effective failover solution to a backup website and monitor traffic.&lt;/p&gt;

&lt;p&gt;During the &lt;a href="https://github.com/astroveny/aws-bootcamp-cruddur-2023"&gt;AWS Cloud Bootcamp&lt;/a&gt; by &lt;a href="https://www.linkedin.com/in/andrew-wc-brown/"&gt;Andrew Brown&lt;/a&gt; &lt;a href="https://www.exampro.co/"&gt;(ExamPro)&lt;/a&gt;, we built a &lt;strong&gt;Cruddur&lt;/strong&gt; web app, so I had to design and deploy a &lt;em&gt;failover solution&lt;/em&gt;. In this example, the web app runs on &lt;strong&gt;ECS Fargate&lt;/strong&gt; behind an &lt;strong&gt;ALB Load Balancer&lt;/strong&gt; which is registered on &lt;strong&gt;Route 53&lt;/strong&gt; hosted zone. The failover solution consist of setting up a &lt;strong&gt;S3&lt;/strong&gt; static website as an origin to a &lt;strong&gt;CloudFront&lt;/strong&gt; distribution, and registered on &lt;strong&gt;Route 53&lt;/strong&gt; hosted zone. We will enable &lt;strong&gt;Route 53&lt;/strong&gt; &lt;em&gt;failover routing policy&lt;/em&gt; so that traffic is routed to the static website in the event that web app is unavailable. &lt;/p&gt;

&lt;p&gt;The benefits of &lt;strong&gt;CloudFront&lt;/strong&gt; would be to cache the content globally and utilize HTTPS using TLS which encrypt data in transit. To start, we first need to set up an &lt;strong&gt;S3&lt;/strong&gt; static website, after which we will create a &lt;strong&gt;CloudFront&lt;/strong&gt; distribution with the &lt;strong&gt;S3&lt;/strong&gt; static website as the origin. Next, we will Update the &lt;strong&gt;Route 53&lt;/strong&gt; hosted zone, edit the primary A record to enable failover by evaluating target health, create a new A record with the same record name to point to the &lt;strong&gt;CloudFront&lt;/strong&gt; Distribution domain name, and route as secondary failover.&lt;/p&gt;

&lt;p&gt;Finally, we will monitor the web traffic by enabling CloudFront logging to a new &lt;strong&gt;S3&lt;/strong&gt; bucket and reduce the log file count by invoking a &lt;strong&gt;lambda&lt;/strong&gt; function once a new log file is created. Lastly, we will query the logs using &lt;strong&gt;AWS Athena&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspv4qoikljcz0eb8r99a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspv4qoikljcz0eb8r99a.png" alt="Serverless Diagram" width="710" height="447"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Create S3 Static Website Bucket
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS S3 console&lt;/li&gt;
&lt;li&gt;Create a bucket using DomainName as the name of the bucket&lt;/li&gt;
&lt;li&gt;Select the bucket then Edit &lt;strong&gt;Static website hosting&lt;/strong&gt; under &lt;strong&gt;Properties&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Enable&lt;/strong&gt; Static website hosting&lt;/li&gt;
&lt;li&gt;Enter the &lt;strong&gt;Index document&lt;/strong&gt; file name e.g. index.html that display "Under Maintenance"
&lt;/li&gt;
&lt;li&gt;Save changes &lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Upload Static Website Files
&lt;/h3&gt;

&lt;p&gt;We will upload the content of the static website. This can be a simple single-page website which only requires uploading the html and css files or more complicated website built using for example JavaScript, which requires npm build of the website files then upload the build files.&lt;/p&gt;

&lt;p&gt;In both ways, we may follow the following steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go To AWS S3 Console&lt;/li&gt;
&lt;li&gt;Select the bucket name created previously &lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Upload&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add the files of the static website
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Upload&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Cloudfront Distribution
&lt;/h3&gt;

&lt;p&gt;We will use the existing ACM certificate which is already used by the ALB.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS CloudFront console&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create Distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin domain:&lt;/strong&gt; Select the S3 bucket created previously &lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Use website endpoint&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viewer/Viewer protocol policy:&lt;/strong&gt; Redirect HTTP to HTTPS

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allowed HTTP methods:&lt;/strong&gt; GET, HEAD&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settings/Alternate domain name (CNAME):&lt;/strong&gt; Add your DomainName

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom SSL certificate - optional:&lt;/strong&gt; Select your ACM certificate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supported HTTP versions:&lt;/strong&gt; Select both HTTTP 2/3&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Update S3 Bucket Policy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS S3 console&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Permissions&lt;/strong&gt; tab, Edit &lt;strong&gt;Bucket policy&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;Add the following policy (replace the "S3-Bucket-ARN" &amp;amp; "cloudfront-ARN" with the respective value)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2008-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PolicyForCloudFrontPrivateContent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowCloudFrontServicePrincipal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cloudfront.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::S3-Bucket-ARN/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="nl"&gt;"AWS:SourceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:cloudfront-ARN"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Route 53 Hosted Zone Records
&lt;/h3&gt;

&lt;p&gt;Enable primary failover routing policy for the exiting A record pointing to the web app, then create a new A record that will point to the CloudFront distribution URL "Static website" and enable secondary failover routing policy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS Route 53 console&lt;/li&gt;
&lt;li&gt;Edit the exiting primary A record pointing to your website via the ALB&lt;/li&gt;
&lt;li&gt;Change &lt;strong&gt;Routing policy:&lt;/strong&gt; to Failover&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failover record type:&lt;/strong&gt; Primary&lt;/li&gt;
&lt;li&gt;Make sure &lt;strong&gt;Evaluate target health&lt;/strong&gt; is enabled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record ID:&lt;/strong&gt; enter any value&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Save&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Create a new A record to point to the static website:

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;Create record&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Record type&lt;/strong&gt; as A record&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Alias&lt;/strong&gt; then under &lt;strong&gt;Route traffic to&lt;/strong&gt; select CloudFront distribution&lt;/li&gt;
&lt;li&gt;Select the CloudFront Distribution domain name created in the previous step
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Routing policy&lt;/strong&gt; as Failover&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Failover record type&lt;/strong&gt; as Secondary &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record ID:&lt;/strong&gt; enter any value&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create record&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Route 53 can now failover to the &lt;strong&gt;static website&lt;/strong&gt; in the event that the web app is unavailable due to maintenance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsajgk9b5rml98hso6p9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsajgk9b5rml98hso6p9.png" alt="Image description" width="800" height="119"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In this phase we have completed deploying an &lt;strong&gt;S3&lt;/strong&gt; static website as an origin to the &lt;strong&gt;CloudFront&lt;/strong&gt; distribution, then updated the &lt;strong&gt;Route 53&lt;/strong&gt; configuration to add a new A record pointing to the static website and enabled failover routing policy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/astroveny/serverless-and-cost-effective-failover-solution-using-backup-website-with-traffic-monitoring-part-22-46ff"&gt;In the next phase (part 2/2)&lt;/a&gt; we will continue deploying serverless services to enable traffic monitoring using S3 bucket to save the &lt;strong&gt;CloudFront&lt;/strong&gt; access logs, create a &lt;strong&gt;Lambda&lt;/strong&gt; function to reduce the log count and use &lt;strong&gt;Athena&lt;/strong&gt; to query the access logs data. &lt;/p&gt;

</description>
      <category>awscloudfrontdistribution</category>
      <category>staticwebsitehostings3</category>
      <category>awslambda</category>
      <category>serverlesswebsite</category>
    </item>
    <item>
      <title>How to create an AWS Cross-Account Access? (A Step-by-Step Guide)</title>
      <dc:creator>Bachar Hakam </dc:creator>
      <pubDate>Thu, 10 Aug 2023 19:19:04 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-cross-account-access-a-step-by-step-guide-394e</link>
      <guid>https://dev.to/aws-builders/aws-cross-account-access-a-step-by-step-guide-394e</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%2Fflfol3bsj9o4biy0q04b.jpg" class="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%2Fflfol3bsj9o4biy0q04b.jpg" alt="Image description" width="611" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We usually use multiple accounts when configuring a new or existing AWS environment, which could require cross-account access between those accounts. We could use the AWS Resource Manager to share some resources between the accounts. Alternatively, we can create a cross-account role to be assumed by users in another account to access more resources with higher permissions.&lt;/p&gt;

&lt;p&gt;This article will demonstrate how to set up cross-account access between 2 accounts (Alice &amp;amp; Bob) using either AWS Management Console or CloudFormation stack. &lt;/p&gt;

&lt;h2&gt;
  
  
  Cross Account Setup
&lt;/h2&gt;

&lt;p&gt;Using the accounts Alice and Bob as an example, Bob requests administrator access to Alice's account.&lt;br&gt;
To begin, we'll create an Administrator role for account Alice that account Bob will use. The next step is to switch to account Bob so that user Bob can set up an inline policy allowing them to take on this new role in account Alice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; It would be better to use a role with the least privilege permissions as per the best practice, but for the sack of simplicity we will use the Administrator access role policy in this article. In a real-world scenario, the policy should only have the necessary permissions for each user based on the use case.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Account Alice - Administrator Role
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option-1: Using AWS Management Console
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to The AWS IAM console inside Account Alice&lt;/li&gt;
&lt;li&gt;Create a new role &lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Another AWS account&lt;/strong&gt; then add Bob's account ID&lt;/li&gt;
&lt;li&gt;Attach the required policy, in this example "AdministratorAccess"&lt;/li&gt;
&lt;li&gt;Enter the name of the role "SwitchAccountBobAdminRole"&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Create role&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option-2: Using AWS CloudFormation stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Download the CloudFormation template &lt;a href="https://d1dnaq25q27r0t.cloudfront.net/CrossAccountRole-admin.yaml" rel="noopener noreferrer"&gt;CrossAccountRole-admin.yaml&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Edit the template to update the &lt;strong&gt;Default&lt;/strong&gt; value of the &lt;strong&gt;AccessToAccountId&lt;/strong&gt; under &lt;strong&gt;Parameters&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;Replace &lt;strong&gt;ACCOUNT-B-ID&lt;/strong&gt; with an actual AWS account ID "in this case account Bob"
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Default: 'ACCOUNT-B-ID'&lt;/code&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS CloudFormation console&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create stack&lt;/strong&gt; (Standard)&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Upload a template file&lt;/strong&gt; then upload the updated template and click &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Type the &lt;strong&gt;Stack name&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Review the stack, select &lt;strong&gt;I acknowledge that AWS CloudFormation might create IAM resources.&lt;/strong&gt; then click on &lt;strong&gt;submit&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 2: Account Bob - Assume Role Policy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option-1: Using AWS Management Console
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS IAM console&lt;/li&gt;
&lt;li&gt;Select Policy then create a new policy &lt;/li&gt;
&lt;li&gt;use the following json policy and change the relevant details (role ARN created previously)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::&amp;lt;AlicAccount-id&amp;gt;:&amp;lt;RoleName&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Enter the name of the policy "Alice-Account-AssumeRole"&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Create policy&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Attach the policy to user Bob&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option-2: Using AWS CloudFormation stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Download the CloudFormation template &lt;a href="https://d1dnaq25q27r0t.cloudfront.net/AssumeRolePolicy-Bob.yaml" rel="noopener noreferrer"&gt;AssumeRolePolicy-Bob.yaml&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Edit the template to update the following values

&lt;ul&gt;
&lt;li&gt;Rename the policy name as required
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;PolicyName: BobAssumeRoleFromAccountAlice&lt;/code&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;strong&gt;ACCOUNT-ALICE-ID&lt;/strong&gt; with an actual account ID
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Resource: arn:aws:iam::ACCOUNT-ALICE-ID:role/CrossAccountAdminRole&lt;/code&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Replace &lt;strong&gt;Bob&lt;/strong&gt; with the actual username in the second account&lt;br&gt;&lt;br&gt;
&lt;code&gt;UserName: Bob&lt;/code&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS CloudFormation console&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create stack&lt;/strong&gt; (Standard)&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Upload a template file&lt;/strong&gt; then upload the updated template and click &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Type the &lt;strong&gt;Stack name&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Review the stack, select &lt;strong&gt;I acknowledge that AWS CloudFormation might create IAM resources.&lt;/strong&gt; then click on &lt;strong&gt;submit&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Test &amp;amp; Verify
&lt;/h2&gt;

&lt;p&gt;Now that the new role has been created in the first account (Account Alice) and you have attached the AssumeRole policy to the User inside the second account (Account Bob). You can verify that Bob can access Alice account by following these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to Account Bob&lt;/li&gt;
&lt;li&gt;Click on the account ID at the top right&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Switch role&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Type the account ID of the other account (Account Alice)&lt;/li&gt;
&lt;li&gt;Type the role name you have created in (Account Alice) "in this example we used CrossAccountAdminRole"&lt;/li&gt;
&lt;li&gt;Type the display name, chose a color then click &lt;strong&gt;Switch Role&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should be able to access the other account (Account Alice) successfully then return back to (Account Bob) by clicking on the account ID on the top right then select &lt;strong&gt;Switch back&lt;/strong&gt;&lt;/p&gt;




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

&lt;p&gt;To sum up, using AWS cross-account features helps different AWS accounts work together by sharing resources and access. This article showed how to do this with a simple example involving two accounts, Alice and Bob. By creating roles and policies, we made sure Bob could easily access and work in Alice's account. This approach makes it easier for different accounts to collaborate securely, which is important for complex setups in AWS.&lt;/p&gt;

</description>
      <category>cloudformation</category>
      <category>devops</category>
      <category>awscrossaccount</category>
      <category>shareawsaccount</category>
    </item>
  </channel>
</rss>
