<?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: Sagnik Ghosh</title>
    <description>The latest articles on DEV Community by Sagnik Ghosh (@nik26_).</description>
    <link>https://dev.to/nik26_</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%2F2561409%2F34392c43-bd3b-46f7-8fe8-1b08ccd425d0.png</url>
      <title>DEV Community: Sagnik Ghosh</title>
      <link>https://dev.to/nik26_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nik26_"/>
    <language>en</language>
    <item>
      <title>Building a Secure Bastion Host Architecture in AWS: A Complete Step-by-Step Guide</title>
      <dc:creator>Sagnik Ghosh</dc:creator>
      <pubDate>Sun, 28 Dec 2025 20:18:52 +0000</pubDate>
      <link>https://dev.to/nik26_/building-a-secure-bastion-host-architecture-in-aws-a-complete-step-by-step-guide-22p0</link>
      <guid>https://dev.to/nik26_/building-a-secure-bastion-host-architecture-in-aws-a-complete-step-by-step-guide-22p0</guid>
      <description>&lt;h3&gt;
  
  
  What is a Bastion Host?
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Bastion Host&lt;/strong&gt; (also called a Jump Server or Jump Box) is a special-purpose server that acts as a secure gateway between an external network (like the internet) and a private network. Think of it as a heavily guarded front door to your castle—everyone who wants to enter must pass through this single, monitored entry point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use a Bastion Host?
&lt;/h3&gt;

&lt;p&gt;Imagine you have critical application servers, databases, and backend services running in AWS. You don't want these directly exposed to the internet because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Attack Surface&lt;/strong&gt;: Only one server (the bastion) is exposed to the internet, not your entire infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized Access Control&lt;/strong&gt;: All SSH access flows through a single point, making it easier to monitor and audit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Private instances have no public IP addresses, making them invisible to the outside world.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance&lt;/strong&gt;: Many security standards (PCI-DSS, HIPAA, SOC2) require this level of network segregation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Architecture We'll Build
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                            AWS CLOUD                            │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                      VPC (10.0.0.0/16)                    │  │
│  │                                                           │  │
│  │   ┌─────────────────┐       ┌─────────────────────────┐   │  │
│  │   │  Public Subnet  │       │    Private Subnet       │   │  │
│  │   │  (10.0.1.0/24)  │       │    (10.0.3.0/24)        │   │  │
│  │   │                 │       │                         │   │  │
│  │   │  ┌───────────┐  │       │    ┌───────────────┐    │   │  │
│  │   │  │  Bastion  │  │  SSH  │    │    Private    │    │   │  │
│  │   │  │   Host    │──────────────▶│   Instance    │    │   │  │
│  │   │  │ (Public IP)│ │       │    │  (No Public IP)│   │   │  │
│  │   │  └───────────┘  │       │    └───────────────┘    │   │  │
│  │   │        ▲        │       │                         │   │  │
│  │   └────────│────────┘       └─────────────────────────┘   │  │
│  │            │                                              │  │
│  │   ┌────────┴────────┐                                     │  │
│  │   │ Internet Gateway│                                     │  │
│  │   └────────┬────────┘                                     │  │
│  └────────────│──────────────────────────────────────────────┘  │
│               │                                                 │
└───────────────│─────────────────────────────────────────────────┘
                │
         ┌──────┴──────┐
         │  INTERNET   │
         │   (You)     │
         └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we begin, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account with appropriate permissions.&lt;/li&gt;
&lt;li&gt;Basic understanding of networking concepts (IP addresses, subnets, routing).&lt;/li&gt;
&lt;li&gt;SSH client installed on your local machine (If you have MacBook then not needed since it Comes with inbuilt SSH Client).&lt;/li&gt;
&lt;li&gt;AWS Console access.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Create a Virtual Private Cloud (VPC)
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;VPC (Virtual Private Cloud)&lt;/strong&gt; is your own isolated section of the AWS cloud where you can launch resources in a virtual network that you define.&lt;/p&gt;

&lt;h3&gt;
  
  
  Navigate to VPC Dashboard
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log into the AWS Management Console&lt;/li&gt;
&lt;li&gt;Search for "VPC" in the search bar&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;VPC Dashboard&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create the VPC
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create VPC&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;VPC only&lt;/strong&gt; (we'll create subnets manually for learning purposes)&lt;/li&gt;
&lt;li&gt;Configure the following:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name tag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPv4 CIDR block&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.0/16&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPv6 CIDR block&lt;/td&gt;
&lt;td&gt;No IPv6 CIDR block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tenancy&lt;/td&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create VPC&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Understanding the CIDR Block
&lt;/h3&gt;

&lt;p&gt;The CIDR block &lt;code&gt;10.0.0.0/16&lt;/code&gt; means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;10.0.0.0&lt;/strong&gt; is the base IP address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/16&lt;/strong&gt; means the first 16 bits are fixed (total 32 bits), giving us total of (32-16) = 16 bits or 2 octets (1 octet = 8 bits).
So, total 2^16 = 65,536 available IP addresses (10.0.0.0 to 10.0.255.255)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This large range allows us to create multiple subnets within our VPC.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Create and Attach an Internet Gateway
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;Internet Gateway (IGW)&lt;/strong&gt; is a horizontally scaled, redundant, and highly available VPC component that allows communication between your VPC and the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the Internet Gateway
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the VPC Dashboard, click &lt;strong&gt;Internet Gateways&lt;/strong&gt; in the left sidebar&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create internet gateway&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name tag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-igw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create internet gateway&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Attach to VPC
&lt;/h3&gt;

&lt;p&gt;After creation, the IGW is in a "Detached" state. We need to attach it to our VPC:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the newly created internet gateway&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Actions&lt;/strong&gt; → &lt;strong&gt;Attach to VPC&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;my-bastion-vpc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Attach internet gateway&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The status should now show "Attached".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Key Concept&lt;/strong&gt;: Without an Internet Gateway, nothing in your VPC can communicate with the internet, regardless of other configurations.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 3: Create Public and Private Subnets
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Subnets&lt;/strong&gt; are segments of your VPC's IP address range where you can place groups of isolated resources. We'll create two subnets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public Subnet&lt;/strong&gt;: For resources that need direct internet access (our bastion host)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private Subnet&lt;/strong&gt;: For resources that should NOT be directly accessible from the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create the Public Subnet
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the VPC Dashboard, click &lt;strong&gt;Subnets&lt;/strong&gt; in the left sidebar&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create subnet&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPC ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subnet name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public-subnet&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Availability Zone&lt;/td&gt;
&lt;td&gt;Choose any (e.g., &lt;code&gt;us-east-1a&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPv4 CIDR block&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create subnet&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create the Private Subnet
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create subnet&lt;/strong&gt; again&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPC ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subnet name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;private-subnet&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Availability Zone&lt;/td&gt;
&lt;td&gt;Same as public subnet (e.g., &lt;code&gt;us-east-1a&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPv4 CIDR block&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.3.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create subnet&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Understanding the Subnet CIDR Blocks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;10.0.1.0/24&lt;/strong&gt;: Provides 256 IP addresses (10.0.1.0 to 10.0.1.255)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10.0.3.0/24&lt;/strong&gt;: Provides 256 IP addresses (10.0.3.0 to 10.0.3.255)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are subsets of our VPC's &lt;code&gt;10.0.0.0/16&lt;/code&gt; range.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Pro Tip&lt;/strong&gt;: Keep public and private subnets in the same Availability Zone to minimize latency and data transfer costs between your bastion host and private instances.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Configure Route Tables
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Route Table&lt;/strong&gt; contains a set of rules (routes) that determine where network traffic is directed. This is where we define what makes a subnet "public" or "private".&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the Public Route Table
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the VPC Dashboard, click &lt;strong&gt;Route Tables&lt;/strong&gt; in the left sidebar&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create route table&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public-route-table&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create route table&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Add Internet Route to Public Route Table
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;code&gt;public-route-table&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Routes&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit routes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add route&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0.0.0.0/0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select "Internet Gateway" → &lt;code&gt;my-bastion-igw&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Save changes&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The route &lt;code&gt;0.0.0.0/0&lt;/code&gt; means "all traffic not destined for the local VPC should go to the Internet Gateway".&lt;/p&gt;

&lt;h3&gt;
  
  
  Associate Public Subnet with Public Route Table
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;With &lt;code&gt;public-route-table&lt;/code&gt; still selected, click the &lt;strong&gt;Subnet associations&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit subnet associations&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Check the box next to &lt;code&gt;public-subnet&lt;/code&gt; (Select the Subnet that you created which is supposed to be accessible to the internet)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Save associations&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create the Private Route Table
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create route table&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;private-route-table&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create route table&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Associate Private Subnet with Private Route Table
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;code&gt;private-route-table&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Subnet associations&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit subnet associations&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Check the box next to &lt;code&gt;private-subnet&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Save associations&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🔒 Security Note&lt;/strong&gt;: Notice we did NOT add an internet gateway route to the private route table. This is intentional—the private subnet has no direct path to the internet.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 5: Create Security Groups
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Security Groups&lt;/strong&gt; act as virtual firewalls for your EC2 instances, controlling inbound and outbound traffic at the instance level.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Security Group for Bastion Host
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the VPC Dashboard, click &lt;strong&gt;Security Groups&lt;/strong&gt; in the left sidebar&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create security group&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security group name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bastion-sg&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Security group for bastion host&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Add Inbound Rule:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Port Range&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSH&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0.0.0.0/0&lt;/code&gt; (or your IP for better security)&lt;/td&gt;
&lt;td&gt;SSH access&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Keep the default outbound rule (Allow all traffic)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create security group&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create Security Group for Private Instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create security group&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security group name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;private-instance-sg&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Security group for private instances&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Add Inbound Rule:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Port Range&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSH&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;bastion-sg&lt;/code&gt; (select the security group)&lt;/td&gt;
&lt;td&gt;SSH from bastion only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create security group&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🔒 Security Best Practice&lt;/strong&gt;: By specifying the bastion's security group as the source (instead of an IP range), we ensure only the bastion host can SSH into private instances. If the bastion's IP changes, the rule still works.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 6: Launch the Bastion Host (Public EC2 Instance)
&lt;/h2&gt;

&lt;p&gt;Now we'll launch our bastion host in the public subnet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Key Pair (if you don't have one)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;EC2 Dashboard&lt;/strong&gt; → &lt;strong&gt;Key Pairs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create key pair&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bastion-key&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key pair type&lt;/td&gt;
&lt;td&gt;RSA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Private key file format&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.pem&lt;/code&gt; (for Linux/Mac) or &lt;code&gt;.ppk&lt;/code&gt; (for Windows/PuTTY)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create key pair&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The private key file will automatically download—&lt;strong&gt;keep this safe!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Launch the Bastion EC2 Instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;EC2 Dashboard&lt;/strong&gt; → &lt;strong&gt;Instances&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Launch instances&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Name and Tags:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| Name | &lt;code&gt;bastion-host&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application and OS Images:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| AMI | Ubuntu Server 22.04 LTS (or Amazon Linux 2023) |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instance Type:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| Instance type | &lt;code&gt;t2.micro&lt;/code&gt; (Free tier eligible) |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Pair:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| Key pair name | &lt;code&gt;bastion-key&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Settings:&lt;/strong&gt; Click &lt;strong&gt;Edit&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subnet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public-subnet&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-assign public IP&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Enable&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security group&lt;/td&gt;
&lt;td&gt;Select existing → &lt;code&gt;bastion-sg&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Launch instance&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Important&lt;/strong&gt;: We enabled "Auto-assign public IP" because this instance needs to be accessible from the internet.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Step 7: Launch the Private EC2 Instance
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create Another Key Pair for Private Instance
&lt;/h3&gt;

&lt;p&gt;For better security, use a separate key pair for the private instance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new key pair named &lt;code&gt;private-instance-key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Download and save the &lt;code&gt;.pem&lt;/code&gt; file&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Launch the Private EC2 Instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Launch instances&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Name and Tags:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| Name | &lt;code&gt;private-instance&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application and OS Images:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| AMI | Ubuntu Server 22.04 LTS (same as bastion) |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instance Type:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| Instance type | &lt;code&gt;t2.micro&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Pair:&lt;/strong&gt;&lt;br&gt;
| Setting | Value |&lt;br&gt;
|---------|-------|&lt;br&gt;
| Key pair name | &lt;code&gt;private-instance-key&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Settings:&lt;/strong&gt; Click &lt;strong&gt;Edit&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-bastion-vpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subnet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;private-subnet&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-assign public IP&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Disable&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security group&lt;/td&gt;
&lt;td&gt;Select existing → &lt;code&gt;private-instance-sg&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Launch instance&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🔒 Security Note&lt;/strong&gt;: We disabled "Auto-assign public IP" because this instance should NOT be directly accessible from the internet.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Step 8: Connect to Your Infrastructure
&lt;/h2&gt;

&lt;p&gt;Now comes the exciting part—actually connecting to your private instance through the bastion host!&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 8.1: SSH into the Bastion Host
&lt;/h3&gt;

&lt;p&gt;First, let's connect to our bastion host from your local machine.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the public IP of your bastion host from the EC2 console&lt;/li&gt;
&lt;li&gt;Open your terminal&lt;/li&gt;
&lt;li&gt;Set correct permissions on your key file:
&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;chmod &lt;/span&gt;400 bastion-key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;SSH into the bastion:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"bastion-key.pem"&lt;/span&gt; ubuntu@&amp;lt;BASTION_PUBLIC_IP&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Replace &lt;code&gt;&amp;lt;BASTION_PUBLIC_IP&amp;gt;&lt;/code&gt; with your bastion's actual public IP address.&lt;/p&gt;

&lt;p&gt;You should see the Ubuntu welcome message—you're now on the bastion host!&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 8.2: Transfer the Private Key to Bastion Host
&lt;/h3&gt;

&lt;p&gt;To SSH from the bastion to the private instance, we need the private instance's key on the bastion. There are several ways to do this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 1: SCP (Secure Copy)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From your local machine (not the bastion), run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scp &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"bastion-key.pem"&lt;/span&gt; private-instance-key.pem ubuntu@&amp;lt;BASTION_PUBLIC_IP&amp;gt;:~/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Method 2: Copy-Paste (for quick testing)&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the private key file locally and copy its contents&lt;/li&gt;
&lt;li&gt;On the bastion, create a new file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/private-instance-key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Paste the contents and save (Ctrl+X, Y, Enter)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 8.3: Set Correct Permissions on the Private Key
&lt;/h3&gt;

&lt;p&gt;On the bastion host, set the correct permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;400 ~/private-instance-key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Common Error&lt;/strong&gt;: If you see &lt;code&gt;Load key "private-instance-key.pem": Permission denied&lt;/code&gt;, the key permissions are too open. SSH requires private keys to be readable only by the owner (permissions 400 or 600).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Another Common Error&lt;/strong&gt;: If the key is owned by root but you're running as ubuntu, you'll need to change ownership:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chown &lt;/span&gt;ubuntu:ubuntu ~/private-instance-key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 8.4: SSH into the Private Instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Get the &lt;strong&gt;private IP&lt;/strong&gt; of your private instance from the EC2 console (it will be something like &lt;code&gt;10.0.3.xxx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;From the bastion host, SSH into the private instance:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"private-instance-key.pem"&lt;/span&gt; ubuntu@&amp;lt;PRIVATE_INSTANCE_PRIVATE_IP&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Success!&lt;/strong&gt; You're now connected to your private instance that has no public IP address. The only way to reach it is through the bastion host.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verifying the Setup
&lt;/h2&gt;

&lt;p&gt;Let's verify everything is working as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  On the Private Instance, Try to Reach the Internet
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping google.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should fail (hang or show "Network is unreachable") because the private instance has no route to the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check the Private Instance Has No Public IP
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl ifconfig.me
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should timeout or fail, confirming no public IP is assigned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check You Cannot SSH Directly to Private Instance
&lt;/h3&gt;

&lt;p&gt;From your local machine, try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"private-instance-key.pem"&lt;/span&gt; ubuntu@&amp;lt;PRIVATE_INSTANCE_PRIVATE_IP&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should fail because your local machine cannot route to private IP addresses in AWS.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices and Security Recommendations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Restrict Bastion SSH Access
&lt;/h3&gt;

&lt;p&gt;Instead of allowing SSH from &lt;code&gt;0.0.0.0/0&lt;/code&gt;, restrict to your specific IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source: YOUR_PUBLIC_IP/32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Use SSH Agent Forwarding
&lt;/h3&gt;

&lt;p&gt;Instead of copying private keys to the bastion, use SSH agent forwarding:&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="c"&gt;# On your local machine&lt;/span&gt;
ssh-add private-instance-key.pem
ssh &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"bastion-key.pem"&lt;/span&gt; ubuntu@&amp;lt;BASTION_PUBLIC_IP&amp;gt;

&lt;span class="c"&gt;# Now on the bastion, you can SSH without specifying a key&lt;/span&gt;
ssh ubuntu@&amp;lt;PRIVATE_INSTANCE_PRIVATE_IP&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Enable VPC Flow Logs
&lt;/h3&gt;

&lt;p&gt;Monitor all network traffic for security analysis:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to VPC → Your VPC → Flow Logs&lt;/li&gt;
&lt;li&gt;Create a flow log to CloudWatch Logs&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4. Use Session Manager Instead
&lt;/h3&gt;

&lt;p&gt;AWS Systems Manager Session Manager provides a more secure alternative to SSH bastion hosts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need to open port 22&lt;/li&gt;
&lt;li&gt;No need to manage SSH keys&lt;/li&gt;
&lt;li&gt;Built-in logging and auditing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Implement Multi-Factor Authentication
&lt;/h3&gt;

&lt;p&gt;Consider using AWS IAM Identity Center with MFA for accessing your AWS resources.&lt;/p&gt;




&lt;h2&gt;
  
  
  Troubleshooting Common Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Permission denied (publickey)"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause&lt;/strong&gt;: SSH key issues&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Check key file permissions: &lt;code&gt;chmod 400 key.pem&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check key ownership: &lt;code&gt;ls -la key.pem&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ensure you're using the correct key for the correct instance&lt;/li&gt;
&lt;li&gt;Verify the username (ubuntu for Ubuntu AMI, ec2-user for Amazon Linux)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Connection timed out"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause&lt;/strong&gt;: Network/routing issues&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Verify the instance is running&lt;/li&gt;
&lt;li&gt;Check security group rules allow SSH (port 22)&lt;/li&gt;
&lt;li&gt;Verify route table associations&lt;/li&gt;
&lt;li&gt;Ensure Internet Gateway is attached (for bastion)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "error in libcrypto"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause&lt;/strong&gt;: Corrupted key file&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Re-download the key from AWS&lt;/li&gt;
&lt;li&gt;Use SCP instead of copy-paste to transfer keys&lt;/li&gt;
&lt;li&gt;Check for hidden characters in the key file&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Network is unreachable" from private instance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause&lt;/strong&gt;: This is expected! Private instances have no internet access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: If you need internet access for updates, set up a NAT Gateway (additional topic for another article).&lt;/p&gt;




&lt;h2&gt;
  
  
  Cost Considerations
&lt;/h2&gt;

&lt;p&gt;Here's what this setup will cost:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPC&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Gateway&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subnets&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Route Tables&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security Groups&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;t2.micro EC2 (Free Tier)&lt;/td&gt;
&lt;td&gt;Free for 750 hours/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;t2.micro EC2 (after Free Tier)&lt;/td&gt;
&lt;td&gt;~$8.50/month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: Free if using Free Tier eligible instances, otherwise minimal cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cleanup
&lt;/h2&gt;

&lt;p&gt;If you are doing this for learning purpose, then, clean up resources to avoid unexpected charges when done:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Terminate EC2 Instances&lt;/strong&gt;: EC2 → Instances → Select → Instance State → Terminate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete Security Groups&lt;/strong&gt;: VPC → Security Groups → Delete (delete custom ones)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete Subnets&lt;/strong&gt;: VPC → Subnets → Delete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detach and Delete Internet Gateway&lt;/strong&gt;: VPC → Internet Gateways → Detach → Delete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete Route Tables&lt;/strong&gt;: VPC → Route Tables → Delete (delete custom ones)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete VPC&lt;/strong&gt;: VPC → Your VPCs → Delete&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Congratulations! 🎉 You've successfully built a secure bastion host architecture in AWS. Here's what we accomplished:&lt;/p&gt;

&lt;p&gt;✅ Created a VPC with custom CIDR block&lt;br&gt;&lt;br&gt;
✅ Set up an Internet Gateway for public internet access&lt;br&gt;&lt;br&gt;
✅ Created public and private subnets&lt;br&gt;&lt;br&gt;
✅ Configured route tables for proper traffic flow&lt;br&gt;&lt;br&gt;
✅ Implemented security groups for access control&lt;br&gt;&lt;br&gt;
✅ Launched a bastion host in the public subnet&lt;br&gt;&lt;br&gt;
✅ Launched a private instance accessible only through the bastion&lt;br&gt;&lt;br&gt;
✅ Successfully SSH'd from local → bastion → private instance  &lt;/p&gt;

&lt;p&gt;This architecture forms the foundation for many production AWS environments and is a crucial pattern to understand for anyone working with cloud infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Now that you have this foundation, consider exploring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NAT Gateway&lt;/strong&gt;: Allow private instances to access the internet for updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Systems Manager Session Manager&lt;/strong&gt;: Bastion-less access to private instances&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC Peering&lt;/strong&gt;: Connect multiple VPCs together&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS PrivateLink&lt;/strong&gt;: Access AWS services without going through the internet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code&lt;/strong&gt;: Automate this setup using Terraform or CloudFormation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Connect With Me
&lt;/h2&gt;

&lt;p&gt;If you found this article helpful, give it a ❤️ and follow me for more cloud and DevOps content!&lt;/p&gt;

&lt;p&gt;Have questions? Drop them in the comments below—I'd love to help!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article is part of my AWS Fundamentals series. I am documenting my own cloud journey to serve as a personal knowledge base and to provide a clear, relatable guide for others navigating the same path. For more comprehensive deep dives, explore my full collection of AWS tutorials.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags&lt;/strong&gt;: #aws #cloud #devops #security #networking #tutorial&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>security</category>
      <category>aws</category>
      <category>devops</category>
    </item>
    <item>
      <title>Reconciliation in React Native vs. React Web: A Brief Analysis</title>
      <dc:creator>Sagnik Ghosh</dc:creator>
      <pubDate>Tue, 04 Feb 2025 12:38:43 +0000</pubDate>
      <link>https://dev.to/nik26_/how-reconciliation-works-in-react-native-vs-react-web-a-deep-dive-3h3</link>
      <guid>https://dev.to/nik26_/how-reconciliation-works-in-react-native-vs-react-web-a-deep-dive-3h3</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;React is widely used for building both web and mobile applications through React Web and React Native. One of its key features is Reconciliation, the process that determines how changes in the component state or props reflect in the UI efficiently.&lt;/p&gt;

&lt;p&gt;With the release of React Native 0.76, the architecture has significantly changed, moving away from the old bridge system to a more performant Fabric and TurboModules architecture. This brings notable differences in how reconciliation works compared to previous versions of React Native and React Web.&lt;/p&gt;

&lt;p&gt;In this article, we’ll compare reconciliation in React Web and React Native 0.76 (New Architecture), highlighting key differences, improvements, use cases, and optimization techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is Reconciliation in React?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Reconciliation is the algorithm React uses to efficiently update the UI in response to changes in component state or props. It minimizes unnecessary re-renders by identifying differences between the current and previous virtual DOM (in React Web) or virtual tree (in React Native).&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Steps in Reconciliation:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Rendering the Virtual Representation:&lt;/strong&gt;&lt;/em&gt; React creates a virtual representation of the UI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Diffing Algorithm:&lt;/strong&gt;&lt;/em&gt; React compares the new virtual representation with the previous one to identify changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Efficient Updates:&lt;/strong&gt;&lt;/em&gt; Only the necessary changes are applied to the real DOM (React Web) or native views (React Native).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Reconciliation in React Web vs React Native (0.76)&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  React Web:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Uses the Virtual DOM, a JavaScript object representation of the HTML DOM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Updates the real DOM in the browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimizes performance through efficient DOM updates but can be constrained by browser limitations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Batches updates to avoid excessive DOM manipulation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Uses synthetic events managed within the browser environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animations are executed in JavaScript (less performant) or via CSS.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  React Native 0.76 (Fabric):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Uses a Virtual Tree, a JavaScript object representation of native UI views.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Updates native views via Fabric, the new rendering pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Eliminates the bridge bottleneck by using a direct-to-native threading model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enables synchronous layout updates for improved UI responsiveness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Uses Fabric’s concurrent event handling, reducing UI lag.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animations now utilize JSI-powered native animations, improving FPS and responsiveness.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Optimizing Reconciliation in React Web and React Native 0.76&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;key&lt;/code&gt; in Lists
&lt;/h3&gt;

&lt;p&gt;Keys help React efficiently track changes in lists. This applies to both React Web and React Native. Incorrectly managing keys can result in unnecessary re-renders and degraded performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const items = [{ id: 1, name: "Item 1" }, { id: 2, name: "Item 2" }];

return (
  &amp;lt;FlatList
    data={items}
    keyExtractor={(item) =&amp;gt; item.id.toString()}
    renderItem={({ item }) =&amp;gt; &amp;lt;Text&amp;gt;{item.name}&amp;lt;/Text&amp;gt;}
  /&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use &lt;code&gt;React.memo&lt;/code&gt; and &lt;code&gt;PureComponent&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Memoization prevents unnecessary re-renders in both React Web and React Native by ensuring components only update when their props change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MemoizedComponent = React.memo(({ name }) =&amp;gt; {
  return &amp;lt;Text&amp;gt;{name}&amp;lt;/Text&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Leverage Synchronous Updates in Fabric (React Native Only)
&lt;/h3&gt;

&lt;p&gt;Fabric’s synchronous updates significantly improve performance by reducing UI lag. Ensure your components are structured to take advantage of these updates and avoid unnecessary state updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use JSI-based Native Modules (React Native Only)
&lt;/h3&gt;

&lt;p&gt;JSI (JavaScript Interface) allows for direct interaction with native code, bypassing the old bridge, reducing the performance overhead, and making state updates more efficient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NativeModules } from 'react-native';
const { MyNativeModule } = NativeModules;

MyNativeModule.performNativeTask();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use Concurrent Event Handling (React Native Only)
&lt;/h3&gt;

&lt;p&gt;Fabric introduces a concurrent event system that reduces bottlenecks during UI interactions. Use event listeners that fully utilize Fabric’s improved event handling model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handlePress = useCallback(() =&amp;gt; {
  console.log("Button pressed");
}, []);

&amp;lt;Button onPress={handlePress} title="Press Me" /&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Optimize Animations Using the Native Driver (React Native Only)
&lt;/h3&gt;

&lt;p&gt;React Native’s JSI-based native driver allows for animations to run smoothly without blocking the JavaScript thread. Always use useNativeDriver: true where possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Animated.timing(animatedValue, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true, // Runs animation on the native thread
}).start();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Batch State Updates
&lt;/h3&gt;

&lt;p&gt;React automatically batches multiple state updates into a single re-render cycle, reducing performance overhead in both React Web and React Native.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setState1(value1);
setState2(value2);
// React optimizes and processes both updates together.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Profile and Optimize Performance Using React DevTools
&lt;/h3&gt;

&lt;p&gt;For React Web, use React DevTools to analyze component re-renders. For React Native, use Flipper to monitor performance bottlenecks and improve reconciliation efficiency.&lt;/p&gt;

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

&lt;p&gt;With React Native 0.76, reconciliation has evolved significantly compared to previous versions, moving away from the traditional bridge-based architecture. Fabric, TurboModules, and JSI have made UI updates faster, reducing bottlenecks that existed in earlier versions.&lt;/p&gt;

&lt;p&gt;In contrast, React Web still relies on the Virtual DOM, which, while optimized, does not achieve the same level of native performance improvements seen with Fabric.&lt;/p&gt;

&lt;p&gt;By understanding the differences, use cases, and optimizations available in React Web and React Native 0.76, developers can build highly performant applications tailored to their respective platforms.&lt;/p&gt;

&lt;p&gt;If you have experience optimizing reconciliation with React Web or React Native 0.76, share your insights in the comments below!&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>How Arrow Functions Work with useEffect in React: An In-Depth Guide</title>
      <dc:creator>Sagnik Ghosh</dc:creator>
      <pubDate>Fri, 17 Jan 2025 19:15:17 +0000</pubDate>
      <link>https://dev.to/nik26_/how-arrow-functions-work-with-useeffect-in-react-an-in-depth-guide-l98</link>
      <guid>https://dev.to/nik26_/how-arrow-functions-work-with-useeffect-in-react-an-in-depth-guide-l98</guid>
      <description>&lt;p&gt;During a recent interview, I was asked an intriguing question about hoisting and its interaction with React. Specifically, the interviewer wanted to know why, in React, an arrow function defined below a useEffect hook can still be called inside that useEffect. Although I could not properly answer it but this question piqued my interest, and I decided to dive deep into the underlying concepts. Here’s what I found.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Scenario&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s the situation described in the question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect } from "react";

const MyComponent = () =&amp;gt; {
  useEffect(() =&amp;gt; {
    myArrowFunction(); // This works!
  }, []);

  const myArrowFunction = () =&amp;gt; {
    console.log("Arrow function called");
  };

  return &amp;lt;div&amp;gt;Check the console&amp;lt;/div&amp;gt;;
};

export default MyComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, it may seem surprising that this code works. After all, we know that arrow functions are not hoisted, unlike regular function declarations. So, why does React’s &lt;code&gt;useEffect&lt;/code&gt; behave as if the function was defined before it was called?&lt;/p&gt;

&lt;p&gt;To understand this, we need to break down several core JavaScript and React concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. What Is Hoisting in JavaScript?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Hoisting is a behavior in JavaScript where variable and function declarations are moved to the top of their scope during the compilation phase, even before the code is executed. This means you can use certain variables or functions before they are explicitly defined in the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function Declarations vs. Function Expressions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function Declarations&lt;/strong&gt;: These are hoisted entirely-both the variable and the function body are available before the line where they are defined.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hello(); // Works!

function hello() {
  console.log("Hello, world!");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function Expressions&lt;/strong&gt;: These are not hoisted in the same way. Only the variable name is hoisted, not the function body. This means you’ll encounter a TypeError if you try to call the function before it is assigned.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hello(); // TypeError: hello is not a function

const hello = function () {
  console.log("Hello, world!");
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Arrow Functions&lt;/strong&gt;&lt;br&gt;
Arrow functions are a special type of function expression. Like regular function expressions, only their variable name is hoisted—the actual function body remains uninitialized until the code execution reaches the assignment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myArrowFunction(); // TypeError: myArrowFunction is not a function

const myArrowFunction = () =&amp;gt; {
  console.log("Arrow function");
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;2. How React’s useEffect Works&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In React, the &lt;code&gt;useEffect&lt;/code&gt; hook allows you to perform side effects after the render phase of a component. Importantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;useEffect&lt;/code&gt; Executes After Rendering:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;React does not execute the &lt;code&gt;useEffect&lt;/code&gt; callback during the initial rendering phase. Instead, it schedules the &lt;code&gt;useEffect&lt;/code&gt; callback to run after the DOM has been updated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This means that by the time &lt;code&gt;useEffect&lt;/code&gt; runs, the entire body of the component function has already been executed, ensuring that all variables and functions within the component scope are fully initialized.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Function Scope and Execution Context:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;useEffect&lt;/code&gt; hook has access to all variables and functions defined within the same scope. Since &lt;code&gt;myArrowFunction&lt;/code&gt; is defined in the component scope, it is available for use when the &lt;code&gt;useEffect&lt;/code&gt; callback is executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Why the Arrow Function Works in useEffect&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now let’s apply these concepts to the code in question. Here’s a step-by-step explanation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Component Rendering&lt;/strong&gt;&lt;br&gt;
When the component is rendered, the following happens in order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;JavaScript parses the &lt;code&gt;MyComponent&lt;/code&gt; function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It encounters the &lt;code&gt;useEffect&lt;/code&gt; call and registers the callback to be executed later (after rendering).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It initializes the variable &lt;code&gt;myArrowFunction&lt;/code&gt; with the arrow function.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the time React executes the &lt;code&gt;useEffect&lt;/code&gt; callback, the &lt;code&gt;myArrowFunction&lt;/code&gt; has already been defined, so it can be called without any issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Execution Lifecycle&lt;/strong&gt;&lt;br&gt;
Here’s how the lifecycle works in this case:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Code Parsing:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The entire &lt;code&gt;MyComponent&lt;/code&gt; function is parsed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is registered, and &lt;code&gt;myArrowFunction&lt;/code&gt; is initialized.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Rendering:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The component’s output is rendered to the DOM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;useEffect Execution:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;After rendering, React runs the &lt;code&gt;useEffect&lt;/code&gt; callback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At this point, &lt;code&gt;myArrowFunction&lt;/code&gt; is fully defined and ready to use.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Common Misunderstandings&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Misconception: Arrow Functions Are Hoisted&lt;/strong&gt;&lt;br&gt;
Arrow functions themselves are not hoisted. In this case, it works because &lt;code&gt;useEffect&lt;/code&gt; runs after the function body has been fully executed, not because of hoisting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Misconception: &lt;code&gt;useEffect&lt;/code&gt; Runs Inline&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;useEffect&lt;/code&gt; does not execute inline during the parsing phase. It is scheduled to run after the render phase, ensuring all variables and functions in the component scope are available.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. Temporal Dead Zone and React&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;Temporal Dead Zone (TDZ)&lt;/em&gt;&lt;/strong&gt; refers to the period between the start of a variable’s scope and its actual declaration where it cannot be accessed. In the code example, there is no TDZ issue because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;myArrowFunction&lt;/code&gt; is declared before the &lt;code&gt;useEffect&lt;/code&gt; is executed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React’s lifecycle ensures that the &lt;code&gt;useEffect&lt;/code&gt; callback does not run until after the component function has completed execution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;6. Summary&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To summarize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hoisting in JavaScript:&lt;/strong&gt; Arrow functions are not hoisted, but variables declared with &lt;code&gt;const&lt;/code&gt; or &lt;code&gt;let&lt;/code&gt; are scoped to their block and are accessible after their declaration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;React Lifecycle:&lt;/strong&gt; &lt;code&gt;useEffect&lt;/code&gt; does not execute immediately; it waits until the component has rendered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Execution Order:&lt;/strong&gt; By the time the &lt;code&gt;useEffect&lt;/code&gt; callback runs, all variables and functions within the component scope are initialized, including arrow functions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combination of JavaScript behavior and React’s execution model explains why you can use an arrow function inside a &lt;code&gt;useEffect&lt;/code&gt;, even if it appears to be declared "later" in the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;7. Key Takeaways for Interviews&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you’re asked this in an interview, here’s a concise way to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Arrow functions are not hoisted, but React’s &lt;code&gt;useEffect&lt;/code&gt; executes after the component has been rendered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This ensures that any arrow function defined in the component scope is fully initialized and accessible by the time &lt;code&gt;useEffect&lt;/code&gt; runs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The behavior relies on React’s lifecycle and JavaScript’s execution order, not on hoisting.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By understanding the interplay between JavaScript’s scoping rules and React’s rendering lifecycle, you can confidently tackle questions like this and demonstrate your expertise in modern JavaScript and React.&lt;/p&gt;

&lt;p&gt;Feel free to share your thoughts or ask questions in the comments! Let’s discuss and learn together.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>interview</category>
    </item>
    <item>
      <title>A Deep Dive into Promises and Their Real-World Applications</title>
      <dc:creator>Sagnik Ghosh</dc:creator>
      <pubDate>Mon, 13 Jan 2025 19:04:17 +0000</pubDate>
      <link>https://dev.to/nik26_/a-deep-dive-into-promises-and-their-real-world-applications-9db</link>
      <guid>https://dev.to/nik26_/a-deep-dive-into-promises-and-their-real-world-applications-9db</guid>
      <description>&lt;p&gt;In modern JavaScript, asynchronous programming has become an integral part of application development. Promises play a pivotal role in managing asynchronous operations effectively. This blog delves deep into JavaScript Promises, their APIs, practical scenarios, examples, and their pros and cons.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is a Promise in JavaScript?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A Promise in JavaScript is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value. It serves as a placeholder for the result of an operation that hasn’t completed yet but is expected in the future.&lt;/p&gt;

&lt;p&gt;The Three States of a Promise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Pending&lt;/em&gt;:&lt;/strong&gt; Initial state, neither fulfilled nor rejected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fulfilled&lt;/em&gt;:&lt;/strong&gt; The operation completed successfully, and the promise has a resulting value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Rejected&lt;/em&gt;:&lt;/strong&gt; The operation failed, and the promise has a reason for the failure.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Creating a Promise&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s how you can create a simple Promise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myPromise = new Promise((resolve, reject) =&amp;gt; {
  const success = true; // Simulating success or failure

  if (success) {
    resolve("Operation succeeded!");
  } else {
    reject("Operation failed!");
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Consuming Promises&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Promises are consumed using .then(), .catch(), and .finally():&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myPromise
  .then(result =&amp;gt; {
    console.log(result); // Logs: "Operation succeeded!"
  })
  .catch(error =&amp;gt; {
    console.error(error); // Logs: "Operation failed!"
  })
  .finally(() =&amp;gt; {
    console.log("Operation completed.");
  });

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Promise APIs in Depth&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promise.resolve():&lt;/strong&gt;
This method creates a promise that is immediately resolved with the provided value. It is useful for wrapping non-promise values into a promise for consistency.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Promise.resolve("Quick resolve").then(value =&amp;gt; console.log(value));
// Logs: "Quick resolve"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Promise.reject():&lt;/strong&gt;
This method creates a promise that is immediately rejected with the provided reason. It’s typically used to simulate errors or pass rejections in promise chains.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Promise.reject("Quick reject").catch(reason =&amp;gt; console.error(reason));
// Logs: "Quick reject"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promise.all():&lt;/strong&gt;
This method takes an array of promises and returns a single promise that resolves when all promises have resolved or rejects as soon as one promise rejects. It is often used when multiple asynchronous tasks need to complete together.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const promises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
];

Promise.all(promises).then(values =&amp;gt; console.log(values));
// Logs: [1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promise.allSettled():&lt;/strong&gt;
This method takes an array of promises and returns a promise that resolves after all promises have settled, regardless of whether they are resolved or rejected. It is useful when you want to handle both outcomes for all promises.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const promises = [
  Promise.resolve(1),
  Promise.reject("Error"),
  Promise.resolve(3)
];

Promise.allSettled(promises).then(results =&amp;gt; console.log(results));
/* Logs:
[
  { status: "fulfilled", value: 1 },
  { status: "rejected", reason: "Error" },
  { status: "fulfilled", value: 3 }
]
*/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promise.race():&lt;/strong&gt;
This method takes an array of promises and returns a single promise that resolves or rejects as soon as the first promise in the array resolves or rejects. It’s ideal for timeout scenarios.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const promises = [
  new Promise(resolve =&amp;gt; setTimeout(() =&amp;gt; resolve("Fast"), 100)),
  new Promise(resolve =&amp;gt; setTimeout(() =&amp;gt; resolve("Slow"), 500))
];

Promise.race(promises).then(value =&amp;gt; console.log(value));
// Logs: "Fast"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Promise.any()&lt;/strong&gt;
This method takes an array of promises and resolves with the value of the first promise that fulfills. If all promises are rejected, it returns an AggregateError. It’s useful when you only care about the first successful outcome.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const promises = [
  Promise.reject("Error"),
  Promise.resolve("First success"),
  Promise.resolve("Second success")
];

Promise.any(promises).then(value =&amp;gt; console.log(value));
// Logs: "First success"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Practical Scenarios&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fetching Data from Multiple APIs&lt;/strong&gt;
Imagine needing user information and their associated posts. You can handle both requests simultaneously:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const userPromise = fetch("https://api.example.com/user").then(res =&amp;gt; res.json());
const postsPromise = fetch("https://api.example.com/posts").then(res =&amp;gt; res.json());

Promise.all([userPromise, postsPromise])
  .then(([user, posts]) =&amp;gt; {
    console.log("User:", user);
    console.log("Posts:", posts);
  })
  .catch(error =&amp;gt; console.error("Error fetching data:", error));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sequential Execution of Dependent Promises&lt;/strong&gt;
Some operations depend on the completion of prior tasks. Here’s 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;fetch("https://api.example.com/authenticate")
  .then(response =&amp;gt; response.json())
  .then(authData =&amp;gt; {
    return fetch(`https://api.example.com/user/${authData.userId}`);
  })
  .then(response =&amp;gt; response.json())
  .then(userData =&amp;gt; console.log("User Data:", userData))
  .catch(error =&amp;gt; console.error("Error:", error));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retry Mechanism&lt;/strong&gt;
To handle transient network errors, you can implement a retry mechanism:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function retryPromise(fn, retries) {
  return fn().catch(err =&amp;gt; {
    if (retries &amp;gt; 0) {
      return retryPromise(fn, retries - 1);
    } else {
      throw err;
    }
  });
}

retryPromise(() =&amp;gt; fetch("https://api.example.com/data"), 3)
  .then(response =&amp;gt; response.json())
  .then(data =&amp;gt; console.log(data))
  .catch(err =&amp;gt; console.error("Failed after retries:", err));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timeout Handling&lt;/strong&gt;
Handling operations that take too long:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fetchWithTimeout(url, timeout) {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) =&amp;gt; setTimeout(() =&amp;gt; reject("Request timed out"), timeout))
  ]);
}

fetchWithTimeout("https://api.example.com/data", 5000)
  .then(response =&amp;gt; response.json())
  .then(data =&amp;gt; console.log(data))
  .catch(err =&amp;gt; console.error(err));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chaining Multiple Asynchronous Tasks&lt;/strong&gt;
For tasks requiring step-by-step execution:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function task1() {
  return new Promise(resolve =&amp;gt; setTimeout(() =&amp;gt; resolve("Task 1 completed"), 1000));
}

function task2() {
  return new Promise(resolve =&amp;gt; setTimeout(() =&amp;gt; resolve("Task 2 completed"), 2000));
}

task1()
  .then(result1 =&amp;gt; {
    console.log(result1);
    return task2();
  })
  .then(result2 =&amp;gt; {
    console.log(result2);
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Pros and Cons of Promises&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Pros:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;em&gt;Readable Code:&lt;/em&gt;&lt;/em&gt;&lt;/strong&gt; Promises make asynchronous code more readable compared to nested callbacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Error Handling:&lt;/em&gt;&lt;/strong&gt; Centralized error handling with .catch().&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Chaining:&lt;/em&gt;&lt;/strong&gt; Easy to chain multiple asynchronous operations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Cons:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Complexity:&lt;/em&gt;&lt;/strong&gt; Understanding edge cases with .race(), .all(), or .allSettled() can be challenging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Debugging:&lt;/em&gt;&lt;/strong&gt; Tracing the source of errors can sometimes be difficult in complex promise chains.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Understanding the Critical Render Path and Its Role in Web Performance</title>
      <dc:creator>Sagnik Ghosh</dc:creator>
      <pubDate>Mon, 13 Jan 2025 17:11:15 +0000</pubDate>
      <link>https://dev.to/nik26_/understanding-the-critical-render-path-and-its-role-in-web-performance-24c5</link>
      <guid>https://dev.to/nik26_/understanding-the-critical-render-path-and-its-role-in-web-performance-24c5</guid>
      <description>&lt;p&gt;Web performance is a critical factor in modern development, directly impacting user experience, engagement, and conversion rates. The Critical Render Path (CRP) is a core concept in optimizing web performance. By understanding and optimizing the CRP, developers can significantly improve the speed at which web pages load and become interactive. Let’s dive into what the CRP entails, why it matters, and how to optimize it based on insights from web.dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Web Performance Matters
&lt;/h2&gt;

&lt;p&gt;Speed is at the heart of web performance. According to &lt;a href="https://web.dev/learn/performance/why-speed-matters" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt;, fast-loading websites lead to better user engagement, retention, and overall satisfaction. Slow websites, on the other hand, frustrate users, leading to higher bounce rates and lost opportunities. Performance isn’t just about milliseconds, it’s about creating seamless experiences that respect users’ time.&lt;/p&gt;

&lt;p&gt;Google have spent some considerable amount of time creating user centric performance metrics which are known as Core Web Vitals. Here is a list of some case studies which highlights the connection between performance and business outcomes based on these core web vitals - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/case-studies/economic-times-cwv?authuser=1" rel="noopener noreferrer"&gt;How The Economic Times passed Core Web Vitals thresholds and achieved an overall 43% better bounce rate&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/case-studies/renault?authuser=1" rel="noopener noreferrer"&gt;How Renault improved its bounce and conversion rates by measuring and optimizing Largest Contentful Paint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/case-studies/rakuten?authuser=1" rel="noopener noreferrer"&gt;How Rakuten 24's investment in Core Web Vitals increased revenue per visitor by 53.37% and conversion rate by 33.13%&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/case-studies/vodafone?authuser=1" rel="noopener noreferrer"&gt;Vodafone: A 31% improvement in LCP increased sales by 8% &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/case-studies/redbus-inp?authuser=1" rel="noopener noreferrer"&gt;How redBus improved their website's Interaction to Next Paint (INP) and increased sales by 7%&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Role of the Critical Render Path
&lt;/h2&gt;

&lt;p&gt;The Critical Render Path refers to the sequence of steps the browser takes to convert HTML, CSS, and JavaScript into pixels on the screen. Every web page has its unique CRP, influenced by the content structure, resource size, and dependencies. Optimizing the CRP ensures a faster path from the server to the user’s viewable content.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Key Stages in the Critical Render Path&lt;/em&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;HTML Parsing&lt;/strong&gt;: The browser parses the HTML document to construct the Document Object Model (DOM).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSSOM Construction&lt;/strong&gt;: The browser processes CSS files to build the CSS Object Model (CSSOM).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript Execution&lt;/strong&gt;: If the HTML references external or inline JavaScript, the browser may pause parsing to execute scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render Tree Construction&lt;/strong&gt;: The DOM and CSSOM combine to form the Render Tree, representing elements to be displayed with their styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout and Paint&lt;/strong&gt;: The browser calculates the layout of elements and paints pixels on the screen.&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%2Fgi2a1qw5tnfreab59r5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgi2a1qw5tnfreab59r5b.png" alt="Stages to render CRP" width="691" height="833"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Content of this Image is sourced from &lt;a href="https://web.dev/" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Only after all these steps have been completed, will the user see content on the screen. The critical rendering path focuses on the process outlined for the initial render, and depends on the critical resources necessary for it. And in between re-rendering happens multiple times as more resources which affect page's rendering becomes available to update what the user sees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources on the Critical rendering path
&lt;/h2&gt;

&lt;p&gt;Here’s an overview of the resources that influence the critical rendering path and how browsers handle them -&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;1. Critical Resources for Initial Rendering&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The browser requires certain resources to complete the initial page render, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;: Key portions are processed as they arrive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Render-blocking CSS&lt;/strong&gt;: Typically in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Render-blocking JavaScript&lt;/strong&gt;: Typically in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;2. What the Browser Doesn’t Wait For&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;For efficiency, the browser doesn’t halt the initial render for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;All HTML&lt;/strong&gt;: Rendering starts with the available portions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fonts&lt;/strong&gt;: Text may be temporarily invisible until fonts load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Images&lt;/strong&gt;: Space may be reserved, but the browser moves forward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Non-render-blocking JavaScript&lt;/strong&gt;: Often placed outside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; or marked as async or defer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Non-render-blocking CSS&lt;/strong&gt;: Includes styles with media attributes irrelevant to the current viewport.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;3. The Role of the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; Element&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; contains metadata and critical resources that guide rendering. It does not include visible content but ensures the browser knows how to render the visible content in the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;element.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;4. Render-Blocking Resources&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Render-blocking resources pause rendering until they’re downloaded and processed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;: Blocks rendering by default unless its media attribute makes it non-applicable to the current conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recent Innovations&lt;/strong&gt;: The &lt;code&gt;blocking=render&lt;/code&gt; attribute allows developers to explicitly manage rendering-blocking elements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;what is FOUC?&lt;/strong&gt;&lt;br&gt;
CSS is considered a render-blocking resource because it prevents the browser from displaying any content until the CSS Object Model (CSSOM) is fully constructed. This behavior ensures a seamless user experience by avoiding a Flash of Unstyled Content (FOUC), where the page appears briefly without styling before the CSS is applied.&lt;/p&gt;

&lt;p&gt;While FOUC is typically brief and may go unnoticed, understanding its implications is essential. The browser delays rendering to maintain a polished appearance, but prolonged render blocking can negatively impact performance. To address this, ensure your CSS is efficient and well-optimized to reduce the time it takes for the page to display fully styled content.&lt;/p&gt;

&lt;p&gt;Here is a sample video clip of FOUC taken from &lt;a href="https://web.dev/" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt; where you can see the page without any styling and all styles are applied once the page's CSS has finished loading from the network. &lt;br&gt;
&lt;a href="https://web.dev/static/learn/performance/optimize-resource-loading/video/fouc.webm?authuser=1" rel="noopener noreferrer"&gt;Example of FOUC&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;5. Parser-Blocking Resources&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;These resources halt the browser’s ability to parse HTML further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt;: By default, it blocks parsing unless marked &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;. This ensures DOM and CSSOM stability before execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Browsers mitigate parser blocking with techniques like the preload scanner, which downloads resources in advance to reduce delays.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;6. Identifying Blocking Resources&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Tools like WebPageTest and Lighthouse help developers pinpoint performance bottlenecks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebPageTest&lt;/strong&gt;: Marks render-blocking resources with an orange circle in its network waterfall diagram.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lighthouse&lt;/strong&gt;: Highlights resources only if they delay rendering, avoiding false positives.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Optimizing the Critical Render Path
&lt;/h2&gt;

&lt;p&gt;So now that we have understood what a Critical Rendering Path (CRP) is and how different resources affect it's path while rendering, It's time to know how to optimize the CRP for better web performance, ensuring faster page load times, and enhancing user experience. Below are key strategies to streamline the CRP -&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;1. Efficient HTML Structure&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;As highlighted in &lt;a href="https://web.dev/learn/performance/general-html-performance" rel="noopener noreferrer"&gt;General HTML Performance&lt;/a&gt;, clean and semantic HTML is essential. Avoid excessive DOM depth and unnecessary elements, as they can complicate the rendering process. Use modern HTML standards to ensure compatibility and efficiency.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;2. Minimize Critical Resources&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Critical resources are those required to render the first paint of the page. To optimize their impact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Eliminate unnecessary resources&lt;/strong&gt;: Remove unused CSS, JavaScript, and large media files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inline critical CSS&lt;/strong&gt;: Embed only the CSS needed for above-the-fold content directly into the HTML.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;3. Optimize Resource Loading&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Efficient resource loading can significantly reduce delays:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;defer&lt;/code&gt; for JavaScript: These attributes prevent JavaScript from blocking the parsing of HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;async&lt;/code&gt;: Scripts load independently and execute as soon as they are ready.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;defer&lt;/code&gt;: Scripts load in order and execute after the HTML parsing is complete.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lazy-load non-critical resources&lt;/strong&gt;: Images, videos, and other resources not immediately visible can be loaded only when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;4. Prioritize Critical Resources&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Ensure the browser prioritizes the most important resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preload key resources&lt;/strong&gt;: Use the &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt; tag for fonts, images, and other assets required early in the rendering process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduce the size of critical resources&lt;/strong&gt;: Minify CSS, JavaScript, and compress images to decrease file sizes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;5. Reduce the Number of Critical Path Length&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Shortening the CRP involves reducing the number of render-blocking requests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Combine CSS and JavaScript files&lt;/strong&gt;: Fewer requests translate to shorter load times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Eliminate render-blocking CSS and JavaScript&lt;/strong&gt;: Defer or asynchronously load these files to allow the page to render sooner.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;6. Optimize Web Fonts&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Fonts can delay the first paint and add to the CRP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use font-display: swap&lt;/strong&gt;: This CSS property ensures text is displayed using fallback fonts until the web font is fully loaded.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preload fonts&lt;/strong&gt;: Preload key font files to make them available earlier in the rendering process.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Measuring and Monitoring Performance
&lt;/h2&gt;

&lt;p&gt;Optimization doesn’t end with implementation. Regularly measure performance using tools like Lighthouse or WebPageTest to analyze the CRP. Look for metrics such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;First Contentful Paint (FCP)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time to Interactive (TTI)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Largest Contentful Paint (LCP)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Identify bottlenecks and iteratively improve based on data.&lt;/p&gt;

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

&lt;p&gt;The Critical Render Path is a vital aspect of web performance. By understanding its components and employing optimization techniques, developers can create faster, more engaging websites. Remember, performance is a journey, not a destination. Continuously monitor, test, and refine your strategies to stay ahead in delivering exceptional user experiences.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
