<?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: Mawuli Denteh</title>
    <description>The latest articles on DEV Community by Mawuli Denteh (@mawulikode).</description>
    <link>https://dev.to/mawulikode</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%2F1117990%2F5edc9eed-f107-43b1-a8ef-431a3344cb33.jpeg</url>
      <title>DEV Community: Mawuli Denteh</title>
      <link>https://dev.to/mawulikode</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mawulikode"/>
    <language>en</language>
    <item>
      <title>Create a cloud-backed IDE for development</title>
      <dc:creator>Mawuli Denteh</dc:creator>
      <pubDate>Thu, 23 Oct 2025 23:32:19 +0000</pubDate>
      <link>https://dev.to/aws-builders/create-a-cloud-backed-ide-for-development-1f64</link>
      <guid>https://dev.to/aws-builders/create-a-cloud-backed-ide-for-development-1f64</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I find it burdensome creating and configuring my development environment all over again when using a new laptop or system.&lt;/p&gt;

&lt;p&gt;The need for speed when installing packages, extensions, and compiling code is also very important, and the network plays a big role in that.&lt;/p&gt;

&lt;p&gt;After setting it all up, I also don’t want anything to disrupt the environment. I also want to be able to log in or access it reliably and easily anytime I need from any machine without having to set it all up again.&lt;/p&gt;

&lt;p&gt;Having dealt with this scenario many times, I found a way to create this environment, call upon it when I need and put it off when I don’t — and also have the ability to back it up anytime I make progress with new states of the storage/system.&lt;/p&gt;

&lt;p&gt;This may not be for everyone, but I think many developers may find value in this setup depending on their situation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Create a Linux server in the cloud and use &lt;strong&gt;VS Code’s Remote SSH&lt;/strong&gt; feature to securely access it, with the capability to manage the file system from the editor like you would locally.  &lt;/p&gt;

&lt;p&gt;I call it “The DevBox”. Sounds cool, doesn’t it? Let’s build it.&lt;/p&gt;




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

&lt;p&gt;This solution is going to cost a roughly fixed amount per month for &lt;strong&gt;EBS storage and snapshots (minimal)&lt;/strong&gt; and a variable amount for &lt;strong&gt;EC2 compute&lt;/strong&gt;, depending on how many hours you keep the server up in a month.  &lt;/p&gt;

&lt;p&gt;Take note and check the cost of what you are going to build (using the &lt;strong&gt;AWS Pricing Calculator&lt;/strong&gt;) based on how you will use it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 – Create a Dedicated Network for the DevBox
&lt;/h2&gt;

&lt;p&gt;I chose to create a small &lt;strong&gt;VPC with a /24 network&lt;/strong&gt;, which is just ideal for this case.  &lt;/p&gt;

&lt;p&gt;You can optionally add an &lt;strong&gt;S3 Private Gateway Endpoint&lt;/strong&gt; for no extra charge. This would be useful for copying files from authorized S3 buckets into your environment when needed.&lt;/p&gt;

&lt;p&gt;I chose a simple &lt;strong&gt;public subnet design&lt;/strong&gt; with a &lt;strong&gt;restricted instance security group&lt;/strong&gt; allowing &lt;strong&gt;SSH access only from my IP address&lt;/strong&gt;.&lt;/p&gt;

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

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

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

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




&lt;h2&gt;
  
  
  Step 2 – Create the DevBox EC2 Instance
&lt;/h2&gt;

&lt;p&gt;You can go with the latest &lt;strong&gt;Amazon Linux AMI&lt;/strong&gt; or &lt;strong&gt;Ubuntu 24.04 LTS&lt;/strong&gt;, which I used in this setup.&lt;/p&gt;

&lt;p&gt;Restrict &lt;strong&gt;SSH access to your IP&lt;/strong&gt; in the security group for security.&lt;/p&gt;

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

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

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

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

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvv8b4jdst28ozqr10o5.png" width="800" height="1252"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Step 3 – Configure SSH Access in VS Code
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Right-click the left panel of your &lt;strong&gt;VS Code editor&lt;/strong&gt; and ensure the &lt;strong&gt;Remote Explorer&lt;/strong&gt; is checked.
&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%2Ffeiumykh165dxjw05chj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffeiumykh165dxjw05chj.png" width="550" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Right-click on &lt;strong&gt;SSH&lt;/strong&gt; and open the config file.
&lt;/li&gt;
&lt;li&gt;Edit the config file as shown below:&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt;: Varies depending on the AMI you use.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IdentityFile&lt;/strong&gt;: Points to the location of your key file.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HostName&lt;/strong&gt;: The remote server IP address.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ol&gt;
&lt;li&gt;Connect in a &lt;strong&gt;new window&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Confirm the step by hitting the &lt;strong&gt;Enter&lt;/strong&gt; key. &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%2Ff0bzq2tnjovtropq93n9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0bzq2tnjovtropq93n9.png" width="800" height="144"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It should take a few seconds to connect and configure — and boom! You’re connected via SSH within VS Code, while utilizing &lt;strong&gt;cloud storage and networking&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install your packages and set up your environment as needed.
&lt;/li&gt;
&lt;li&gt;Expand the storage as you grow.
&lt;/li&gt;
&lt;li&gt;Optionally add a &lt;strong&gt;second EBS volume&lt;/strong&gt; as the data/working volume.
&lt;/li&gt;
&lt;li&gt;Connect to an &lt;strong&gt;S3 bucket&lt;/strong&gt; within your account via the S3 Gateway.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Back up&lt;/strong&gt; the volume, stop, and/or terminate the instance as needed.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>architecture</category>
      <category>cloud</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Customize VPCs with CloudFormation Conditions</title>
      <dc:creator>Mawuli Denteh</dc:creator>
      <pubDate>Mon, 13 Jan 2025 03:29:22 +0000</pubDate>
      <link>https://dev.to/aws-builders/customizable-vpcs-with-cloudformation-conditions-2af7</link>
      <guid>https://dev.to/aws-builders/customizable-vpcs-with-cloudformation-conditions-2af7</guid>
      <description>&lt;p&gt;Using CloudFormation Conditions you can decide which resources to create/configure from your CloudFormation template. &lt;/p&gt;

&lt;p&gt;In this post, we are going to build a template that can create a VPC with private subnets and a NAT gateway or only public subnets depending on a parameter when creating the CloudFormation stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to create and use Conditions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Define the input parameters you want your condition to evaluate.&lt;/li&gt;
&lt;li&gt;Define the condition by using the intrinsic condition functions. &lt;/li&gt;
&lt;li&gt;Declare the condition in resources or outputs you want to create. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's dive into the example!&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the parameter and condition
&lt;/h2&gt;

&lt;p&gt;In the first part of our template, we'll define our parameter and condition.&lt;/p&gt;

&lt;p&gt;We associate the &lt;em&gt;CreatePrivateResources&lt;/em&gt; condition with a value/option from our &lt;em&gt;CreateNatGateway&lt;/em&gt; parameter. This enables us to do what has been discussed in the intro above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parameters:
  CreateNatGateway:
    Type: String
    Description: "Need a NAT Gateway?"
    AllowedValues:
      - yes
      - no
    Default: yes

Conditions:
  CreatePrivateResources: !Equals
    - !Ref CreateNatGateway
    - yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Define the public resources&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here, we will define our VPC, internet gateway, public subnets, routes and route tables. These resources will always be created. This is because they will not have any condition associated with them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: "10.0.0.0/16"
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-VPC"

  # Public Resources
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-InternetGateway"

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.1.0/24"
      MapPublicIpOnLaunch: true
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PublicSubnet1"

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.2.0/24"
      MapPublicIpOnLaunch: true
      AvailabilityZone: !Select [1, !GetAZs ""]
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PublicSubnet2"

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PublicRouteTable"

  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Use the condition&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We now apply our condition to selected resources which creates a private environment for us, i.e. NatGateway, private subnets and routes etc. If we choose no at the prompt, these will not get created.&lt;/p&gt;

&lt;p&gt;We also control the display of outputs using the same conditions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Private Resources
  NatGateway:
    Condition: CreatePrivateResources
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt EIPNatGateway.AllocationId
      SubnetId: !Ref PublicSubnet1
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-NatGateway"

  EIPNatGateway:
    Condition: CreatePrivateResources
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-EIPNatGateway"

  PrivateSubnet1:
    Condition: CreatePrivateResources
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.3.0/24"
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PrivateSubnet1"

  PrivateSubnet2:
    Condition: CreatePrivateResources
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.4.0/24"
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Select [1, !GetAZs ""]
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PrivateSubnet2"

  PrivateRouteTable:
    Condition: CreatePrivateResources
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PrivateRouteTable"

  PrivateRoute:
    Condition: CreatePrivateResources
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NatGateway

  PrivateSubnet1RouteTableAssociation:
    Condition: CreatePrivateResources
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnet2RouteTableAssociation:
    Condition: CreatePrivateResources
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable

Outputs:
  VPCId:
    Description: "VPC ID"
    Value: !Ref VPC
  PublicSubnet1Id:
    Description: "Public Subnet 1 ID"
    Value: !Ref PublicSubnet1
  PublicSubnet2Id:
    Description: "Public Subnet 2 ID"
    Value: !Ref PublicSubnet2
  PrivateSubnet1Id:
    Condition: CreatePrivateResources
    Description: "Private Subnet 1 ID"
    Value: !Ref PrivateSubnet1
  PrivateSubnet2Id:
    Condition: CreatePrivateResources
    Description: "Private Subnet 2 ID"
    Value: !Ref PrivateSubnet2
  NatGatewayId:
    Condition: CreatePrivateResources
    Description: "NAT Gateway ID"
    Value: !Ref NatGateway

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

&lt;/div&gt;



&lt;p&gt;You can now customize your VPC creation just by changing a parameter. &lt;br&gt;
Thanks for reading. Happy Building!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>vpc</category>
      <category>cloudformation</category>
      <category>iac</category>
    </item>
    <item>
      <title>Create a load-balanced web server with auto-scaling</title>
      <dc:creator>Mawuli Denteh</dc:creator>
      <pubDate>Wed, 06 Mar 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/create-a-load-balanced-web-server-with-auto-scaling-6d</link>
      <guid>https://dev.to/aws-builders/create-a-load-balanced-web-server-with-auto-scaling-6d</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;This tutorial walks you through the process of creating web servers, managed by an auto scaling group. The auto scaling group uses a launch template to create the servers. The auto scaling group launches the servers into a target group. An internet-facing load balancer directs traffic to the target group.&lt;/p&gt;



&lt;h2&gt;
  
  
  Architecture Diagram
&lt;/h2&gt;

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



&lt;h2&gt;
  
  
  1. Create a VPC
&lt;/h2&gt;

&lt;p&gt;A VPC is an isolated, private network you can create to run your workloads. You have complete control over your VPC when you create one.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;a href="https://us-east-1.console.aws.amazon.com/vpc/home?region=us-east-1#CreateVpc:createMode=vpcWithResources" rel="noopener noreferrer"&gt;Create VPC&lt;/a&gt; from the VPC Dashboard to create a new VPC.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;VPC and more&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter a name under &lt;strong&gt;Auto-generate&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose a &lt;strong&gt;10.0.0.0/16&lt;/strong&gt; IPV4 Cidr block.&lt;/li&gt;
&lt;li&gt;Number of Availability Zones (AZs) = 2.&lt;/li&gt;
&lt;li&gt;Number of public subnets = 2.&lt;/li&gt;
&lt;li&gt;Number of private subnets = 0.&lt;/li&gt;
&lt;li&gt;NAT gateways ($): None.&lt;/li&gt;
&lt;li&gt;VPC endpoints = None.&lt;/li&gt;
&lt;li&gt;Leave all other settings as default.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create VPC&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9MKsavNn_pQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  2. Create a Launch Template
&lt;/h2&gt;

&lt;p&gt;The launch template will serve as the blueprint for creating the exact type of server we need to meet our web server demands. A launch template can be modified to create new versions when you need to change a configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;a href="https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#CreateTemplate:" rel="noopener noreferrer"&gt;Create launch template&lt;/a&gt; from the EC2 console to create a new launch template.&lt;/li&gt;
&lt;li&gt;Launch template name - required.&lt;/li&gt;
&lt;li&gt;Check the &lt;strong&gt;Provide guidance to help me set up a template that I can use with EC2 Auto Scaling&lt;/strong&gt; box.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Application and OS Images (Amazon Machine Image) - required&lt;/strong&gt;, choose &lt;strong&gt;Amazon Linux 2023 AMI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Instance type = &lt;strong&gt;t2.micro&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Key pair - Proceed without a keypair.&lt;/li&gt;
&lt;li&gt;Subnet - &lt;strong&gt;Don't include in launch template&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create security group.&lt;/li&gt;
&lt;li&gt;Allow HTTP traffic from 0.0.0.0/0 (Ignore the warning about security group. We will edit it later).&lt;/li&gt;
&lt;li&gt;VPC - Select the VPC you created.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Advanced network configuration&lt;/strong&gt;, choose &lt;strong&gt;Enable&lt;/strong&gt; under &lt;strong&gt;Auto-assign public IP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Storage&lt;/strong&gt;, leave all other configuration as default and choose &lt;strong&gt;"gp3"&lt;/strong&gt; for &lt;strong&gt;Volume type&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Resource tags: optional.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Advanced details&lt;/strong&gt;, scroll down to the &lt;strong&gt;User data&lt;/strong&gt; section and enter the following lines of code exactly as shown:&lt;/li&gt;
&lt;/ol&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "&amp;lt;h1&amp;gt;Hello World from $(hostname -f)&amp;lt;/h1&amp;gt;" &amp;gt; /var/www/html/index.html
systemctl restart httpd
amazon-linux-extras enable epel
yum install -y stress
cat &amp;lt;&amp;lt; 'EOF' &amp;gt; /home/ec2-user/start_stress.sh
#!/bin/bash
sleep 240
vcpus=$(nproc)
workers=$vcpus
stress --cpu "$workers" --timeout 300
EOF
chmod +x /home/ec2-user/start_stress.sh
nohup /home/ec2-user/start_stress.sh &amp;gt; /home/ec2-user/start_stress.log 2&amp;gt;&amp;amp;1 &amp;amp;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/J_a9zdVQRmo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  3. Create Target Group
&lt;/h2&gt;

&lt;p&gt;A target group will route requests to the web servers we create. Our load balancer will need this target group to know what set of servers to distribute traffic to. Our auto scaling group will also be associated with this target group so it launches our servers into the target group.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;a href="https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#CreateTargetGroup:" rel="noopener noreferrer"&gt;Create target group&lt;/a&gt; from the EC2 console to create a target group.&lt;/li&gt;
&lt;li&gt;Choose a target type: &lt;strong&gt;Instances&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Target group name: Enter a name.&lt;/li&gt;
&lt;li&gt;Protocol: &lt;strong&gt;HTTP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Port: &lt;strong&gt;80&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;VPC: Select the VPC you created.&lt;/li&gt;
&lt;li&gt;Leave every other value on this page as default. &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Register Targets: Leave as is.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create target group&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/d5Uzm132PpM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  4. Create Load Balancer
&lt;/h2&gt;

&lt;p&gt;An application load balancer acts as the entry point for traffic to our web servers. Instead of allowing users to access our application directly, we will use the load balancer to distribute traffic equally among our autoscaling group of web servers. This is better for load management, security and reliability of our application.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;a href="https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#SelectCreateELBWizard:" rel="noopener noreferrer"&gt;Create load balancer&lt;/a&gt; from the EC2 console to create a load balancer&lt;/li&gt;
&lt;li&gt;Type: &lt;strong&gt;Application Load Balancer&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Scheme: &lt;strong&gt;Internet-facing&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;IP address type: &lt;strong&gt;IPV4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;VPC: Select the VPC you created.&lt;/li&gt;
&lt;li&gt;Mappings: Check the box beside the two AZs listed.&lt;/li&gt;
&lt;li&gt;Subnet: For each AZ selected, choose the public subnet in the dropdown menu.&lt;/li&gt;
&lt;li&gt;At this point, go to the Security groups console and create a new security group for the load balancer. The inbound rule should allow HTTP traffic from anywhere.&lt;/li&gt;
&lt;li&gt;Select this security group as the load balancer security group.&lt;/li&gt;
&lt;li&gt;Listeners and routing: Leave protocol and port as &lt;strong&gt;HTTP:80&lt;/strong&gt;. Select the target group you created as target group.&lt;/li&gt;
&lt;li&gt;Leave every other config as default and click &lt;strong&gt;Create load balancer&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/JVyPOaC1QII"&gt;
&lt;/iframe&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  5. Create Auto Scaling Group
&lt;/h2&gt;

&lt;p&gt;The auto scaling group configures and controls how your application scales automatically in response to varying traffic situations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;a href="https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#CreateAutoScalingGroup:" rel="noopener noreferrer"&gt;Create Auto Scaling group&lt;/a&gt; from the EC2 console to create an auto scaling group.&lt;/li&gt;
&lt;li&gt;Enter a name.&lt;/li&gt;
&lt;li&gt;Choose the launch template you created. Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select your webserver VPC created from the VPC step.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Availability Zones and subnets&lt;/strong&gt;, select the two public subnets in your VPC, in different AZs. Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;NB:&lt;/strong&gt; Note that you can use the auto scaling group to override your instance type config from the launch template*.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Under &lt;strong&gt;Load balancing&lt;/strong&gt;, choose the option &lt;strong&gt;Attach to an existing load balancer&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Choose from your load balancer target groups&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the target group you created.&lt;/li&gt;
&lt;li&gt;Select VPC Lattice service to attach: &lt;strong&gt;No VPC Lattice service&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Additional health check types - optional: &lt;strong&gt;Turn on Elastic Load Balancing health checks&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Leave every other config as default. &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Group size: Desired: &lt;strong&gt;2&lt;/strong&gt;, Minimum: &lt;strong&gt;1&lt;/strong&gt;, Maximum: &lt;strong&gt;4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Scaling policies: &lt;strong&gt;Target Tracking Policy&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Metric type: &lt;strong&gt;Average CPU Utilization&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Target Value: &lt;strong&gt;50%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create Auto Scaling Group&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/miOEZZcFtAI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;



&lt;p&gt;Once you successfully create your autoscaling group, you should see two new instances in the EC2 console. This is because we specified a desired count of 2. Also note that they are automatically placed one in each AZ to support high availability.&lt;/p&gt;

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



&lt;h2&gt;
  
  
  Restrict web traffic to servers
&lt;/h2&gt;

&lt;p&gt;With the current design, users can directly access our web server using its IP address. We don't want that. That is why we created a load balancer.&lt;/p&gt;

&lt;p&gt;To ensure all incoming HTTP traffic goes through the load balancer, we will update the webserver security group to accept HTTP traffic only from our application load balancer security group.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;strong&gt;autoscale-webserver-sg&lt;/strong&gt; security group and click on &lt;strong&gt;Edit inbound rules&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Delete the existing HTTP rule.&lt;/li&gt;
&lt;li&gt;Add a new HTTP rule. In the &lt;strong&gt;Source&lt;/strong&gt; box, scroll down to select the security group of the load balancer. &lt;strong&gt;Save rules&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You have successfully restricted traffic going to the servers to the load balancer.&lt;/li&gt;
&lt;li&gt;You should no longer be able to access your web server using the server IPs or DNS names. You should now be able to use the load balancer DNS name to access the servers. Test this out.&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%2Fgenuiea2j6qbr0a5t9qe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgenuiea2j6qbr0a5t9qe.png" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  Observations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;From the details tab of the load balancer, copy the DNS name and paste in a new tab. Refresh the tab and note the changing hostnames with every refresh. That's the load balancer alternating traffic between its target web servers.&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%2Fd27cfdmch0nybz.cloudfront.net%2Fblog-demos%2Fautoscaling%2Fvideos%2Fautoscaling-alb-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd27cfdmch0nybz.cloudfront.net%2Fblog-demos%2Fautoscaling%2Fvideos%2Fautoscaling-alb-demo.gif" alt="ALB at work" width="600" height="99"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;ol&gt;
&lt;li&gt;After launching the desired number of instances, a bash script will run in the background to increase CPU utilization to 50%. This will trigger a scale out action.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This should lead to a maximum number of 4 instances being available to serve web traffic.&lt;/p&gt;

&lt;p&gt;When the script stops running, a scale in action should equally be triggered to reduce the instances back to the desired number.&lt;/p&gt;

&lt;p&gt;It takes about an hour to observe this.&lt;/p&gt;

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

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

&lt;p&gt;You have built a load-balanced and highly available web application that auto-scales based on a target of CPU utilization.&lt;/p&gt;

&lt;p&gt;Delete the autoscaling group and load balancer after your tests to prevent unwanted charges.&lt;/p&gt;

&lt;p&gt;If you made it this far, here's a little reward:&lt;/p&gt;

&lt;p&gt;The CloudFormation stack below will deploy exactly what you have built in the demo. Try it out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://d27cfdmch0nybz.cloudfront.net/blog-demos/autoscaling/templates/AutoScalingWebserver.yaml" rel="noopener noreferrer"&gt;Download IAC template&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
