DEV Community

Cover image for Create VPC with Public/Private Subnets, attach Internet/NAT Gateways, and launch EC2 instances via AWS CLI.
Nsisong Etim
Nsisong Etim

Posted on

Create VPC with Public/Private Subnets, attach Internet/NAT Gateways, and launch EC2 instances via AWS CLI.

Project Workflow

Introduction

Cloud infrastructure management is often associated with the convenience of graphical interfaces like AWS console. But what if I told you that you could completely set up a fully functional Virtual Private Cloud (VPC) with public and private subnets, internet access, NAT gateways, and EC2 instances, all from the command line?

In this guide, I'll walk you through the entire process, from creating a VPC from scratch, configuring subnets, and launching EC2 instances in both public and private subnets. Everything will be done using the powerful AWS CLI. No clicks. Just pure CLI magic. So, are you ready to dive in? Let’s get started!

Architectural Diagram.

Image description

Prerequisites

  1. You must have AWS CLI is installed and configured.

  2. You must have a key pair for SSH access, or create one using the CLI.

  3. Replace placeholders with actual values from your AWS environment.

Step 1: Create a VPC

  • Create a VPC with a CIDR block of your choice (e.g., 10.0.0.0/16). To do this, use the command, aws ec2 create-vpc --cidr-block <IP address>
C:\Users\Nsisong>aws ec2 create-vpc --cidr-block 10.0.0.0/16
{
    "Vpc": {
        "CidrBlock": "10.0.0.0/16",
        "DhcpOptionsId": "dopt-04bb9d34aac15e56f",
        "State": "pending",
        "VpcId": "vpc-086c99e11cde64580",
        "OwnerId": "101061110965",
        "InstanceTenancy": "default",
        "Ipv6CidrBlockAssociationSet": [],
        "CidrBlockAssociationSet": [
            {
                "AssociationId": "vpc-cidr-assoc-054cc70aca2d0823d",
                "CidrBlock": "10.0.0.0/16",
                "CidrBlockState": {
                    "State": "associated"
                }
            }
        ],
        "IsDefault": false
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Create tag or a descriptive name for your VPC.

  • To do this, use the command

aws ec2 create-tags --resources <Your vpc> --tags Key=Name,Value=<name>

Replace the placeholers with vpc id and with a name.


C:\Users\Nsisong>aws ec2 create-tags --resources vpc-086c99e11cde64580 --tags Key=Name,Value=CLI-VPC
Enter fullscreen mode Exit fullscreen mode

Step 2: Create Subnets

  • Create a public subnet
  • Use the following command

aws ec2 create-subnet --vpc-id <VpcId> --cidr-block 10.0.1.0/24

  • Configure an IP range that is still within your VPC cidr-block.

C:\Users\Nsisong>aws ec2 create-subnet --vpc-id vpc-086c99e11cde64580 --cidr-block 10.0.1.
0/24
{
    "Subnet": {
        "AvailabilityZone": "us-east-1f",
        "AvailabilityZoneId": "use1-az5",
        "AvailableIpAddressCount": 251,
        "CidrBlock": "10.0.1.0/24",
        "DefaultForAz": false,
        "MapPublicIpOnLaunch": false,
        "State": "available",
        "SubnetId": "subnet-090e0fa27cedb8e6a",
        "VpcId": "vpc-086c99e11cde64580",
        "OwnerId": "101061110965",
        "AssignIpv6AddressOnCreation": false,        "Ipv6CidrBlockAssociationSet": [],
        "SubnetArn": "arn:aws:ec2:us-east-1:101061110965:subnet/subnet-090e0fa27cedb8e6a",        "EnableDns64": false,
        "Ipv6Native": false,
        "PrivateDnsNameOptionsOnLaunch": {
            "HostnameType": "ip-name",
            "EnableResourceNameDnsARecord": false,
            "EnableResourceNameDnsAAAARecord": false
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Create tag or a descriptive name for your Public-subnet.
    aws ec2 create-tags --resources <subnetId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your subnetId

  • For Value, provide a name for Public subnet

C:\Users\Nsisong>aws ec2 create-tags --resources subnet-090e0fa27cedb8e6a --tags Key=Name,Value=CLI-Public-subnet
Enter fullscreen mode Exit fullscreen mode
  • Create a private subnet

  • Use the following command
    aws ec2 create-subnet --vpc-id <VpcId> --cidr-block 10.0.2.0/24

  • Replace with your VPC ID.

  • Configure an IP range that is still within your VPC cidr-block.

C:\Users\Nsisong>aws ec2 create-subnet --vpc-id vpc-086c99e11cde64580 --cidr-block 10.0.2.0/24
{
    "Subnet": {
        "AvailabilityZone": "us-east-1f",
        "AvailabilityZoneId": "use1-az5",
        "AvailableIpAddressCount": 251,
        "CidrBlock": "10.0.2.0/24",
        "DefaultForAz": false,
        "MapPublicIpOnLaunch": false,
        "State": "available",
        "SubnetId": "subnet-0ab4cd05a41dc4882",
        "VpcId": "vpc-086c99e11cde64580",
        "OwnerId": "101061110965",
        "AssignIpv6AddressOnCreation": false,
        "Ipv6CidrBlockAssociationSet": [],
        "SubnetArn": "arn:aws:ec2:us-east-1:101061110965:subnet/subnet-0ab4cd05a41dc4882",
        "EnableDns64": false,
        "Ipv6Native": false,
        "PrivateDnsNameOptionsOnLaunch": {
            "HostnameType": "ip-name",
            "EnableResourceNameDnsARecord": false,
            "EnableResourceNameDnsAAAARecord": false
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Create tag or a descriptive name for your Private-subnet.
    aws ec2 create-tags --resources <subnetId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your subnetId

  • For Value, provide a name for Private subnet

C:\Users\Nsisong>aws ec2 create-tags --resources subnet-0ab4cd05a41dc4882 --tags Key=Name,Value=CLI-Private-
subnet
Enter fullscreen mode Exit fullscreen mode

Step 3: Create and Attach an Internet Gateway

  • Create an internet gateway

  • Use the following command
    aws ec2 create-internet-gateway

C:\Users\Nsisong>aws ec2 create-internet-gateway
{
    "InternetGateway": {
        "Attachments": [],
        "InternetGatewayId": "igw-0e9b76329f85c97ca",
        "OwnerId": "101061110965",
        "Tags": []
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Create tag or a descriptive name for your Internet Gateway.
    aws ec2 create-tags --resources <igwId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your igwId

  • For Value, provide a name for Internet gateway.


C:\Users\Nsisong>aws ec2 create-tags --resources igw-0e9b76329f85c97ca --tags Key=Name,Value=CLI-internetGat
eway
Enter fullscreen mode Exit fullscreen mode
  • Now, attach the internet gateway to the VPC.

  • To do this, use the command
    aws ec2 attach-internet-gateway --vpc-id <VpcId> --internet-gateway-id <InternetGatewayId>

  • For vpc-id, copy and paste your actual VpcId

  • For internet-gateway-id, copy and paste your InternetGatewayId


C:\Users\Nsisong>aws ec2 attach-internet-gateway --vpc-id vpc-086c99e11cde64580 --internet-gateway-id igw-0e
9b76329f85c97ca
Enter fullscreen mode Exit fullscreen mode

Step 4: Create an Elastic IP and Nat gateway

  • First, allocate an Elastic IP for the Nat gateway.

  • To do this, use the command
    aws ec2 allocate-address

C:\Users\Nsisong>aws ec2 allocate-address
{
    "PublicIp": "34.224.220.87",
    "AllocationId": "eipalloc-0b582827c154b315d",
    "PublicIpv4Pool": "amazon",
    "NetworkBorderGroup": "us-east-1",
    "Domain": "vpc"
}
Enter fullscreen mode Exit fullscreen mode
  • Now, create a Nat gateway in the public subnet

  • To do this, use the command
    aws ec2 create-nat-gateway --subnet-id <PublicSubnetId> --allocation-id <AllocationId>

  • For subnet-id, copy and paste your PublicSubnetId.

  • For allocation-id, copy and paste your AllocationId.

C:\Users\Nsisong>aws ec2 create-nat-gateway --subnet-id subnet-090e0fa27cedb8e6a --allocation-id eipalloc-0b
582827c154b315d
{
    "ClientToken": "b526971b-6815-4f0e-8cf3-df731c83dbd6",
    "NatGateway": {
        "CreateTime": "2024-09-17T06:45:43+00:00",
        "NatGatewayAddresses": [
            {
                "AllocationId": "eipalloc-0b582827c154b315d",
                "IsPrimary": true,
                "Status": "associating"
            }
        ],
        "NatGatewayId": "nat-070e891694114824b",
        "State": "pending",
        "SubnetId": "subnet-090e0fa27cedb8e6a",
        "VpcId": "vpc-086c99e11cde64580",
        "ConnectivityType": "public"
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Create tag or a descriptive name for your Nat gateway.
    aws ec2 create-tags --resources <NatId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your NatId

  • For Value, provide a name for Nat gateway


C:\Users\Nsisong>aws ec2 create-tags --resources nat-070e891694114824b --tags Key=Name,Value=CLI-NatGateway
Enter fullscreen mode Exit fullscreen mode

Step 5: Create Route Tables

  • Create a route table for the public subnet.

  • To do this, use the command
    aws ec2 create-route-table --vpc-id <VpcId>

  • For vpc-id, copy and paste your VpcId


C:\Users\Nsisong>aws ec2 create-route-table --vpc-id vpc-086c99e11cde64580
{
    "RouteTable": {
        "Associations": [],
        "PropagatingVgws": [],
        "RouteTableId": "rtb-06f3188e96a915faa",
        "Routes": [
            {
                "DestinationCidrBlock": "10.0.0.0/16",                "GatewayId": "local",
                "Origin": "CreateRouteTable",
                "State": "active"
            }
        ],
        "Tags": [],
        "VpcId": "vpc-086c99e11cde64580",
        "OwnerId": "101061110965"
    },
    "ClientToken": "4a292c9d-1b49-404d-80e0-52ed8fb63f4c"
}

Enter fullscreen mode Exit fullscreen mode
  • Then, create tag or a descriptive name to your Public route table.
    aws ec2 create-tags --resources <RouteTableId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your RouteTableId

  • For Value, provide a name for your Public route table

C:\Users\Nsisong>aws ec2 create-tags --resources rtb-06f3188e96a915faa --tags Key=Name,Value=CLI-PUBLICROUTE
Enter fullscreen mode Exit fullscreen mode
  • Now, create a route to allow internet access

  • To do this, use the command
    aws ec2 create-route --route-table-id <RouteTableId> --destination-cidr-block 0.0.0.0/0 --gateway-id <InternetGatewayId>

  • For RouteTableId, copy and paste your rtb-Id

  • For InternetGatewayId, copy and paste your igwId

  • And ensure to configure the destination cidr-block to anywhere

C:\Users\Nsisong>aws ec2 create-route --route-table-id rtb-06f3188e96a915faa --destination-cidr-block 0.0.0.
0/0 --gateway-id igw-0e9b76329f85c97ca
{
    "Return": true
}
Enter fullscreen mode Exit fullscreen mode

_Now since you have created a route table, you have also given it an internet access and you have given it a name as Public route table _

  • Then, associate the route table with the public subnet.

  • To do this, use the command
    aws ec2 associate-route-table --subnet-id <PublicSubnetId> --route-table-id <RouteTableId>

  • For PublicSubnetId, copy and paste your Public-subnetId there.

  • For RouteTableId, copy and paste your rtb-id there

C:\Users\Nsisong>aws ec2 associate-route-table --subnet-id subnet-090e0fa27cedb8e6a --route-table-id rtb-06f
3188e96a915faa
{
    "AssociationId": "rtbassoc-0c6413a18d81b055c",
    "AssociationState": {
        "State": "associated"
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Enable auto-assign public IP on the public subnet

  • To do this, use the command
    aws ec2 modify-subnet-attribute --subnet-id <PublicSubnetId> --map-public-ip-on-launch

  • Where you have PublicSubnetId, copy and paste your Public-subnetId there.


C:\Users\Nsisong>aws ec2 modify-subnet-attribute --subnet-id subnet-090e0fa27cedb8e6a --map-public-ip-on-lau
nch
Enter fullscreen mode Exit fullscreen mode
  • Create a route table for the private subnet

  • To do this, use this command
    aws ec2 create-route-table --vpc-id <VpcId>

  • Where you have VpcId, copy and paste your vpc-id


C:\Users\Nsisong>aws ec2 create-route-table --vpc-id vpc-086c99e11cde64580
{
    "RouteTable": {
        "Associations": [],
        "PropagatingVgws": [],
        "RouteTableId": "rtb-09a1dc578d89c4d88",
        "Routes": [
            {
                "DestinationCidrBlock": "10.0.0.0/16",                "GatewayId": "local",
                "Origin": "CreateRouteTable",
                "State": "active"
            }
        ],
        "Tags": [],
        "VpcId": "vpc-086c99e11cde64580",
        "OwnerId": "101061110965"
    },
    "ClientToken": "ae6c4808-d1fd-4417-aee7-912067d74c22"
}
Enter fullscreen mode Exit fullscreen mode
  • Then, create tag or a descriptive name to your Private route table.
    aws ec2 create-tags --resources <RouteTableId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your RouteTableId

  • For Value, provide a name for your Public route table

C:\Users\Nsisong>aws ec2 create-tags --resources rtb-09a1dc578d89c4d88 --tags Key=Name,Value=CLI-PRIVATEROUT
E
Enter fullscreen mode Exit fullscreen mode
  • Create a route in the private route table to use the NAT gateway

  • To do this, use the command
    aws ec2 create-route --route-table-id <PrivateRouteTableId> --destination-cidr-block 0.0.0.0/0 --nat-gateway-id <NatGatewayId>

  • Where you have PrivateRouteTableId, copy and paste your private-rtb-id

  • And where you have NatGatewayId, copy and paste your nat-gateway-id.

  • However, ensure you configure your destination to anywhere.

_Because your private instances might need access to internet for updates.
And that could be archived securely through the Nat gateway.
_

C:\Users\Nsisong>aws ec2 create-route --route-table-id rtb-09a1dc578d89c4d88 --destination-cidr-block 0.0.0.
0/0 --nat-gateway-id nat-070e891694114824b
{
    "Return": true
}
Enter fullscreen mode Exit fullscreen mode

Ok! now that you have created a route table, you have also given it a Nat gateway internet access and you have given it a name as Private route table

  • Then, associate the route table with the Private subnet

  • To do this, use the command
    aws ec2 associate-route-table --subnet-id <PrivateSubnetId> --route-table-id <PrivateRouteTableId>

  • Where you have PrivateSubnetId, copy and paste your private-Subnet-id there

  • And where you have PrivateRouteTableId, copy and paste your private-rtb-id there.

C:\Users\Nsisong>aws ec2 associate-route-table --subnet-id subnet-0ab4cd05a41dc4882 --route-table-id rtb-09a
1dc578d89c4d88
{
    "AssociationId": "rtbassoc-025956002fd6aef15",
    "AssociationState": {
        "State": "associated"
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: create security groups

  • To do this, use the command
    aws ec2 create-security-group --group-name <security-group-name> --description "<description>" --vpc-id <vpc-id>

  • Where you have security-group-name, provide a name for you security group.

  • Where you have description, give a description to your security group.

  • Then, where you have vpc-id, copy and paste your vpc-id there.

C:\Users\Nsisong>aws ec2 create-security-group --group
-name CLI-WEB-securityGroup --description "This is my
security group" --vpc-id vpc-086c99e11cde64580
{
    "GroupId": "sg-03b513eb8de674a4e"
}
Enter fullscreen mode Exit fullscreen mode
  • Then, create tag or a descriptive name to your security group.
    aws ec2 create-tags --resources <GroupId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your GroupId

  • For Value, provide a name for your Security group.

C:\Users\Nsisong>aws ec2 create-tags --resources sg-03b513eb8de674a4e --tags Key=Name,Value=CLI-security-gro
up
Enter fullscreen mode Exit fullscreen mode

Now, configure the security rules
By default, outbound rules is always open.
However, add an inbound rules that allows both ssh and http access

  • To do this, use the command
    aws ec2 authorize-security-group-ingress --group-id <security-group-id>
    --protocol tcp --port 22 --cidr 0.0.0.0/0

  • Where you have security-group-id, copy and paste your GroupId

  • --protocol tcp: Specifies the TCP protocol.

  • --port 22: Specifies port 22, which is used for SSH.

  • --cidr 0.0.0.0/0: Allows SSH access from any IP address.

C:\Users\Nsisong>aws ec2 authorize-security-group-ingr
ess --group-id sg-03b513eb8de674a4e --protocol tcp --p
ort 22 --cidr 0.0.0.0/0
{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "sgr-0c91fcd4316408ba4",
            "GroupId": "sg-03b513eb8de674a4e",
            "GroupOwnerId": "101061110965",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 22,
            "ToPort": 22,
            "CidrIpv4": "0.0.0.0/0"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

aws ec2 authorize-security-group-ingress --group-id <security-group-id>
--protocol tcp --port 80 --cidr 0.0.0.0/0

C:\Users\Nsisong>aws ec2 authorize-security-group-ingress --group-id sg-03b513eb8de674a4e --protocol tcp --port 80 --cidr 0.0.0.0/0
{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "sgr-0fb478a9af9831a69",
            "GroupId": "sg-03b513eb8de674a4e",
            "GroupOwnerId": "101061110965",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 80,
            "ToPort": 80,
            "CidrIpv4": "0.0.0.0/0"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Create key pair for SSH Login

  • To do this, use the command
    aws ec2 create-key-pair --key-name <your_key_name> --query 'KeyMaterial' --output text > your_key_name

  • Replace your key name, with the name of your keypair.

C:\Users\Nsisong>aws ec2 create-key-pair --key-name MYCLIKEY123 --query "KeyMaterial" --output text > MYCLIKEY123
Enter fullscreen mode Exit fullscreen mode

Step 8: Launch EC2 Instances

Launch an instance in the public subnet

  • To do this, use the command
    aws ec2 run-instances --image-id <AMI-ID> --count 1 --instance-type <InstanceType> --key-name <KeyName> --subnet-id <PublicSubnetId> --security-group-ids <GroupId> --associate-public-ip-address

  • Where you have AMI-ID, copy and paste you image-id

  • --count 1: Specifies the number of instances

  • Where you have InstanceType, replace with t2.micro which free tier.

  • Where you have KeyName, replace with your key-pair.

  • Where you have GroupId, copy and paste your sg-id there

  • And where you have PublicSubnetId, copy and paste your publicSubnetid there.

  • --associate-public-ip-address: This command enables or gives this instance a Public IP address.

C:\Users\Nsisong>aws ec2 run-instances --image-id ami-0ebfd941bbafe70c6 --count 1 --instance-type t2.micro --key-name MYCLIKEY123 --security-group-ids sg-03b513eb8de674a4e --subnet-id subnet-090e0fa27cedb8e6a --associate-public-ip-address
{
    "Groups": [],
    "Instances": [
        {
            "AmiLaunchIndex": 0,
            "ImageId": "ami-0ebfd941bbafe70c6",
            "InstanceId": "i-0e60743780a84216e",
            "InstanceType": "t2.micro",
            "KeyName": "MYCLIKEY123",
            "LaunchTime": "2024-09-17T08:31:11+00:00",
            "Monitoring": {
                "State": "disabled"
            },
            "Placement": {
                "AvailabilityZone": "us-east-1f",
                "GroupName": "",
                "Tenancy": "default"
            },
            "PrivateDnsName": "ip-10-0-1-102.ec2.internal",
            "PrivateIpAddress": "10.0.1.102",
            "ProductCodes": [],
            "PublicDnsName": "",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "StateTransitionReason": "",
            "SubnetId": "subnet-090e0fa27cedb8e6a",
            "VpcId": "vpc-086c99e11cde64580",
            "Architecture": "x86_64",
            "BlockDeviceMappings": [],
            "ClientToken": "3dd000e7-5c7a-4a41-b1ed-26ec27d693f2",
            "EbsOptimized": false,
            "EnaSupport": true,
            "Hypervisor": "xen",
            "NetworkInterfaces": [
                {
                    "Attachment": {
                        "AttachTime": "2024-09-17T08:31:11+00:00",
                        "AttachmentId": "eni-attach-07c3c205d29357b4c",
                        "DeleteOnTermination": true,
                        "DeviceIndex": 0,
                        "Status": "attaching",
                        "NetworkCardIndex": 0
                    },
                    "Description": "",
                    "Groups": [
                        {
                            "GroupName": "CLI-WEB-securityGroup",
                            "GroupId": "sg-03b513eb8de674a4e"
                        }
                    ],
                    "Ipv6Addresses": [],
                    "MacAddress": "16:ff:c6:9b:03:b7",
                    "NetworkInterfaceId": "eni-0fd5681bfcdfa9866",
                    "OwnerId": "101061110965",
                    "PrivateIpAddress": "10.0.1.102",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateIpAddress": "10.0.1.102"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Status": "in-use",
                    "SubnetId": "subnet-090e0fa27cedb8e6a",
                    "VpcId": "vpc-086c99e11cde64580",
                    "InterfaceType": "interface"
                }
            ],
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SecurityGroups": [
                {
                    "GroupName": "CLI-WEB-securityGroup",
                    "GroupId": "sg-03b513eb8de674a4e"
                }
            ],
            "SourceDestCheck": true,
            "StateReason": {
                "Code": "pending",
                "Message": "pending"
            },
            "VirtualizationType": "hvm",
            "CpuOptions": {
                "CoreCount": 1,
                "ThreadsPerCore": 1
            },
            "CapacityReservationSpecification": {
                "CapacityReservationPreference": "open"
            },
            "MetadataOptions": {
                "State": "pending",
                "HttpTokens": "required",
                "HttpPutResponseHopLimit": 2,
                "HttpEndpoint": "enabled",
                "HttpProtocolIpv6": "disabled",
                "InstanceMetadataTags": "disabled"
            },
            "EnclaveOptions": {
                "Enabled": false
            },
            "BootMode": "uefi-preferred",
            "PrivateDnsNameOptions": {
                "HostnameType": "ip-name",
                "EnableResourceNameDnsARecord": false,
                "EnableResourceNameDnsAAAARecord": false
            },
            "MaintenanceOptions": {
                "AutoRecovery": "default"
            },
            "CurrentInstanceBootMode": "legacy-bios"
        }
    ],
    "OwnerId": "101061110965",
    "ReservationId": "r-0cbfc7bce9bf67f90"
}

Enter fullscreen mode Exit fullscreen mode
  • Then, create tag or a descriptive name to your Instance.

aws ec2 create-tags --resources <InstanceId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your InstanceId there.

  • For Value, provide a name for your instance there.

C:\Users\Nsisong>aws ec2 create-tags --resources i-0e60743780a84216e --tags Key=Name,Value=CLI-Public-instance
Enter fullscreen mode Exit fullscreen mode

Launch an instance in the private subnet

  • To do this, use the command
    aws ec2 run-instances --image-id <AMI-ID> --count 1 --instance-type <InstanceType> --key-name <KeyName> --subnet-id <PrivateSubnetId>

  • Where you have AMI-ID, copy and paste you image-id.

  • --count 1: Specifies the number of instances

  • Where you have InstanceType, replace with t2.micro which free tier.

  • Where you have KeyName, replace with your key-pair.

  • And where you have PrivateSubnetId, copy and paste your PrivateSubnetId there.


C:\Users\Nsisong>aws ec2 run-instances --image-id ami-0ebfd941bbafe70c6 --count 1 --instance-type t2.micro --key-name MYCLIKEY123 --subnet-id subnet-0ab4cd05a41dc4882
{
    "Groups": [],
    "Instances": [
        {
            "AmiLaunchIndex": 0,
            "ImageId": "ami-0ebfd941bbafe70c6",
            "InstanceId": "i-056e1777784aab32a",
            "InstanceType": "t2.micro",
            "KeyName": "MYCLIKEY123",
            "LaunchTime": "2024-09-17T11:45:13+00:00",
            "Monitoring": {
                "State": "disabled"
            },
            "Placement": {
                "AvailabilityZone": "us-east-1f",
                "GroupName": "",
                "Tenancy": "default"
            },
            "PrivateDnsName": "ip-10-0-2-103.ec2.internal",
            "PrivateIpAddress": "10.0.2.103",
            "ProductCodes": [],
            "PublicDnsName": "",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "StateTransitionReason": "",
            "SubnetId": "subnet-0ab4cd05a41dc4882",
            "VpcId": "vpc-086c99e11cde64580",
            "Architecture": "x86_64",
            "BlockDeviceMappings": [],
            "ClientToken": "b9543fc9-e093-46a2-9d6c-b5391ac90eb5",
            "EbsOptimized": false,
            "EnaSupport": true,
            "Hypervisor": "xen",
            "NetworkInterfaces": [
                {
                    "Attachment": {
                        "AttachTime": "2024-09-17T11:45:13+00:00",
                        "AttachmentId": "eni-attach-04bc3aededd1158ab",
                        "DeleteOnTermination": true,
                        "DeviceIndex": 0,
                        "Status": "attaching",
                        "NetworkCardIndex": 0
                    },
                    "Description": "",
                    "Groups": [
                        {
                            "GroupName": "default",
                            "GroupId": "sg-0f951d3f7faa4766f"
                        }
                    ],
                    "Ipv6Addresses": [],
                    "MacAddress": "16:ff:ef:a1:19:87",
                    "NetworkInterfaceId": "eni-0550fdce65193c750",
                    "OwnerId": "101061110965",
                    "PrivateIpAddress": "10.0.2.103",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateIpAddress": "10.0.2.103"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Status": "in-use",
                    "SubnetId": "subnet-0ab4cd05a41dc4882",
                    "VpcId": "vpc-086c99e11cde64580",
                    "InterfaceType": "interface"
                }
            ],
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SecurityGroups": [
                {
                    "GroupName": "default",
                    "GroupId": "sg-0f951d3f7faa4766f"
                }
            ],
            "SourceDestCheck": true,
            "StateReason": {
                "Code": "pending",
                "Message": "pending"
            },
            "VirtualizationType": "hvm",
            "CpuOptions": {
                "CoreCount": 1,
                "ThreadsPerCore": 1
            },
            "CapacityReservationSpecification": {
                "CapacityReservationPreference": "open"
            },
            "MetadataOptions": {
                "State": "pending",
                "HttpTokens": "required",
                "HttpPutResponseHopLimit": 2,
                "HttpEndpoint": "enabled",
                "HttpProtocolIpv6": "disabled",
                "InstanceMetadataTags": "disabled"
            },
            "EnclaveOptions": {
                "Enabled": false
            },
            "BootMode": "uefi-preferred",
            "PrivateDnsNameOptions": {
                "HostnameType": "ip-name",
                "EnableResourceNameDnsARecord": false,
                "EnableResourceNameDnsAAAARecord": false
            },
            "MaintenanceOptions": {
                "AutoRecovery": "default"
            },
            "CurrentInstanceBootMode": "legacy-bios"
        }
    ],
    "OwnerId": "101061110965",
    "ReservationId": "r-072b7ba930ca46057"
}

Enter fullscreen mode Exit fullscreen mode
  • Then, create tag or a descriptive name to your Instance.

  • To do this, use the command
    aws ec2 create-tags --resources <InstanceId> --tags Key=Name,Value=<name>

  • For resources, copy and paste your InstanceId there.

  • For Value, provide a name for your instance there.

C:\Users\Nsisong>aws ec2 create-tags --resources i-056e1777784aab32a --tags Key=Name,Value=CLI-Private-instance
Enter fullscreen mode Exit fullscreen mode

Step 9: SSH into the EC2 instances

C:\Users\Nsisong>ssh ec2-user@3.238.242.252 -i MYCLIKEY123
The authenticity of host '3.238.242.252 (3.238.242.252)' can't be established.
ED25519 key fingerprint is SHA256:KJqDKGF91jAWqRwY/9WdauIFuN1o0tGVy3qwpZZ3/ME.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '3.238.242.252' (ED25519) to the list of known hosts.
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
[ec2-user@ip-10-0-1-102 ~]$
[ec2-user@ip-10-0-1-102 ~]$
[ec2-user@ip-10-0-1-102 ~]$
Enter fullscreen mode Exit fullscreen mode
[ec2-user@ip-10-0-1-102 ~]$ sudo yum install httpd
Last metadata expiration check: 0:17:56 ago on Tue Sep 17 08:32:05 2024.
Dependencies resolved.
===============================================================================================
 Package                   Architecture Version                        Repository         Size
===============================================================================================
Installing:
 httpd                     x86_64       2.4.62-1.amzn2023              amazonlinux        48 k
Installing dependencies:
 apr                       x86_64       1.7.2-2.amzn2023.0.2           amazonlinux       129 k
 apr-util                  x86_64       1.6.3-1.amzn2023.0.1           amazonlinux        98 k
 generic-logos-httpd       noarch       18.0.0-12.amzn2023.0.3         amazonlinux        19 k
 httpd-core                x86_64       2.4.62-1.amzn2023              amazonlinux       1.4 M
 httpd-filesystem          noarch       2.4.62-1.amzn2023              amazonlinux        14 k
 httpd-tools               x86_64       2.4.62-1.amzn2023              amazonlinux        81 k
 libbrotli                 x86_64       1.0.9-4.amzn2023.0.2           amazonlinux       315 k
 mailcap                   noarch       2.1.49-3.amzn2023.0.3          amazonlinux        33 k
Installing weak dependencies:
 apr-util-openssl          x86_64       1.6.3-1.amzn2023.0.1           amazonlinux        17 k
 mod_http2                 x86_64       2.0.27-1.amzn2023.0.3          amazonlinux       166 k
 mod_lua                   x86_64       2.4.62-1.amzn2023              amazonlinux        61 k

Transaction Summary
===============================================================================================
Install  12 Packages

Total download size: 2.3 M
Installed size: 6.9 M
Is this ok [y/N]: y
Downloading Packages:
(1/12): apr-util-openssl-1.6.3-1.amzn2023.0.1.x86_64.rpm       251 kB/s |  17 kB     00:00
(2/12): apr-util-1.6.3-1.amzn2023.0.1.x86_64.rpm               1.3 MB/s |  98 kB     00:00
(3/12): generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch.rpm  951 kB/s |  19 kB     00:00
(4/12): httpd-2.4.62-1.amzn2023.x86_64.rpm                     2.3 MB/s |  48 kB     00:00
(5/12): apr-1.7.2-2.amzn2023.0.2.x86_64.rpm                    1.2 MB/s | 129 kB     00:00
(6/12): httpd-filesystem-2.4.62-1.amzn2023.noarch.rpm          665 kB/s |  14 kB     00:00
(7/12): httpd-core-2.4.62-1.amzn2023.x86_64.rpm                 24 MB/s | 1.4 MB     00:00
(8/12): httpd-tools-2.4.62-1.amzn2023.x86_64.rpm               1.7 MB/s |  81 kB     00:00
(9/12): libbrotli-1.0.9-4.amzn2023.0.2.x86_64.rpm              7.4 MB/s | 315 kB     00:00
(10/12): mailcap-2.1.49-3.amzn2023.0.3.noarch.rpm              1.5 MB/s |  33 kB     00:00
(11/12): mod_lua-2.4.62-1.amzn2023.x86_64.rpm                  3.0 MB/s |  61 kB     00:00
(12/12): mod_http2-2.0.27-1.amzn2023.0.3.x86_64.rpm            4.7 MB/s | 166 kB     00:00
-----------------------------------------------------------------------------------------------
Total                                                          9.5 MB/s | 2.3 MB     00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                       1/1
  Installing       : apr-1.7.2-2.amzn2023.0.2.x86_64                                      1/12
  Installing       : apr-util-openssl-1.6.3-1.amzn2023.0.1.x86_64                         2/12
  Installing       : apr-util-1.6.3-1.amzn2023.0.1.x86_64                                 3/12
  Installing       : mailcap-2.1.49-3.amzn2023.0.3.noarch                                 4/12
  Installing       : httpd-tools-2.4.62-1.amzn2023.x86_64                                 5/12
  Installing       : libbrotli-1.0.9-4.amzn2023.0.2.x86_64                                6/12
  Running scriptlet: httpd-filesystem-2.4.62-1.amzn2023.noarch                            7/12
  Installing       : httpd-filesystem-2.4.62-1.amzn2023.noarch                            7/12
  Installing       : httpd-core-2.4.62-1.amzn2023.x86_64                                  8/12
  Installing       : mod_http2-2.0.27-1.amzn2023.0.3.x86_64                               9/12
  Installing       : mod_lua-2.4.62-1.amzn2023.x86_64                                    10/12
  Installing       : generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch                   11/12
  Installing       : httpd-2.4.62-1.amzn2023.x86_64                                      12/12
  Running scriptlet: httpd-2.4.62-1.amzn2023.x86_64                                      12/12
  Verifying        : apr-1.7.2-2.amzn2023.0.2.x86_64                                      1/12
  Verifying        : apr-util-1.6.3-1.amzn2023.0.1.x86_64                                 2/12
  Verifying        : apr-util-openssl-1.6.3-1.amzn2023.0.1.x86_64                         3/12
  Verifying        : generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch                    4/12
  Verifying        : httpd-2.4.62-1.amzn2023.x86_64                                       5/12
  Verifying        : httpd-core-2.4.62-1.amzn2023.x86_64                                  6/12
  Verifying        : httpd-filesystem-2.4.62-1.amzn2023.noarch                            7/12
  Verifying        : httpd-tools-2.4.62-1.amzn2023.x86_64                                 8/12
  Verifying        : libbrotli-1.0.9-4.amzn2023.0.2.x86_64                                9/12
  Verifying        : mailcap-2.1.49-3.amzn2023.0.3.noarch                                10/12
  Verifying        : mod_http2-2.0.27-1.amzn2023.0.3.x86_64                              11/12
  Verifying        : mod_lua-2.4.62-1.amzn2023.x86_64                                    12/12

Installed:
  apr-1.7.2-2.amzn2023.0.2.x86_64
  apr-util-1.6.3-1.amzn2023.0.1.x86_64
  apr-util-openssl-1.6.3-1.amzn2023.0.1.x86_64
  generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch
  httpd-2.4.62-1.amzn2023.x86_64
  httpd-core-2.4.62-1.amzn2023.x86_64
  httpd-filesystem-2.4.62-1.amzn2023.noarch
  httpd-tools-2.4.62-1.amzn2023.x86_64
  libbrotli-1.0.9-4.amzn2023.0.2.x86_64
  mailcap-2.1.49-3.amzn2023.0.3.noarch
  mod_http2-2.0.27-1.amzn2023.0.3.x86_64
  mod_lua-2.4.62-1.amzn2023.x86_64

Complete!
Enter fullscreen mode Exit fullscreen mode
[ec2-user@ip-10-0-1-102 ~]$ sudo service httpd start
Redirecting to /bin/systemctl start httpd.service
[ec2-user@ip-10-0-1-102 ~]$ cd /var/www/html/
[ec2-user@ip-10-0-1-102 html]$ echo "<h1> Hello there! this is my first web server that i created, using the CLI.</h1>" > index.html
-bash: index.html: Permission denied
[ec2-user@ip-10-0-1-102 html]$ sudo su
[root@ip-10-0-1-102 html]# echo "<h1>Hello there! this is my first web server that i created using the CLI.</h1>" > index.html
Enter fullscreen mode Exit fullscreen mode

Image description

Conclusion

By using the AWS CLI, you have successfully completed the tasks of setting up a fully functional VPC with both public and private subnets, configured internet and NAT gateways, and launched EC2 instances in each. Now, this process showcases the power of managing cloud infrastructure on the terminal and it gives you more control and efficiency even without having to go and touch the AWS Console.

Mastering the CLI can unlock endless possibilities for automating and
scaling your infrastructure, especially as your cloud knowledge grows and I hope this guide helps you take a confident step toward that journey. Keep exploring and keep experimenting even as you keep building with AWS CLI, of course, the cloud is yours to command!

Top comments (2)

Collapse
 
dheecloud profile image
Uduakabasi Umo-Odiong

Nicely done !

Collapse
 
nsisong_etim_bb31e7ddca64 profile image
Nsisong Etim

Thank you Uduakabasi