<?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: Nsowah Alexander</title>
    <description>The latest articles on DEV Community by Nsowah Alexander (@recklessbud_19).</description>
    <link>https://dev.to/recklessbud_19</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%2F3094850%2F7ac92bd2-ec4c-462f-be7f-db6f6c7ff728.jpeg</url>
      <title>DEV Community: Nsowah Alexander</title>
      <link>https://dev.to/recklessbud_19</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/recklessbud_19"/>
    <language>en</language>
    <item>
      <title>01-VPC — AWS Private/Public Subnet Architecture</title>
      <dc:creator>Nsowah Alexander</dc:creator>
      <pubDate>Fri, 03 Apr 2026 23:19:29 +0000</pubDate>
      <link>https://dev.to/recklessbud_19/01-vpc-aws-privatepublic-subnet-architecture-47be</link>
      <guid>https://dev.to/recklessbud_19/01-vpc-aws-privatepublic-subnet-architecture-47be</guid>
      <description>&lt;p&gt;In this article, I'll walk through how I set up an AWS VPC with a public and private subnet, deployed two EC2 instances, and configured Nginx as a reverse proxy. This is part of my hands-on cloud learning journey. If you're just getting started with AWS networking, this is for you.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;You need to have an AWS account to be able to create the infrastructure&lt;/li&gt;
&lt;li&gt;A basic understanding of networking&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  VPC Deployment
&lt;/h2&gt;

&lt;p&gt;A Virtual Private Cloud provides a logical, isolated virtual network that you define, where you can launch resources that you want. It closely resembles a traditional network you set up or operate in your own data center.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up VPC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Logged in to my AWS and navigated to the VPC section to create a VPC&lt;/li&gt;
&lt;li&gt;To create the VPC, I chose VPC only, gave a dummy name, and specified the IPV4 CIDR as 10.0.0.0/16. Click Create to create the VPC
&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%2Fnbncec9cgk2a9uhyvu9t.png" alt="create vpc" width="800" height="375"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IPV4 CIDR is the address range to be used by the VPC and should be private. I chose 10.0.0.0/16, with /16 as the netmask.&lt;/p&gt;

&lt;p&gt;To be able to access the resources in the VPC, you need a subnet placed in an HA zone&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up a Subnet
&lt;/h3&gt;

&lt;p&gt;A subnet is a smaller network within a larger network. I created two subnets, a public and a private.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click Subnets on the VPC window to create a subnet&lt;/li&gt;
&lt;li&gt;To create subnets for the VPC, I selected the VPC I just made (vpc-spec-01)&lt;/li&gt;
&lt;li&gt;Gave it a name (public), chose us-east-1a as the availability zone&lt;/li&gt;
&lt;li&gt;10.0.1.0/24 as the IPV4 CIDR to give me 256 IPs to use &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%2Fvnncs2czxm646hoepfy7.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%2Fvnncs2czxm646hoepfy7.png" alt="subnets" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;for the private subnet&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I used a different availability zone, us-east-1b&lt;/li&gt;
&lt;li&gt;to spice things up, I used 10.0.2.0/24  as the IPV4 CIDR. &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%2Foyzb3s24xw9yehd985er.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%2Foyzb3s24xw9yehd985er.png" alt="subnet" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the subnets, I created an EC2 instance in the public subnet so that I could SSH into it. &lt;br&gt;
To create the EC2 instance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I navigated to the EC2 service window&lt;/li&gt;
&lt;li&gt;I clicked on Create and gave the instance a name.&lt;/li&gt;
&lt;li&gt;For the Application and OS images, I chose Ubuntu and a free-tier eligible AMI &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%2Fl3xpxg6ok8dx7x5y42ht.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%2Fl3xpxg6ok8dx7x5y42ht.png" alt=" " width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Instance type is also free-tier eligible. created a key pair to securely SSH into the instance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the network settings section, here is where you configure the VPC, subnets, and ports to access the instance.&lt;br&gt;
. Choose the VPC made earlier. &lt;br&gt;
. Select the public subnet in the VPC and select Enable on Auto-assign IP.&lt;br&gt;
. Select Create security groups&lt;br&gt;
. for the inbound security rules, SSH and HTTP to listen on port 80(nginx)&lt;br&gt;
. Launch the EC2&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fib5aioch5aqz44artk7o.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%2Fib5aioch5aqz44artk7o.png" alt="ec2" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to SSH into the EC2, locate where the key is saved, and git bash there&lt;br&gt;
Run these commands to connect&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 &lt;span class="s2"&gt;"key.pem"&lt;/span&gt;
ssh &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"key55.pem"&lt;/span&gt; ubuntu@instanceIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ja, we can't connect to the EC2 because the VPC does not allow any connection from outside. We need to add an internet gateway to achieve this.&lt;br&gt;
steps involve&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an internet gateway&lt;/li&gt;
&lt;li&gt;Attach the internet gateway to the VPC.&lt;/li&gt;
&lt;li&gt;Create a route table for the gateway&lt;/li&gt;
&lt;li&gt;attach the route table to the public subnet
After creating the route table, you need to edit the route to attach the internet gateway created&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%2F5vbe9pbo3qu255rzn2r6.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%2F5vbe9pbo3qu255rzn2r6.png" alt="edit route-table" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Move to the public subnet, select the route table, edit the route table association, and select the route table created&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%2Fx7x8n9xpr3padzsm5eyq.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%2Fx7x8n9xpr3padzsm5eyq.png" alt="subnet rtb edit" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now SSH back into the instance and run the following:&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;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx &lt;span class="c"&gt;# to install nginx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before the creation of the private EC2, I copied the key into the public EC2 for secure SSH&lt;br&gt;
&lt;code&gt;scp -i key.pem key.pem ec2-user@&amp;lt;public-ec2-ip&amp;gt;:~/.ssh/&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting up the Private EC2
&lt;/h3&gt;

&lt;p&gt;Just like building the public EC2, I maintained everything except the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disabled auto-assign public ip&lt;/li&gt;
&lt;li&gt;Selected the private subnet&lt;/li&gt;
&lt;li&gt;Added Custom TCP on port 8080 to the inbound security rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The private EC2 is only accessible in the public EC2. To access the private EC2, SSH into the public, change directory to .ssh, and SSH from there.&lt;br&gt;
Once in the private EC2, I updated the OS and opened Vim to make a simple HTML page to serve up from the public EC2. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;html lang="en"&amp;gt;&lt;br&gt;
&amp;lt;head&amp;gt;&lt;br&gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;&lt;br&gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;&lt;br&gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;&lt;br&gt;
&amp;lt;/head&amp;gt;&lt;br&gt;
&amp;lt;body&amp;gt;&lt;br&gt;
    &amp;lt;h1&amp;gt;ich bin poloand&amp;lt;/h1&amp;gt;&lt;br&gt;
&amp;lt;/body&amp;gt;&lt;br&gt;
&amp;lt;/html&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
I served up this HTML file with Python, which ran in the background. &lt;br&gt;
&lt;code&gt;nohup python3 -m http.server 8080 &amp;amp;&lt;/code&gt;exit from the private EC2 to the public.&lt;/p&gt;

&lt;p&gt;Once in the public EC2, I changed the nginx config file to serve up the python server from the private EC2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;sudo&lt;/span&gt; &lt;span class="s"&gt;vim&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/nginx.conf&lt;/span&gt; &lt;span class="c1"&gt;# move the conf to make changes&lt;/span&gt;

&lt;span class="s"&gt;user&lt;/span&gt; &lt;span class="s"&gt;www-data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;worker_processes&lt;/span&gt; &lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;pid&lt;/span&gt; &lt;span class="n"&gt;/run/nginx.pid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;error_log&lt;/span&gt; &lt;span class="n"&gt;/var/log/nginx/error.log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/modules-enabled/*.conf&lt;/span&gt;;

&lt;span class="k"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;worker_connections&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;sendfile&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;tcp_nopush&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;types_hash_max_size&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/mime.types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;default_type&lt;/span&gt; &lt;span class="nc"&gt;application/octet-stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;ssl_protocols&lt;/span&gt; &lt;span class="s"&gt;TLSv1&lt;/span&gt; &lt;span class="s"&gt;TLSv1.1&lt;/span&gt; &lt;span class="s"&gt;TLSv1.2&lt;/span&gt; &lt;span class="s"&gt;TLSv1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="n"&gt;/var/log/nginx/access.log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;gzip&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/conf.d/*.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                         
                &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://privateIP:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sudo nginx -T # for conf linting&lt;/code&gt;&lt;br&gt;
&lt;code&gt;sudo systemctl restart nginx #to restart the service.&lt;/code&gt;&lt;br&gt;
Now open the browser to see the HTML page served up&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes I encountered
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;HTML file was not executable&lt;/li&gt;
&lt;li&gt;Security group blocking port 8080&lt;/li&gt;
&lt;li&gt;No key pair that resulted in a failed SSH into the private EC2.&lt;/li&gt;
&lt;li&gt;Missing semicolons in nginx.conf&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This project has taught me more about VPCs, subnets, IPv4s, compute, etc. Some of the lessons i got from this project are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security groups are everything about security&lt;/li&gt;
&lt;li&gt;Always create a key pair&lt;/li&gt;
&lt;li&gt;Always ls -l to see permissions on a file.&lt;/li&gt;
&lt;li&gt;Read config carefully&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next up more projects on VPC &lt;/p&gt;

</description>
      <category>aws</category>
    </item>
  </channel>
</rss>
