<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Flask-Bank-Login]]></title><description><![CDATA[This project demonstrates how to build a secure login system using Flask and MySQL on AWS with a multi-tier architecture.]]></description><link>https://flask-bank-login.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 21 Sep 2026 00:28:08 GMT</lastBuildDate><atom:link href="https://flask-bank-login.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building a Secure Flask Login System with MySQL on AWS: A Bare-Bones Banking Application]]></title><description><![CDATA[Introduction
In this project, we’ll build a simple yet secure login system using Flask, a lightweight Python web framework, and MySQL as our database backend. The application architecture follows a best-practice AWS setup with a public-facing bastion...]]></description><link>https://flask-bank-login.hashnode.dev/building-a-secure-flask-login-system-with-mysql-on-aws-a-bare-bones-banking-application</link><guid isPermaLink="true">https://flask-bank-login.hashnode.dev/building-a-secure-flask-login-system-with-mysql-on-aws-a-bare-bones-banking-application</guid><category><![CDATA[#AWS  #EC2  #Flask  #Python  #MySQL  #Database  #CloudComputing  #DevOps  #AWSNetworking  #SecurityGroups  #WebDevelopment #CloudInfrastructure  #Linux  #Troubleshooting  #LearningExperience]]></category><dc:creator><![CDATA[Abhishek Balaji]]></dc:creator><pubDate>Wed, 27 Aug 2025 12:17:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756279052513/b9d4ce4d-f943-4337-8721-f2a43e6944d2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<h2 id="heading-in-this-project-well-build-a-simple-yet-secure-login-system-using-flask-a-lightweight-python-web-framework-and-mysql-as-our-database-backend-the-application-architecture-follows-a-best-practice-aws-setup-with-a-public-facing-bastion-host-running-the-flask-app-and-a-private-ec2-instance-hosting-the-mysql-database-this-multi-tier-setup-simulates-the-foundational-security-design-used-in-real-world-banking-applications-where-sensitive-data-is-isolated-in-private-subnets-and-only-accessible-through-controlled-channels">In this project, we’ll build a simple yet secure login system using Flask, a lightweight Python web framework, and MySQL as our database backend. The application architecture follows a best-practice AWS setup with a public-facing bastion host running the Flask app and a private EC2 instance hosting the MySQL database. This multi-tier setup simulates the foundational security design used in real-world banking applications, where sensitive data is isolated in private subnets and only accessible through controlled channels.</h2>
<p>Our Flask application will serve a login page where users can enter their credentials, which are then validated against the user data stored in the private MySQL database. By following this project, you will learn how to:</p>
<ul>
<li><p>Set up a secure AWS environment with public and private EC2 instances.</p>
</li>
<li><p>Install and configure MySQL in a private subnet.</p>
</li>
<li><p>Build a Flask web app that communicates with a remote database.</p>
</li>
<li><p>Implement basic user authentication.</p>
</li>
<li><p>Manage security groups to control access between instances.</p>
</li>
</ul>
<p>This project is perfect for beginners wanting to understand web application architecture, security best practices on AWS, and the basics of Flask and MySQL integration.</p>
<h2 id="heading-tools-required">Tools Required</h2>
<ul>
<li><p><strong>AWS Account</strong>: To launch EC2 instances and configure networking.</p>
</li>
<li><p><strong>EC2 Instances</strong>: One public instance (bastion host) and one private instance.</p>
</li>
<li><p><strong>Amazon VPC</strong>: With public and private subnets configured.</p>
</li>
<li><p><strong>Python 3</strong>: Installed on the public EC2 instance.</p>
</li>
<li><p><strong>Flask</strong>: Python web framework for building the login application.</p>
</li>
<li><p><strong>MySQL Server</strong>: Installed on the private EC2 instance to store user credentials.</p>
</li>
<li><p><strong>MySQL Client</strong>: For managing the MySQL database from command line.</p>
</li>
<li><p><strong>PyMySQL</strong>: Python package to enable Flask to connect to MySQL.</p>
</li>
<li><p><strong>Security Groups</strong>: Configured to allow traffic between the public and private instances securely.</p>
</li>
<li><p><strong>Basic Command Line Tools</strong>: ssh, apt-get, and text editors like nano or vim.</p>
</li>
</ul>
<h2 id="heading-setting-up-the-bastion-host-infrastructure">Setting Up the Bastion Host Infrastructure</h2>
<p>To build a secure multi-tier architecture on AWS, we start by creating a custom VPC with separate public and private subnets. This setup ensures your database server remains isolated and accessible only through the bastion host.</p>
<h3 id="heading-step-1-create-a-custom-vpc">Step 1: Create a Custom VPC</h3>
<ul>
<li><p>In the AWS Console, navigate to <strong>VPC</strong> and select <strong>Create VPC</strong>.</p>
</li>
<li><p>Define an IPv4 CIDR block (e.g., <code>10.0.0.0/16</code>) and give it a meaningful name (e.g., <code>MyCustomVPC</code>).</p>
</li>
</ul>
<h3 id="heading-step-2-create-subnets">Step 2: Create Subnets</h3>
<ul>
<li><p>Create two subnets within your VPC:</p>
<ul>
<li><p><strong>Public subnet</strong> (e.g., <code>10.0.1.0/24</code>) where the bastion host will reside.</p>
</li>
<li><p><strong>Private subnet</strong> (e.g., <code>10.0.2.0/24</code>) where the database server will reside.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-step-3-create-and-attach-an-internet-gateway-igw">Step 3: Create and Attach an Internet Gateway (IGW)</h3>
<ul>
<li><p>Create an Internet Gateway and attach it to your custom VPC.</p>
</li>
<li><p>This allows instances in the public subnet to access the internet.</p>
</li>
</ul>
<h3 id="heading-step-4-create-route-tables-and-associate-subnets">Step 4: Create Route Tables and Associate Subnets</h3>
<ul>
<li><p>Create a <strong>Public Route Table</strong>:</p>
<ul>
<li><p>Add a route with destination <code>0.0.0.0/0</code> and target as the Internet Gateway (IGW).</p>
</li>
<li><p>Associate the public subnet with this route table.</p>
</li>
</ul>
</li>
<li><p>Create a <strong>Private Route Table</strong>:</p>
<ul>
<li>Initially, it will have no routes to IGW, keeping the subnet private.</li>
</ul>
</li>
</ul>
<h3 id="heading-step-5-set-up-nat-gateway-for-private-subnet-internet-access">Step 5: Set Up NAT Gateway for Private Subnet Internet Access</h3>
<ul>
<li><p>Allocate an Elastic IP address for the NAT Gateway.</p>
</li>
<li><p>Create a NAT Gateway in the <strong>public subnet</strong>, assigning the Elastic IP.</p>
</li>
<li><p>Update the <strong>Private Route Table</strong>:</p>
<ul>
<li><p>Add a route with destination <code>0.0.0.0/0</code> and target as the NAT Gateway.</p>
</li>
<li><p>Associate the private subnet with this private route table.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-step-6-launch-ec2-instances">Step 6: Launch EC2 Instances</h3>
<ul>
<li><p>Launch a <strong>public EC2 instance</strong> (bastion host) in the public subnet with a public IP.</p>
</li>
<li><p>Launch a <strong>private EC2 instance</strong> (database server) in the private subnet <strong>without</strong> a public IP.</p>
</li>
</ul>
<h3 id="heading-step-7-configure-security-groups">Step 7: Configure Security Groups</h3>
<ul>
<li><p><strong>Public instance SG:</strong> Allow inbound SSH (port 22) from your IP and inbound HTTP (port 80) or Flask app port (e.g., 5000) from anywhere or your IP.</p>
</li>
<li><p><strong>Private instance SG:</strong> Allow inbound MySQL (port 3306) <strong>only</strong> from the security group of the public instance.</p>
</li>
</ul>
<hr />
<p>This completes your foundational AWS networking setup for a secure bastion host environment. The bastion host in the public subnet can communicate with the private database server securely, while the database remains inaccessible from the internet.</p>
<h3 id="heading-i-have-logged-into-my-aws-account-let-us-begin-building">I have logged into my AWS account. Let us begin building</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756279444618/b3cda362-6570-42cb-83b7-113ca62fc325.png" alt class="image--center mx-auto" /></p>
<p>Let's go ahead and create a custom virtual private network (VPC) and name it "Indian Bank VPC." In the search bar at the top, type "VPC" and select it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756279582790/9750a498-659d-4b63-ae89-021a54037e9c.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756279612766/c90beddd-2d6a-466a-9a71-19fd78437e09.png" alt class="image--center mx-auto" /></p>
<p>Click on create VPC button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756279791942/dc29e6d7-8ecc-4d37-a0f5-1640b9f3c6d2.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-creating-the-vpc-for-the-indian-bank-infrastructure">Creating the VPC for the Indian Bank Infrastructure</h2>
<p>To begin building our secure cloud environment, the first step is to create a custom Virtual Private Cloud (VPC). This VPC will act as the isolated network in which all our AWS resources — including EC2 instances and subnets — will reside.</p>
<h3 id="heading-vpc-configuration">VPC Configuration</h3>
<ul>
<li><p><strong>VPC Name</strong>: <code>Indian Bank VPC</code></p>
</li>
<li><p><strong>IPv4 CIDR Block</strong>: <code>11.0.0.0/16</code><br />  This provides a large address space of <strong>65,536 IP addresses</strong>, allowing ample room for subnetting and future scalability.</p>
</li>
<li><p><strong>Tenancy</strong>: Default<br />  We are using the default tenancy, which means EC2 instances will run on shared hardware. This is cost-effective and perfectly suitable for development and testing environments.</p>
</li>
<li><p><strong>Tags</strong>:<br />  Always apply meaningful tags when creating AWS resources. Tags improve the <strong>management, organization, and identification</strong> of resources, especially in projects involving multiple components. For example:</p>
<ul>
<li><p>Key: Name</p>
</li>
<li><p>Value: Indian-Bank-VPC</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-why-a-custom-vpc">Why a Custom VPC?</h3>
<p>Using a custom VPC allows for complete control over networking — including IP ranges, subnet placement, routing, and internet access. It’s a foundational best practice when building secure and scalable cloud applications.</p>
<p>With the VPC now created, the next step is to define public and private subnets to organize the network infrastructure for the bastion host and database server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756279980363/e0da2c50-04d0-4ce3-827d-38f7752d9609.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-for-the-indian-bank-vpc-i-chose-the-cidr-block-1100016-this-gives-me-a-total-of-65536-ip-addresses-which-is-more-than-sufficient-for-a-project-of-this-scale-it-allows-for-the-creation-of-up-to-256-24-subnets-each-with-251-usable-ips-after-aws-reservations">For the Indian Bank VPC, I chose the CIDR block <code>11.0.0.0/16</code>. This gives me a total of 65,536 IP addresses, which is more than sufficient for a project of this scale. It allows for the creation of up to 256 <code>/24</code> subnets, each with 251 usable IPs after AWS reservations.</h2>
<p>Click on create VPC button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756280033799/0a22558a-12f7-4bea-a7bb-3e950787224a.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756280061526/36a4e326-c160-4018-b404-4dbdcf34b860.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-creating-subnets-in-the-indian-bank-vpc-region-us-east-1">Creating Subnets in the Indian Bank VPC (Region: <code>us-east-1</code>)</h2>
<p>After creating your custom VPC, the next step is to define subnets to logically separate public-facing and internal resources. In this setup, we will create:</p>
<ul>
<li><p>A <strong>public subnet</strong> for the bastion host (Flask app server).</p>
</li>
<li><p>A <strong>private subnet</strong> for the MySQL database.</p>
</li>
</ul>
<p>By default, subnets in AWS are private unless you explicitly configure them to route through an Internet Gateway.</p>
<hr />
<h3 id="heading-step-1-create-two-subnets">🔧 Step 1: Create Two Subnets</h3>
<p>Go to <strong>VPC Dashboard → Subnets → Create Subnet</strong> and configure:</p>
<h4 id="heading-subnet-1-public-subnet">Subnet 1: Public Subnet</h4>
<ul>
<li><p><strong>Name tag</strong>: <code>IndianBank-Public-Subnet</code></p>
</li>
<li><p><strong>VPC</strong>: <code>Indian Bank VPC</code></p>
</li>
<li><p><strong>Availability Zone</strong>: <code>us-east-1a</code> (or any AZ of your choice in <code>us-east-1</code>)</p>
</li>
<li><p><strong>IPv4 CIDR block</strong>: <code>11.0.1.0/24</code></p>
</li>
</ul>
<h4 id="heading-subnet-2-private-subnet">Subnet 2: Private Subnet</h4>
<ul>
<li><p><strong>Name tag</strong>: <code>IndianBank-Private-Subnet</code></p>
</li>
<li><p><strong>VPC</strong>: <code>Indian Bank VPC</code></p>
</li>
<li><p><strong>Availability Zone</strong>: <code>us-east-1b</code> (for high availability)</p>
</li>
<li><p><strong>IPv4 CIDR block</strong>: <code>11.0.2.0/24</code></p>
</li>
</ul>
<p>Click <strong>Create Subnet</strong> to finish.</p>
<hr />
<h3 id="heading-reminder-subnets-are-private-by-default">⚠️ Reminder: Subnets Are Private by Default</h3>
<p>Without routing configuration, subnets can’t access the internet. Even if you launch an EC2 instance with a public IP, it won't work until you:</p>
<ul>
<li><p>Attach an <strong>Internet Gateway (IGW)</strong> to the VPC.</p>
</li>
<li><p>Associate a route table with a route pointing to the IGW.</p>
</li>
</ul>
<hr />
<h3 id="heading-step-2-convert-the-public-subnet-to-truly-public">🌐 Step 2: Convert the Public Subnet to Truly Public</h3>
<h4 id="heading-1-create-and-attach-an-internet-gateway-igw">1. <strong>Create and Attach an Internet Gateway (IGW)</strong></h4>
<ul>
<li><p>Go to <strong>VPC Dashboard → Internet Gateways → Create Internet Gateway</strong></p>
</li>
<li><p><strong>Name tag</strong>: <code>IndianBank-IGW</code></p>
</li>
<li><p>Create and <strong>attach it</strong> to <code>Indian Bank VPC</code></p>
</li>
</ul>
<h4 id="heading-2-create-public-route-table">2. <strong>Create Public Route Table</strong></h4>
<ul>
<li><p>Go to <strong>Route Tables → Create Route Table</strong></p>
</li>
<li><p><strong>Name tag</strong>: <code>IndianBank-Public-RT</code></p>
</li>
<li><p><strong>VPC</strong>: <code>Indian Bank VPC</code></p>
</li>
<li><p>Create the route table.</p>
</li>
</ul>
<h4 id="heading-3-edit-routes">3. <strong>Edit Routes</strong></h4>
<ul>
<li><p>Click into the route table → <strong>Routes → Edit routes</strong></p>
</li>
<li><p>Add:</p>
<ul>
<li><p><strong>Destination</strong>: <code>0.0.0.0/0</code></p>
</li>
<li><p><strong>Target</strong>: <code>Internet Gateway (IndianBank-IGW)</code></p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-4-associate-route-table-with-public-subnet">4. <strong>Associate Route Table with Public Subnet</strong></h4>
<ul>
<li><p>Go to the <strong>Subnet Associations</strong> tab</p>
</li>
<li><p>Click <strong>Edit subnet associations</strong></p>
</li>
<li><p>Select <code>IndianBank-Public-Subnet</code> and save.</p>
</li>
</ul>
<p>✅ Your <strong>public subnet is now truly public</strong>. EC2 instances launched here <strong>with auto-assign public IP enabled</strong> can access the internet.</p>
<h2 id="heading-click-on-create-subnet-button">Click on create subnet button</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756280339904/6bb036ff-a4dd-4574-a99a-7aa8e2339c5e.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756280369573/51161775-1343-4f17-93e4-c1ed5cd8046a.png" alt class="image--center mx-auto" /></p>
<p>To calculate the IPv4 subnet CIDR block, I will use a tool called the site IPv4 subnet calculator. Here is the link for your reference.</p>
<p><a target="_blank" href="https://www.site24x7.com/tools/ipv4-subnetcalculator.html">https://www.site24x7.com/tools/ipv4-subnetcalculator.html</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756280480842/16b80f0e-07af-41d1-b380-ad5596005b1f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-subnet-planning-and-cidr-allocation">Subnet Planning and CIDR Allocation</h2>
<p>In this project, we begin by <strong>defining a custom IPv4 CIDR block</strong> during the creation of our VPC. For the <code>Indian Bank VPC</code>, we chose:</p>
<ul>
<li><strong>CIDR Block</strong>: <code>11.0.0.0/16</code></li>
</ul>
<p>This provides <strong>65,536 total IP addresses</strong> (from <code>11.0.0.0</code> to <code>11.0.255.255</code>), which we can divide into smaller subnets as needed.</p>
<h3 id="heading-subnet-allocation-for-the-project">📌 Subnet Allocation for the Project</h3>
<p>For this project, we decided to create <strong>16 subnets</strong> to simulate a scalable, production-like environment. You can select the number of subnets directly in the AWS VPC wizard:</p>
<ul>
<li><p><strong>Number of subnets</strong>: <code>16</code></p>
</li>
<li><p><strong>CIDR Notation Enabled</strong>: ✅ (check the box to view or customize each subnet's CIDR)</p>
</li>
</ul>
<p>This setup automatically splits your <code>/16</code> block into 16 smaller <code>/20</code> subnets, each providing <strong>4,096 IP addresses</strong>.</p>
<hr />
<h3 id="heading-reserved-ip-addresses-in-each-subnet">🔐 Reserved IP Addresses in Each Subnet</h3>
<p>Within <strong>each subnet</strong>, AWS reserves <strong>5 IP addresses</strong> that cannot be used:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>IP Address</td><td>Purpose</td></tr>
</thead>
<tbody>
<tr>
<td><code>.0</code></td><td>Network address of the subnet</td></tr>
<tr>
<td><code>.1</code></td><td>Reserved by AWS for the VPC router</td></tr>
<tr>
<td><code>.2</code></td><td>Reserved by AWS for DNS in the subnet</td></tr>
<tr>
<td><code>.3</code></td><td>Reserved for future use by AWS</td></tr>
<tr>
<td><code>.255</code></td><td>Broadcast address of the subnet</td></tr>
</tbody>
</table>
</div><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756280736962/4532a293-09fc-441f-a405-158e6f17832a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-click-on-add-new-subnet-button">Click on add new subnet button</h3>
<h2 id="heading-creating-the-private-subnet-private-subnet-1b">Creating the Private Subnet: <code>private-subnet-1b</code></h2>
<p>After setting up the public subnet, the next step is to create a <strong>private subnet</strong> where the MySQL database server will reside. This subnet will be <strong>isolated from direct internet access</strong>, ensuring that sensitive components remain protected within the network.</p>
<h3 id="heading-step-by-step-create-private-subnet-1b">📌 Step-by-Step: Create <code>private-subnet-1b</code></h3>
<ol>
<li><p>Go to the <strong>VPC Dashboard → Subnets → Create Subnet</strong>.</p>
</li>
<li><p>Fill in the following details:</p>
<ul>
<li><p><strong>Name tag</strong>: <code>private-subnet-1b</code></p>
</li>
<li><p><strong>VPC ID</strong>: Select your custom VPC (<code>Indian Bank VPC</code>)</p>
</li>
<li><p><strong>Availability Zone</strong>: Select <code>us-east-1b</code> (to spread across AZs for high availability)</p>
</li>
<li><p><strong>IPv4 CIDR block</strong>:<br />  Use a non-overlapping subnet from your CIDR range (e.g., <code>11.0.2.0/24</code>)<br />  You can find this using a subnet calculator</p>
</li>
</ul>
</li>
<li><p>✅ This will provide <strong>256 IP addresses</strong>, with <strong>251 usable</strong> (after AWS reserves 5 IPs).</p>
</li>
<li><p>Click <strong>Create Subnet</strong>.</p>
</li>
</ol>
<hr />
<h3 id="heading-why-a-private-subnet">🔒 Why a Private Subnet?</h3>
<p>This subnet is intended for backend services such as a <strong>MySQL database</strong>, which should not be accessible directly from the internet. Instead, access is restricted to internal traffic — for example, only from the <strong>bastion host</strong> in the public subnet.</p>
<hr />
<h3 id="heading-example-of-reserved-ips-for-1102024">🔢 Example of Reserved IPs (for <code>11.0.2.0/24</code>)</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>IP Address</td><td>Reserved For</td></tr>
</thead>
<tbody>
<tr>
<td><code>11.0.2.0</code></td><td>Network Address</td></tr>
<tr>
<td><code>11.0.2.1</code></td><td>AWS VPC Router</td></tr>
<tr>
<td><code>11.0.2.2</code></td><td>AWS DNS</td></tr>
<tr>
<td><code>11.0.2.3</code></td><td>Reserved for future use</td></tr>
<tr>
<td><code>11.0.2.255</code></td><td>Broadcast Address</td></tr>
</tbody>
</table>
</div><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281045893/8f5cf97d-d91d-4206-9810-eaa4a57c6f66.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281064048/ccb66fa1-65dd-4615-bd59-876564c98f22.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-cidr-notation-field-quick-note"><strong>CIDR Notation Field – Quick Note:</strong></h3>
<p>The <strong>CIDR notation field</strong> helps define the IP range of your subnet and automatically calculates the <strong>host IDs</strong> — the usable IP addresses for your resources. For example, a subnet like <code>11.0.2.0/24</code> gives you 256 IPs, out of which <strong>251 are usable</strong>, as AWS reserves 5 IPs for networking functions (router, DNS, etc.). This field is essential for proper subnet planning and resource allocation.</p>
<p>Click on create subnet button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281209353/74709e63-074a-4914-b944-0890c1df1b7f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281228112/be68abb7-9e32-4502-ae16-d7fb18165990.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281290038/a54c4b90-d1df-4aa0-9b12-6baf36f0a0d0.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281309290/6f3b1d88-15d6-4929-86c7-32162f092c87.png" alt class="image--center mx-auto" /></p>
<p>Click on save button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281346235/e28cbe0a-9188-4449-976f-5ba359713cf4.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-how-to-convert-a-subnet-into-a-public-subnet-in-aws">🔧 How to Convert a Subnet into a Public Subnet in AWS</h2>
<p>By default, all newly created subnets in AWS are <strong>private</strong> — they do <strong>not</strong> assign public IPs to EC2 instances. To make a subnet public, you must enable <strong>auto-assign public IPv4 addresses</strong>.</p>
<p>Here are the steps to convert a specific subnet into a public one:</p>
<hr />
<h3 id="heading-step-by-step-instructions">✅ Step-by-Step Instructions:</h3>
<ol>
<li><p><strong>Go to the AWS Management Console</strong><br /> Navigate to the <strong>VPC Dashboard</strong>.</p>
</li>
<li><p><strong>Click on Subnets</strong><br /> In the left-hand menu, choose <strong>Subnets</strong>.</p>
</li>
<li><p><strong>Select the Subnet to Convert</strong><br /> Find the subnet you want to make public — for example:<br /> <code>IndianBank-Public-Subnet (11.0.1.0/24)</code><br /> Click the <strong>checkbox</strong> next to it.</p>
</li>
<li><p><strong>Click on the “Actions” Button</strong><br /> At the top of the Subnets table, click <strong>Actions</strong> → select <strong>Edit subnet settings</strong>.</p>
</li>
<li><p><strong>Enable Auto-Assign Public IPv4 Address</strong><br /> In the configuration panel, <strong>check the box</strong>:<br /> ✅ <strong>Enable auto-assign public IPv4 address</strong></p>
</li>
<li><p><strong>Click Save Changes</strong><br /> This will apply the new setting immediately.</p>
</li>
<li><p><strong>Verify the Setting</strong></p>
<ul>
<li><p>Scroll down to the <strong>Subnet details</strong> panel.</p>
</li>
<li><p>Under <strong>Auto-assign public IPv4 address</strong>, it should now say: <strong>Yes</strong></p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281534038/7f6bd007-e7c7-40d6-9320-6be92751d247.png" alt class="image--center mx-auto" /></p>
<p>Click on create internet gateway button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281574388/c95aa014-9c83-4f7a-b417-67e26266e896.png" alt class="image--center mx-auto" /></p>
<p>Provide the name for your Internet Gateway. Tags will be assigned automatically by AWS. Click on the create Internet gateway button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281643194/5ddee89a-d10d-4679-8f80-546c1c6ee1a4.png" alt class="image--center mx-auto" /></p>
<p>It is in a detached state, as you can see in the above screenshot. We now need to attach this IGW to our custom VPC.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281706089/38bedfe5-6b14-4c12-acce-3f5e7e11b0d7.png" alt class="image--center mx-auto" /></p>
<p>Click on the Actions button → Select the Attach to a VPC option.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281770899/aba50edd-8934-4da2-a53a-418b5fc789ff.png" alt class="image--center mx-auto" /></p>
<p>Choose your custom VPC from the drop-down menu provided. Click on the "Attach Internet Gateway" button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281824279/ce9c61e8-5425-4023-a81f-ebd58a1f2832.png" alt class="image--center mx-auto" /></p>
<p>Now, click on "Route Tables" on the left side.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756281991233/2b66739b-aa1e-48f6-a825-ea94c60ee801.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-note-when-you-create-a-custom-vpc-aws-automatically-creates-a-default-route-table-for-it-this-route-table">Note: When you create a <strong>custom VPC</strong>, AWS automatically creates a <strong>default route table</strong> for it. This route table:</h3>
<ul>
<li><h3 id="heading-has-no-name-tag-youll-often-see-it-as-under-the-name-column">Has <strong>no name tag</strong> (you'll often see it as <code>-</code> under the Name column)</h3>
</li>
<li><h3 id="heading-is-automatically-associated-with-all-subnets-unless-you-manually-associate-them-with-a-different-route-table">Is automatically <strong>associated with all subnets</strong> unless you manually associate them with a different route table</h3>
</li>
<li><h3 id="heading-is-completely-usable-and-editable-you-can-rename-it-add-routes-or-leave-it-as-is">Is completely usable and editable — you can rename it, add routes, or leave it as is</h3>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282082943/bc4f0036-54fc-47c0-8bec-1d9521775601.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-configuring-the-public-route-table-for-internet-access">Configuring the Public Route Table for Internet Access</h2>
<p>Once your VPC and subnets are created, the next crucial step is to configure a <strong>route table</strong> to enable internet connectivity for your public subnet. AWS automatically creates a default route table when you create a custom VPC, but it often lacks a descriptive name and proper routes. We will rename this route table and configure it to serve as the <strong>public route table</strong> for our project.</p>
<h3 id="heading-step-1-rename-the-default-route-table">Step 1: Rename the Default Route Table</h3>
<ol>
<li><p>Navigate to the <strong>AWS VPC Console</strong> and click on <strong>Route Tables</strong> in the left-hand menu.</p>
</li>
<li><p>Locate the default route table created by AWS for your VPC. This table might appear without a name or be shown as “-” in the Name column.</p>
</li>
<li><p>Select this route table and click the <strong>Actions</strong> menu or directly edit the tags.</p>
</li>
<li><p>Add a new <strong>Name</strong> tag with the value:</p>
<p> This helps clearly identify the route table’s purpose within your infrastructure.</p>
</li>
</ol>
<h3 id="heading-step-2-add-a-route-to-the-internet-gateway-igw">Step 2: Add a Route to the Internet Gateway (IGW)</h3>
<ol>
<li><p>With the <code>public-route-table</code> selected, switch to the <strong>Routes</strong> tab.</p>
</li>
<li><p>Click on the <strong>Edit routes</strong> button to modify the routing rules.</p>
</li>
<li><p>Click <strong>Add route</strong> to define a new route.</p>
</li>
<li><p>In the <strong>Destination</strong> field, enter:</p>
</li>
<li><pre><code class="lang-plaintext"> 0.0.0.0/0
</code></pre>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282155359/5326e56a-b1c2-401e-8ab2-e6b037914b38.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>This route signifies that all IPv4 traffic destined for external networks (the internet) should be routed accordingly.</p>
</li>
<li><p>In the <strong>Target</strong> field, select your <strong>Internet Gateway</strong> from the dropdown menu, which should be labeled something like <code>Indian Bank IGW</code>.</p>
</li>
<li><p>After confirming the details, click <strong>Save routes</strong> to apply the changes.</p>
</li>
</ol>
<h3 id="heading-step-3-associate-the-public-subnet-with-the-public-route-table">Step 3: Associate the Public Subnet with the Public Route Table</h3>
<ol>
<li><p>Navigate to the <strong>Subnet Associations</strong> tab within the same route table view.</p>
</li>
<li><p>Click <strong>Edit subnet associations</strong> to manage which subnets use this route table.</p>
</li>
<li><p>From the list of available subnets, select your <strong>public subnet</strong> — in this case, <code>public-subnet-1a</code>.</p>
</li>
<li><p>Click <strong>Save associations</strong> to finalize the linkage.</p>
</li>
</ol>
<hr />
<h3 id="heading-outcome">Outcome</h3>
<p>By completing these steps, you have effectively:</p>
<ul>
<li><p>Renamed your default route table to <code>public-route-table</code> for clarity.</p>
</li>
<li><p>Added a route that directs all internet-bound traffic (<code>0.0.0.0/0</code>) through your VPC’s Internet Gateway (<code>Indian Bank IGW</code>).</p>
</li>
<li><p>Associated the <code>public-subnet-1a</code> with this route table, thereby designating it as a <strong>public subnet</strong>.</p>
</li>
</ul>
<p>Instances launched within this subnet will now be able to communicate with the internet, provided that their security groups and network ACLs allow the required traffic.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282202710/0c0995c0-a6dc-4617-a574-1c6f242dd58c.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282225095/e770cfd9-2074-4202-a957-e72c71761222.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282249665/07dfbae7-a1a5-4b1b-b0a8-357587131051.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282266058/fda9f0be-e581-482c-aa7d-0c35e058b87f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282290581/16e2be39-6216-437d-b7c8-00a015435b72.png" alt class="image--center mx-auto" /></p>
<p>Here is what the resource map looks like so far:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282727804/b3753c6a-4d06-4b60-b17d-487c2d1eb16d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756282825923/6e56a590-1014-4336-8715-4584a4b25aec.png" alt class="image--center mx-auto" /></p>
<p>Now, we will create two security groups: one for the public EC2 instance, which acts as the bank web application server, and another for the private EC2 instance, which acts as the database server.</p>
<p>Click on create security group</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756283004729/4e1e72c3-1d38-4897-9051-8cd951aec8d9.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756283050330/4678bf21-2d20-43a0-a58d-b5b857f08e25.png" alt class="image--center mx-auto" /></p>
<p>Click on create security group button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756283101152/b689b4a3-8871-4029-be18-e9f39375f90f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756283525870/0efa8c9f-77df-4b7e-a22b-0cb47b6055ca.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-creating-a-security-group-for-public-instances">Creating a Security Group for Public Instances</h2>
<p>To securely manage inbound and outbound traffic for your public EC2 instances, you need to create a dedicated <strong>security group</strong>. This acts as a virtual firewall controlling the traffic allowed to and from your instances.</p>
<h3 id="heading-step-1-define-the-security-group">Step 1: Define the Security Group</h3>
<ol>
<li><p>In the <strong>AWS Management Console</strong>, navigate to the <strong>VPC</strong> service.</p>
</li>
<li><p>From the left-hand menu, click on <strong>Security Groups</strong>.</p>
</li>
<li><p>Click the <strong>Create security group</strong> button to start the process.</p>
</li>
<li><p>Provide the following details:</p>
<ul>
<li><p><strong>Security group name:</strong><br />  <code>Indian-Bank-Public-Instances-SG</code><br />  <em>(This name clearly indicates that this security group is for public-facing instances in the Indian Bank project.)</em></p>
</li>
<li><p><strong>Description:</strong><br />  <code>Security group for public EC2 instances allowing SSH and HTTP access</code><br />  <em>(A descriptive note that helps clarify the purpose of this security group for future reference.)</em></p>
</li>
<li><p><strong>VPC:</strong><br />  Select your custom VPC, <code>Indian-Bank-VPC</code>, from the dropdown menu to ensure the security group is associated with the correct network.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-step-2-configure-inbound-rules">Step 2: Configure Inbound Rules</h3>
<p>You will now define rules to permit inbound traffic essential for managing and accessing your public instances:</p>
<ul>
<li><p><strong>Inbound Rule 1: SSH Access</strong></p>
<ul>
<li><p><strong>Type:</strong> SSH</p>
</li>
<li><p><strong>Protocol:</strong> TCP</p>
</li>
<li><p><strong>Port Range:</strong> 22</p>
</li>
<li><p><strong>Source:</strong> Anywhere (IPv4)</p>
</li>
<li><p><strong>Source CIDR:</strong> <code>0.0.0.0/0</code><br />  <em>(Allows SSH access from any IPv4 address — useful for remote management via terminal.)</em></p>
</li>
</ul>
</li>
<li><p><strong>Inbound Rule 2: HTTP Access</strong></p>
<ul>
<li><p><strong>Type:</strong> HTTP</p>
</li>
<li><p><strong>Protocol:</strong> TCP</p>
</li>
<li><p><strong>Port Range:</strong> 80</p>
</li>
<li><p><strong>Source:</strong> Anywhere (IPv4)</p>
</li>
<li><p><strong>Source CIDR:</strong> <code>0.0.0.0/0</code><br />  <em>(Allows web traffic to your Flask application or any web server running on port 80.)</em></p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-step-3-leave-outbound-rules-as-default">Step 3: Leave Outbound Rules as Default</h3>
<p>By default, security groups in AWS are <strong>stateful</strong>, meaning that <strong>outbound traffic is automatically allowed</strong> in response to inbound traffic. Hence, you can safely leave the outbound rule set as default, which allows all outbound traffic.</p>
<h3 id="heading-step-4-add-tags-for-identification">Step 4: Add Tags for Identification</h3>
<p>Adding tags helps in organizing and managing your AWS resources efficiently:</p>
<ul>
<li><p>Click on <strong>Add tag</strong></p>
</li>
<li><p>Add key-value pairs such as:</p>
<ul>
<li><p><strong>Key:</strong> <code>Project</code></p>
</li>
<li><p><strong>Value:</strong> <code>Indian-Bank</code></p>
</li>
<li><p><strong>Key:</strong> <code>Environment</code></p>
</li>
<li><p><strong>Value:</strong> <code>Production</code> <em>(or</em> <code>Development</code> as applicable)</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-step-5-create-the-security-group">Step 5: Create the Security Group</h3>
<ul>
<li>Once all the above configurations are done, click the <strong>Create security group</strong> button.</li>
</ul>
<hr />
<h3 id="heading-outcome-1">Outcome</h3>
<p>You have now created a security group named <strong>Indian-Bank-Public-Instances-SG</strong> that allows secure SSH access from anywhere and serves web traffic on HTTP port 80. This security group will be attached to your public EC2 instances to control their network access securely.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756283721287/046e0deb-5ba0-4b8a-9f59-2c5f4e2f85ce.png" alt class="image--center mx-auto" /></p>
<p>Click on create security group button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756283860413/6483029a-e040-4ce0-b592-91985e3f4ac6.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756283876092/a997c612-0502-4c3e-b987-9761e9dade86.png" alt class="image--center mx-auto" /></p>
<p>Click on create security group button</p>
<h2 id="heading-creating-a-security-group-for-the-private-database-instance">Creating a Security Group for the Private Database Instance</h2>
<p>To secure your private database instance while allowing controlled access only from your public instances, you need to create a dedicated security group with specific inbound rules.</p>
<h3 id="heading-step-1-define-the-security-group-1">Step 1: Define the Security Group</h3>
<ol>
<li><p>In the <strong>AWS Management Console</strong>, navigate to the <strong>VPC</strong> service.</p>
</li>
<li><p>Click on <strong>Security Groups</strong> in the left-hand menu.</p>
</li>
<li><p>Click the <strong>Create security group</strong> button.</p>
</li>
<li><p>Provide the following details:</p>
<ul>
<li><p><strong>Security group name:</strong><br />  <code>Indian-Bank-Private-Database-Instance-SG</code><br />  <em>(Clearly identifies this security group for private database instances.)</em></p>
</li>
<li><p><strong>Description:</strong><br />  <code>Allows SSH and MySQL traffic only from public instances security group</code><br />  <em>(Clarifies that this group restricts access exclusively to public instance sources.)</em></p>
</li>
<li><p><strong>VPC:</strong><br />  Select your custom VPC: <code>Indian-Bank-VPC</code>.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-step-2-configure-inbound-rules-1">Step 2: Configure Inbound Rules</h3>
<p>Add two inbound rules that limit access strictly to your public instance security group:</p>
<ul>
<li><p><strong>Inbound Rule 1: SSH Access from Public Instances</strong></p>
<ul>
<li><p><strong>Type:</strong> SSH</p>
</li>
<li><p><strong>Protocol:</strong> TCP</p>
</li>
<li><p><strong>Port Range:</strong> 22</p>
</li>
<li><p><strong>Source:</strong> Custom</p>
</li>
<li><p><strong>Source security group:</strong> <code>Indian-Bank-Public-Instances-SG</code><br />  <em>(Allows SSH access only from instances associated with the public instances security group.)</em></p>
</li>
</ul>
</li>
<li><p><strong>Inbound Rule 2: MySQL Access from Public Instances</strong></p>
<ul>
<li><p><strong>Type:</strong> Custom TCP</p>
</li>
<li><p><strong>Protocol:</strong> TCP</p>
</li>
<li><p><strong>Port Range:</strong> 3306</p>
</li>
<li><p><strong>Source:</strong> Custom</p>
</li>
<li><p><strong>Source security group:</strong> <code>Indian-Bank-Public-Instances-SG</code><br />  <em>(Allows MySQL database connections exclusively from the public instances security group.)</em></p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-step-3-leave-outbound-rules-as-default-1">Step 3: Leave Outbound Rules as Default</h3>
<p>The outbound rules should remain unchanged. Since AWS security groups are <strong>stateful</strong>, responses to allowed inbound traffic will automatically be permitted outbound.</p>
<h3 id="heading-step-4-add-tags-for-easy-identification">Step 4: Add Tags for Easy Identification</h3>
<p>To manage your AWS resources effectively, add relevant tags such as:</p>
<ul>
<li><p><strong>Key:</strong> <code>Project</code></p>
</li>
<li><p><strong>Value:</strong> <code>Indian-Bank</code></p>
</li>
<li><p><strong>Key:</strong> <code>Environment</code></p>
</li>
<li><p><strong>Value:</strong> <code>Production</code> (or <code>Development</code> as applicable)</p>
</li>
</ul>
<h3 id="heading-step-5-create-the-security-group-1">Step 5: Create the Security Group</h3>
<p>After verifying all the settings, click the <strong>Create security group</strong> button.</p>
<hr />
<h3 id="heading-outcome-2">Outcome</h3>
<p>This security group, <strong>Indian-Bank-Private-Database-Instance-SG</strong>, tightly controls access to your private database instance by allowing only SSH and MySQL traffic originating from your public EC2 instances. This setup enhances security by preventing unwanted external access to your database server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756284161914/d6ef1989-31bc-428c-82b7-fdd9c22d6801.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756284263694/bde47ab7-de74-419a-b4cb-89697d999f83.png" alt class="image--center mx-auto" /></p>
<p>Search for EC2 in the search bar and click on it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756284301978/6b482e05-55f9-4f49-8c66-b746f03ec0bf.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-launching-ec2-instances-in-public-and-private-subnets">Launching EC2 Instances in Public and Private Subnets</h2>
<h3 id="heading-step-1-create-a-key-pair-named-ec2-kp-27-augpem">Step 1: Create a Key Pair Named "EC2-KP-27-AUG.pem"</h3>
<p>Before launching your EC2 instances, you need a key pair to securely SSH into them.</p>
<ol>
<li><p>In the <strong>AWS Management Console</strong>, navigate to the <strong>EC2 Dashboard</strong>.</p>
</li>
<li><p>On the left sidebar, click <strong>Key Pairs</strong> under <strong>Network &amp; Security</strong>.</p>
</li>
<li><p>Click the <strong>Create Key Pair</strong> button.</p>
</li>
<li><p>Provide the following details:</p>
<ul>
<li><p><strong>Key pair name:</strong> <code>EC2-KP-27-AUG</code></p>
</li>
<li><p><strong>Key pair type:</strong> RSA (default)</p>
</li>
<li><p><strong>Private key file format:</strong> <code>.pem</code> (for Linux/Mac/Unix or Windows with WSL)</p>
</li>
</ul>
</li>
<li><p>Click <strong>Create Key Pair</strong>.</p>
</li>
<li><p>The private key file named <strong>EC2-KP-27-AUG.pem</strong> will automatically download to your local machine.</p>
</li>
<li><p><strong>Important:</strong> Store this file securely. Set the correct permissions using:</p>
</li>
<li><pre><code class="lang-plaintext"> chmod 400 EC2-KP-27-AUG.pem
</code></pre>
</li>
</ol>
<p>This key will be required to SSH into your instances.</p>
<h3 id="heading-step-2-launch-the-public-ec2-instance-bastion-host-flask-app-server">Step 2: Launch the Public EC2 Instance (Bastion Host / Flask App Server)</h3>
<ol>
<li><p>Go to the <strong>EC2 Dashboard</strong> and click <strong>Launch Instance</strong>.</p>
</li>
<li><p>Choose your preferred <strong>AMI</strong> (Amazon Linux 2 or Ubuntu).</p>
</li>
<li><p>Select an <strong>Instance Type</strong> like <code>t2.micro</code> (free tier eligible).</p>
</li>
<li><p>Under <strong>Configure Instance Details:</strong></p>
<ul>
<li><p><strong>Network:</strong> Select <code>Indian-Bank-VPC</code>.</p>
</li>
<li><p><strong>Subnet:</strong> Choose the <strong>public subnet (1a)</strong>.</p>
</li>
<li><p><strong>Auto-assign Public IP:</strong> Enable this so the instance gets a public IP.</p>
</li>
</ul>
</li>
<li><p>Add storage as needed.</p>
</li>
<li><p>Add tags such as:</p>
<ul>
<li><p><code>Name: Indian-Bank-Public-Instance</code></p>
</li>
<li><p><code>Project: Indian-Bank</code></p>
</li>
</ul>
</li>
<li><p>In <strong>Configure Security Group</strong>, select the existing security group <code>Indian-Bank-Public-Instances-SG</code>.</p>
</li>
<li><p>On the <strong>Review and Launch</strong> page, <strong>select the key pair</strong> named <code>EC2-KP-27-AUG</code> from the dropdown under "Key pair".</p>
</li>
<li><p>Launch the instance.</p>
</li>
</ol>
<hr />
<h3 id="heading-step-3-launch-the-private-ec2-instance-mysql-database-server">Step 3: Launch the Private EC2 Instance (MySQL Database Server)</h3>
<ol>
<li><p>Click <strong>Launch Instance</strong> again in the EC2 Dashboard.</p>
</li>
<li><p>Choose the same or appropriate <strong>AMI</strong>.</p>
</li>
<li><p>Select the instance type (e.g., <code>t2.micro</code>).</p>
</li>
<li><p>Configure instance details:</p>
<ul>
<li><p><strong>Network:</strong> <code>Indian-Bank-VPC</code></p>
</li>
<li><p><strong>Subnet:</strong> Choose the <strong>private subnet (1b)</strong></p>
</li>
<li><p><strong>Auto-assign Public IP:</strong> <strong>Disable</strong> this (keep instance private).</p>
</li>
</ul>
</li>
<li><p>Add tags such as:</p>
<ul>
<li><p><code>Name: Indian-Bank-Private-Database-Instance</code></p>
</li>
<li><p><code>Project: Indian-Bank</code></p>
</li>
</ul>
</li>
<li><p>Select the security group <code>Indian-Bank-Private-Database-Instance-SG</code>.</p>
</li>
<li><p>On the <strong>Review and Launch</strong> page, <strong>select the key pair</strong> <code>EC2-KP-27-AUG</code>.</p>
</li>
<li><p>Launch the instance.</p>
</li>
</ol>
<hr />
<h3 id="heading-summary">Summary</h3>
<ul>
<li><p>You now have a key pair <code>EC2-KP-27-AUG.pem</code> that you will use to securely access your instances.</p>
</li>
<li><p>Your <strong>public instance</strong> will be reachable via the internet.</p>
</li>
<li><p>Your <strong>private instance</strong> will remain isolated, accessible only through your public instance (bastion host).</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756284528963/b94a0046-3003-480a-bad5-dba58646afce.png" alt class="image--center mx-auto" /></p>
<p>Click on create key pair button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756284577773/8bdc8439-9248-446d-9dee-d52496c4529a.png" alt class="image--center mx-auto" /></p>
<p>Provide the key pair name, set the key pair type to RSA, and choose the private key pair file format as .pem since we are using Linux OS. Add tags for easier identification and management of your AWS resources. Click on "Create key pair."</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756284686962/b763a958-d8fc-47d2-b6eb-42a7a45ea9a0.png" alt class="image--center mx-auto" /></p>
<p>Back to EC2 instances</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756284723192/28ac66c2-8178-4677-87b4-2333508d9015.png" alt class="image--center mx-auto" /></p>
<p>Click the "Launch Instances" button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756287618306/fe7ac656-49fb-43e8-951b-8a0a24430ebb.png" alt class="image--center mx-auto" /></p>
<p>Provide the name of your public EC2 instance. Select the AMI as “Ubuntu”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756287689685/1c465498-dc44-47ca-aeb2-29a5b122135c.png" alt class="image--center mx-auto" /></p>
<p>Select the instance type as “t2.micro” for this project. Select your key pair as well “EC2-KP-27-AUG.pem”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756287849558/ecfc8c12-dc6e-49ed-85b2-c5c5ee9f1a73.png" alt class="image--center mx-auto" /></p>
<p>Select your custom VPC “Indian-Bank-VPC”, Select your public -subnet-1a, Choose your existing “Indian-Bank-Public-Instances-SG” security group.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756287919445/e012d5bf-a051-4521-a4d6-7428b5523a26.png" alt class="image--center mx-auto" /></p>
<p>Leave the storage configuration to default settings.</p>
<p>Click on “Launch Instances” button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756287964042/85ae4f4a-c429-4c99-a3c9-3e370cc7e1ea.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756287976473/691ad8f2-f3e2-4988-ac79-a8a5fe23adab.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288068427/0d0a5bb2-faae-49b1-be47-46fc77e3cd9e.png" alt class="image--center mx-auto" /></p>
<p>Let's repeat the same steps to create a private EC2 database instance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288097504/1d33eef1-9aba-486b-8c38-034b9eeb927a.png" alt class="image--center mx-auto" /></p>
<p>Provide the name of your EC2 instance as “private-EC2-database-instance.” Next, choose the AMI as “Ubuntu.”</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288163987/f47f4375-11bc-4c8b-971b-bc8b947b5ffd.png" alt class="image--center mx-auto" /></p>
<p>Select the instance type as “t2.micro” and choose the key pair as “EC2-KP-27-AUG.pem”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288253395/be315383-20e0-433c-a1ea-2f2b1b6c32e7.png" alt class="image--center mx-auto" /></p>
<p>Click on "Edit VPC Configuration." Select your custom VPC, "Indian-Bank-VPC." Choose your subnet, "private-subnet-1b." Select the existing security group, "Indian-Bank-Private-Database-instance-SG." Leave the storage configurations at the default settings.</p>
<p>Click on the "Launch Instance" button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288402275/9b2c8d37-1ed6-4a4b-898d-3b42fb5849d4.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288416763/e862e092-413d-4e28-9013-76edd0fa44de.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288440066/d091fbee-2fa1-4658-b122-cfbcc8f8443c.png" alt class="image--center mx-auto" /></p>
<p>Let's set up an internet connection for our private EC2 database instance using a NAT gateway.</p>
<p>Note: The NAT gateway uses an elastic IP, which is not available under the free tier. Caution: You will incur charges. After the project demonstration, remember to disconnect the elastic IP from the NAT gateway.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288593498/101b944f-7cc4-486a-8cf3-fbabc8eefc52.png" alt class="image--center mx-auto" /></p>
<p>On the left-hand side, select "NAT Gateway."</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288633167/efe88273-44af-4669-be29-32000db7f8ae.png" alt class="image--center mx-auto" /></p>
<p>But before that, let's create an elastic IP first. It's easier to attach it during the creation of the NAT gateway.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288756566/06ef3a95-68c3-411d-a5b0-3a5f6a6c56ea.png" alt class="image--center mx-auto" /></p>
<p>Click on “allocate elastic IP” button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288796657/ed7e394e-c7f0-4a7c-8f61-49e10b794b09.png" alt class="image--center mx-auto" /></p>
<p>In this configuration, you only need to provide the tags. Click on the “Allocate” button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288863993/b57d8740-6aec-4315-964b-d607f1aa492b.png" alt class="image--center mx-auto" /></p>
<p>Now, back to your NAT gateway page</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288889664/517dd799-5c07-4590-b08e-82db8d29c32f.png" alt class="image--center mx-auto" /></p>
<p>Click on “Create NAT gateway” button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756288953585/167dca55-e53d-41cd-91d1-395670aea34f.png" alt class="image--center mx-auto" /></p>
<p>In this configuration tab, enter the name of your NAT gateway as “Indian-Bank-NAT-GW” and choose your public subnet, "public-subnet-1a."</p>
<p>Note: NAT gateways must be deployed in the public subnet only.</p>
<p>Select your recently created elastic IP from the dropdown menu. Add tags for easier identification and management of your AWS resources.</p>
<p>Click on the “Create NAT gateway” button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289090307/eca328ea-3caf-4e2a-87e2-1f92a356b1d4.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289197309/44372c32-c028-4b15-b93e-b311388487e0.png" alt class="image--center mx-auto" /></p>
<p>Done.</p>
<p>Let's create a private route table for my private-subnet-1b.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289669411/ef838214-1e55-4400-8743-90ba737e421e.png" alt class="image--center mx-auto" /></p>
<p>Click on “create route table” button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289719605/bf9bc260-9ce7-49ac-88b3-acb894c460b8.png" alt class="image--center mx-auto" /></p>
<p>Provide the name for your private route table, select your custom VPC - “Indian-Bank-VPC,” and add tags for easier identification and management of your AWS resources.</p>
<p>Click on the “Create route table” button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289807696/24a1b962-22b8-4426-a7ed-8ee13aa6f610.png" alt class="image--center mx-auto" /></p>
<p>Click on routes tab → Select “edit routes” button</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289858793/da8689ff-81e6-46bf-bdf8-d40d375bf582.png" alt class="image--center mx-auto" /></p>
<p>Provide the destination as 0.0.0.0/0 and set the target as the NAT gateway. Select your NAT gateway (Indian-Bank-NAT-GW) from the list below.</p>
<p>Click on "Save changes."</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289947334/ae97b285-1d30-4df7-8f75-035b51d0f1a6.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289965193/e01ba175-241c-4d06-9314-49f6e0436155.png" alt class="image--center mx-auto" /></p>
<p>In the subnet associations tab, click on the “Edit Subnet Association” button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290018812/f95b8ded-9e72-4578-a0b1-2cf8a96da12c.png" alt class="image--center mx-auto" /></p>
<p>Choose your private subnets (private-subnet-1b). Click on the “Save associations” button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290114255/b548f3c2-1157-4110-9f37-24ed14d68f75.png" alt class="image--center mx-auto" /></p>
<p>Done</p>
<p>Now, let's give read-only permissions to the key-pair in the downloads folder. Open the terminal and navigate to your key-pair.pem file (for example, EC2-KP-27-AUG.pem in my case).</p>
<p>Use this command to set read-only permissions for the user only.</p>
<pre><code class="lang-plaintext">sudo chmod 400 EC2-KP-27-AUG.pem
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756289376225/59b38909-1047-4a72-b63c-09a0e0571c6d.png" alt class="image--center mx-auto" /></p>
<p>I have successfully set read-only permissions for the user, with no permissions for the group or others.</p>
<p>Let's use the <code>scp</code> command to upload your <code>key-pair.pem</code> file from my local machine to my <code>public-EC2-web-app-instance</code>. Access your <code>public-EC2-web-app-instance</code> via SSH, and then use the <code>scp</code> command to upload your <code>key-pair.pem</code> file to your <code>private-EC2-database-instance</code>. Perform ping operations to check if the internet connection is configured properly.</p>
<p>Perform SCP upload of key-pair.pem file from local machine to your public-EC2-instance.</p>
<h2 id="heading-scp-command">SCP command</h2>
<pre><code class="lang-plaintext">scp -i EC2-KP-27-AUG.pem EC2-KP-27-AUG.pem ubuntu@44.223.103.94:/home/ubuntu
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290374253/87971ce9-af81-4fce-9ded-60a4eb367339.png" alt class="image--center mx-auto" /></p>
<p>Upload of key-pair.pem file successful</p>
<p>Perform SSH login using the command</p>
<pre><code class="lang-plaintext">ssh -i "EC2-KP-27-AUG.pem" ubuntu@44.223.103.94
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290433943/d1d8b6b0-d8b7-41d9-b870-c16935287d79.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290479976/0b711417-7e1e-461b-8f2a-9d0656e67324.png" alt class="image--center mx-auto" /></p>
<p>SSH login successful</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290521589/ae07e89f-06be-4e85-bae8-008a2a60b25d.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext">pwd
ls -l
</code></pre>
<p>As you can see, the key-pair.pem file is located in /home/ubuntu.</p>
<p>Use the “ls -l” command to display the files and folders in the current directory with detailed information.</p>
<p>Before running the SCP command again, perform a ping operation.</p>
<pre><code class="lang-plaintext">ping -c 10 www.google.com
or 
ping www.google.com
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290760068/5ae119f5-d46d-4e4e-a10f-0b18567415b9.png" alt class="image--center mx-auto" /></p>
<p>Internet connection is working</p>
<p>Now, use the <code>scp</code> command to transfer files from your public EC2 web app instance to your private EC2 database instance.</p>
<h2 id="heading-scp-command-1">SCP command</h2>
<pre><code class="lang-plaintext">scp -i EC2-KP-27-AUG.pem EC2-KP-27-AUG.pem ubuntu@11.0.104.42:/home/ubuntu
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756290980085/604a2a9b-140f-4613-aad3-94c53bef3ad9.png" alt class="image--center mx-auto" /></p>
<p>Copy the private IP address of your private-EC2-database-instance.</p>
<p>As we are in the public-EC2-web-app-instance, let us update the system, download python3, and flask application package using the following commands.</p>
<pre><code class="lang-plaintext">nano install-setup.bash
</code></pre>
<p>Paste the following installation code within the script. Save and exit</p>
<pre><code class="lang-plaintext">#!/bin/bash

# Update system
sudo apt update &amp;&amp; sudo apt upgrade -y

# Install Python3 and pip
sudo apt install python3 python3-pip -y

# Install Flask and PyMySQL
pip3 install flask pymysql

# Confirm installations
echo "Python version:"
python3 --version

echo "Pip version:"
pip3 --version

echo "Installed Flask version:"
python3 -m flask --version

echo "Setup completed successfully."
</code></pre>
<p>Give executable permissions to the script file.</p>
<pre><code class="lang-plaintext">sudo chmod 770 install-setup.bash
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291317760/4ce4869c-9b91-491c-9a41-fbdea71f5ca6.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291346383/2891b9b1-3473-4f16-b5fb-4fb232bdd086.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext"># To save
ctrl + s

# To exit
ctrl + x
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291425200/e165bfd4-1367-4816-a849-ef0264037d83.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291447034/4d4bdb8f-46f4-4bec-9fb5-c325075d9090.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291464877/59c34db4-fe87-4ee8-a3e2-4dcf6c092402.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291545878/ef5e29a5-ae57-48ad-9062-4756a61c708a.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext">python3 --version
pip3 --version
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291610431/ace8404f-e551-4a99-aa29-a0ed7b99ca82.png" alt class="image--center mx-auto" /></p>
<p>The packages have been successfully installed</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291698239/460148b0-ce47-4e2a-b45e-d4e7659f3064.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext">sudo apt install python3-flask -y
</code></pre>
<p>Verify if the installation was successful.</p>
<pre><code class="lang-plaintext">python3 -m flask --version
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291805134/8c045d34-239f-412b-a5e8-182f2483a66c.png" alt class="image--center mx-auto" /></p>
<p>Yes, Python Flask has been successfully installed.</p>
<p>Now, perform the SCP operation.</p>
<h3 id="heading-scp-command-2">SCP command</h3>
<pre><code class="lang-plaintext">scp -i EC2-KP-27-AUG.pem EC2-KP-27-AUG.pem ubuntu@11.0.104.42:/home/ubuntu
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756291973435/dde28ebf-b41f-487b-a288-b1c8d30fe1c7.png" alt class="image--center mx-auto" /></p>
<p>Done, the key-pair.pem file (EC2-KP-27-AUG.pem) has been successfully uploaded to the private-EC2-database-instance.</p>
<p>Now, let's perform an SSH login.</p>
<pre><code class="lang-plaintext">ssh -i "EC2-KP-27-AUG.pem" ubuntu@11.0.104.42
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292063188/c96669c0-55b1-40e5-857f-77a6cfbaa505.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292109953/5e6c8042-e6c6-482e-b180-5dc1d6a0f98d.png" alt class="image--center mx-auto" /></p>
<p>SSH login successful</p>
<p>Now let us update the system</p>
<pre><code class="lang-plaintext">sudo apt update -y &amp;&amp; sudo apt upgrade -y
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292197225/a5576f3c-0a2d-4987-a23d-d0e5d0e7c2e9.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292222296/e33cbf00-55a0-4424-86e7-fa6122451b9b.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292241696/4886ea21-985f-427b-acd4-a15dbb0d4c67.png" alt class="image--center mx-auto" /></p>
<p>Let's check if the key-pair.pem file is present.</p>
<pre><code class="lang-plaintext">pwd
ls -l
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292289951/ccf6dbc8-34e9-4038-88f8-ce0e0eba0bf3.png" alt class="image--center mx-auto" /></p>
<p>Upload was done right</p>
<p>Once the upgrade completes, you can proceed to:</p>
<ol>
<li><p><strong>Install MySQL Server</strong> (since this is your DB server):</p>
</li>
<li><pre><code class="lang-plaintext"> sudo apt install mysql-server -y
</code></pre>
</li>
</ol>
<p><strong>Start and enable MySQL service</strong>:</p>
<pre><code class="lang-plaintext">sudo systemctl start mysql
sudo systemctl enable mysql
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292413308/3c831446-8765-46d6-b63a-9b81d1243ec4.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292435866/a3542d67-f196-4068-a666-0980a48cf23a.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292494536/dab8e354-cf83-4a85-8df3-e18a4bb90a13.png" alt class="image--center mx-auto" /></p>
<p>The MySQL service is active and running successfully.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756292563440/6eb82f59-d57b-4428-a240-bf23b94b4b3f.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-by-step-set-up-mysql-for-flask-login">Step-by-Step: Set Up MySQL for Flask Login</h3>
<p>Run the following commands <strong>inside your private EC2 instance</strong>:</p>
<hr />
<h3 id="heading-1-log-in-to-mysql-as-root">1. <strong>Log in to MySQL as root</strong></h3>
<pre><code class="lang-plaintext">sudo mysql
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293091771/6f0c2da9-7799-465a-82ff-465c1703d500.png" alt class="image--center mx-auto" /></p>
<p>2. <strong>Create the database</strong></p>
<pre><code class="lang-plaintext">CREATE DATABASE flaskdb;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293121310/82574bd2-6e00-4972-b916-c8dec1e07f2e.png" alt class="image--center mx-auto" /></p>
<p>3. <strong>Use the database</strong></p>
<pre><code class="lang-plaintext">USE flaskdb;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293141782/6f7bd96a-0c1c-43a6-9972-70ac49972377.png" alt class="image--center mx-auto" /></p>
<p>4. <strong>Create the users table</strong></p>
<pre><code class="lang-plaintext">CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL
);
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293183394/0602901e-739f-45a8-93c5-74313bdda750.png" alt class="image--center mx-auto" /></p>
<p>5. <strong>Insert default login credentials</strong></p>
<pre><code class="lang-plaintext">INSERT INTO users (username, password) VALUES ('admin', 'admin');
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293223023/12ced0eb-8bec-4aa1-935d-a7923f65a0c7.png" alt class="image--center mx-auto" /></p>
<p>6. <strong>Create a MySQL user named</strong> <code>admin</code> with password <code>admin</code></p>
<pre><code class="lang-plaintext">CREATE USER 'admin'@'%' IDENTIFIED BY 'admin';
</code></pre>
<p>The <code>%</code> allows access from any IP — safe here because your <strong>security group limits access to only the public EC2 instance</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293373750/434a5882-c2bd-46d2-8fb4-eeb3afe140c6.png" alt class="image--center mx-auto" /></p>
<p>7. <strong>Grant all privileges on</strong> <code>flaskdb</code> to <code>admin</code></p>
<pre><code class="lang-plaintext">GRANT ALL PRIVILEGES ON flaskdb.* TO 'admin'@'%';
FLUSH PRIVILEGES;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293398716/894323e7-193e-443e-b048-7198236c5588.png" alt class="image--center mx-auto" /></p>
<p>8. <strong>Exit MySQL</strong></p>
<pre><code class="lang-plaintext">EXIT;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293434161/701a7a45-788b-4830-8112-937703b870d6.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext"># To end SSH session
exit
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293631562/b344fbcd-f79c-4c88-a0d9-3cb1372ef830.png" alt class="image--center mx-auto" /></p>
<p>Now, I am connected to my public EC2 web app instance via SSH.</p>
<p>Open or create your Flask app file:</p>
<pre><code class="lang-plaintext">nano app.py
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293717526/fe9f4a84-addf-4404-b086-f92bf6789c13.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext">from flask import Flask, request, render_template_string
import pymysql

app = Flask(__name__)

# Replace this with the **private IP** of your private EC2 instance
DB_HOST = "11.0.104.42"  # &lt;-- update this if needed
DB_USER = "admin"
DB_PASSWORD = "admin"
DB_NAME = "flaskdb"

LOGIN_PAGE = '''
    &lt;h2&gt;Login&lt;/h2&gt;
    &lt;form method="POST"&gt;
        Username: &lt;input name="username" type="text"&gt;&lt;br&gt;
        Password: &lt;input name="password" type="password"&gt;&lt;br&gt;
        &lt;input type="submit" value="Login"&gt;
    &lt;/form&gt;
'''

@app.route('/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        uname = request.form['username']
        passwd = request.form['password']

        connection = pymysql.connect(
            host=DB_HOST,
            user=DB_USER,
            password=DB_PASSWORD,
            database=DB_NAME
        )

        with connection.cursor() as cursor:
            cursor.execute("SELECT * FROM users WHERE username=%s AND password=%s", (uname, passwd))
            result = cursor.fetchone()

        connection.close()

        if result:
            return "&lt;h1&gt;Welcome, admin!&lt;/h1&gt;"
        else:
            return "&lt;h1&gt;Login Failed&lt;/h1&gt;" + LOGIN_PAGE

    return LOGIN_PAGE

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293814834/6716c0f8-766b-4edc-92dc-2d71ec2c319a.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext"># To save the file
ctrl + s

# To exit the file
ctrl + x
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293876754/252ddb37-a3af-47a2-ae22-128172ab8bb7.png" alt class="image--center mx-auto" /></p>
<p>Run the Flask app with sudo (because port 80 needs root privileges):</p>
<pre><code class="lang-plaintext">sudo python3 app.py
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756293925929/95196446-7845-495b-9a75-4d159d4af9b9.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756294000234/80e8c020-16f1-4f28-a372-d4ace944c153.png" alt class="image--center mx-auto" /></p>
<p>To fix this, run:</p>
<pre><code class="lang-plaintext">sudo apt update
sudo apt install python3-pymysql -y
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756294107725/c2d62035-f1bf-4d19-a0ea-38d2add56be5.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756294130393/244ae961-41f5-4039-a717-e2fc6ec618ec.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756294522794/69c291ef-8c60-4d2d-aaf0-61e5af7303ba.png" alt class="image--center mx-auto" /></p>
<p><strong>After installation</strong>, try running your app again with:</p>
<pre><code class="lang-plaintext">sudo python3 app.py
</code></pre>
<p>Copy the public IP of the public EC2 web app instance and paste it into any browser of your choice.</p>
<pre><code class="lang-plaintext">http://44.223.103.94:80
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756294659776/a344c3cd-5687-46c2-b2d9-4707df8280b8.png" alt class="image--center mx-auto" /></p>
<p>Enter the username as "admin" and the password as "admin".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756294699744/d4340f9b-266b-423b-a6da-d58e3e5822dd.png" alt class="image--center mx-auto" /></p>
<p>If you don’t see it or get a timeout/error, here are quick checks:</p>
<ol>
<li><p><strong>Security Group:</strong><br /> Make sure your public EC2 instance’s security group allows inbound HTTP (port 80) from your IP (or anywhere 0.0.0.0/0 for testing).</p>
</li>
<li><p><strong>Flask app running:</strong><br /> Confirm the Flask app is running (you already did this).</p>
</li>
<li><p><strong>Firewall on EC2:</strong><br /> Check if <code>ufw</code> or any firewall isn’t blocking port 80.</p>
</li>
<li><p><strong>Correct IP:</strong><br /> Double-check you are using the public IP of the public EC2 instance, not the private IP.</p>
</li>
</ol>
<p>Try accessing now and let me know what you see!</p>
<p>Note: There was a huge error. I forgot to install mysql-client package on my public-EC2-web-app instance.</p>
<p>Now, that I have installed it</p>
<p>This is what I received</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756295760696/e56c0b4c-42b7-40ae-af5f-e069520a7545.png" alt class="image--center mx-auto" /></p>
<p>Now, I will enter an incorrect username and password. Let’s see what I receive</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756295818037/dec45994-a5ce-4194-8cc0-377418ab9541.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756295848144/bd9f58c6-2eea-467c-bcdb-6aff5fdab19d.png" alt class="image--center mx-auto" /></p>
<p>I entered the username as "abhishek" and the password as "abhishek".</p>
<h2 id="heading-what-really-caused-the-connection-refused-error">What Really Caused the Connection Refused Error?</h2>
<h4 id="heading-1-aws-security-groups">1. AWS Security Groups:</h4>
<p>Your security groups were configured properly. The private EC2’s security group allowed inbound MySQL traffic (port 3306) <strong>only from the public EC2’s security group</strong> — which is the best practice for limiting access. So no issue there.</p>
<h4 id="heading-2-mysql-client-on-public-ec2">2. mysql-client on Public EC2:</h4>
<p>Installing <code>mysql-client</code> on the public EC2 is optional. It’s a helpful tool for manually testing MySQL connectivity from the public instance, but it is <strong>not required</strong> for your Flask app to connect programmatically via Python’s <code>pymysql</code>.</p>
<h4 id="heading-3-mysql-bind-address-the-actual-culprit">3. MySQL Bind Address (The Actual Culprit):</h4>
<p>By default, MySQL listens on <code>127.0.0.1</code> (<a target="_blank" href="http://localhost">localhost</a>) only, meaning it refuses remote connections from other instances. To enable remote access, you need to update the MySQL configuration:</p>
<ul>
<li>Open the private-ec2-database-instance → MySQL configuration file, typically located at:</li>
</ul>
<pre><code class="lang-plaintext">cd /etc/mysql/mysql.conf.d/mysqld.cnf
</code></pre>
<p>Find the line that starts with:</p>
<pre><code class="lang-plaintext">bind-address = 127.0.0.1
</code></pre>
<p>Change it to:</p>
<pre><code class="lang-plaintext">bind-address = 0.0.0.0
</code></pre>
<p>Save the file and restart MySQL to apply changes:</p>
<pre><code class="lang-plaintext">sudo systemctl restart mysql
</code></pre>
<p>This change tells MySQL to listen on all network interfaces, including the private IP, allowing your public EC2 instance to connect.</p>
<hr />
<h3 id="heading-key-takeaway">Key Takeaway:</h3>
<ul>
<li><p>Proper AWS Security Groups <strong>and</strong> MySQL configured to listen on <code>0.0.0.0</code> = successful remote connection.</p>
</li>
<li><p>Installing <code>mysql-client</code> on the public EC2 is <strong>helpful</strong> for testing but <strong>not required</strong> for your Flask app to connect.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion:</h2>
<h2 id="heading-project-conclusion-and-key-takeaways">Project Conclusion and Key Takeaways</h2>
<p>This project involved deploying a Flask web application on a public EC2 instance that connects to a MySQL database hosted on a private EC2 instance within the same AWS VPC. Throughout the deployment and testing phases, several critical insights were uncovered that contributed to the successful setup and highlighted best practices for secure and functional cloud-based application architectures.</p>
<h3 id="heading-key-takeaways">Key Takeaways:</h3>
<ol>
<li><p><strong>Network Security and Access Control:</strong><br /> Proper configuration of AWS Security Groups is fundamental. Restricting MySQL access on the private EC2 instance’s security group to allow inbound traffic only from the public EC2 instance’s security group enhances security by limiting the attack surface.</p>
</li>
<li><p><strong>Database Connectivity and Configuration:</strong><br /> MySQL’s default configuration binds the service to <code>127.0.0.1</code>, which restricts connections to <a target="_blank" href="http://localhost">localhost</a> only. To enable remote connections from the public EC2 instance, updating the <code>bind-address</code> in MySQL’s configuration file (<code>/etc/mysql/mysql.conf.d/mysqld.cnf</code>) to <code>0.0.0.0</code> is essential. This change allows MySQL to listen on all network interfaces within the private subnet.</p>
</li>
<li><p><strong>Tooling and Testing:</strong><br /> While installing the MySQL client (<code>mysql-client</code>) on the public EC2 instance is not mandatory for the Flask application’s operation, it is highly beneficial for manual connectivity testing and debugging. This facilitates quicker diagnosis of network and authentication issues.</p>
</li>
<li><p><strong>Application Deployment Best Practices:</strong><br /> Running the Flask development server on port 80 and as root can work for quick testing but is not recommended for production. For production-grade deployments, using a WSGI server such as Gunicorn or uWSGI behind a reverse proxy (e.g., Nginx) is advised.</p>
</li>
<li><p><strong>Error Diagnosis and Troubleshooting:</strong><br /> Connection refused errors often stem from service configuration issues rather than security group misconfigurations. A systematic approach—checking network rules, verifying service bindings, and testing connectivity—proves effective in identifying root causes.</p>
</li>
<li><p>The <strong>changing of the</strong> <code>bind-address</code> to <code>0.0.0.0</code> was done on the private EC2 instance where the MySQL server is running. This allows MySQL to listen on all network interfaces, including the private IP address accessible from your public EC2 instance.</p>
</li>
<li><p>The <strong>public EC2 instance was configured correctly from the start</strong>—your Flask app was set up, security groups allowed traffic, and everything was ready to communicate with the private EC2 instance.</p>
<p> The root cause of the connection issue was solely on the <strong>private EC2 instance</strong>, where MySQL was bound only to <a target="_blank" href="http://localhost">localhost</a>, blocking remote access.</p>
<p> So, no changes were needed on the public EC2 side regarding connectivity or app setup.</p>
</li>
<li><p>Your <strong>Flask app</strong> is running on the <strong>public EC2 instance</strong>, which listens on <code>0.0.0.0</code> — meaning it accepts incoming HTTP requests from anywhere on the internet (public IP).</p>
</li>
<li><p>But when your Flask app connects to MySQL, <strong>the MySQL server is on the private EC2 instance</strong> inside your VPC.</p>
</li>
<li><p>The MySQL server’s <code>bind-address</code> was set to <code>127.0.0.1</code> (<a target="_blank" href="http://localhost">localhost</a>), meaning it only accepted connections originating from <strong>itself</strong> — no remote connections allowed.</p>
</li>
<li><p>By changing the MySQL <code>bind-address</code> to <code>0.0.0.0</code> on the <strong>private EC2</strong>, it allowed the database to accept connections from other machines inside the VPC, specifically your <strong>public EC2</strong>.</p>
</li>
<li><p>The <strong>public EC2’s Flask app</strong> connects to MySQL over the <strong>private IP</strong> of the private EC2 (<code>11.0.104.42</code>), not via the public internet.</p>
</li>
</ol>
<p>So while your Flask app listens on <code>0.0.0.0</code> to serve users from the internet, your database connection is internal inside the VPC, protected by security groups.</p>
<hr />
<p>By adhering to these principles, the project successfully established a secure, scalable, and maintainable architecture for a cloud-hosted Flask application with a remote MySQL backend. This foundation can be extended with further enhancements such as automated deployment pipelines, database replication, and advanced security measures.</p>
<p>Thank you for your time.</p>
<hr />
]]></content:encoded></item></channel></rss>