<?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: Bilal Bukhari</title>
    <description>The latest articles on DEV Community by Bilal Bukhari (@bilal_bukhari_75aeb34a969).</description>
    <link>https://dev.to/bilal_bukhari_75aeb34a969</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4122348%2Fb013453b-52bd-461f-8846-9e7e301491ec.png</url>
      <title>DEV Community: Bilal Bukhari</title>
      <link>https://dev.to/bilal_bukhari_75aeb34a969</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bilal_bukhari_75aeb34a969"/>
    <language>en</language>
    <item>
      <title>Launching an EC2 Instance, Connecting via RDP</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:11:41 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/launching-an-ec2-instance-connecting-via-rdp-4hkn</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/launching-an-ec2-instance-connecting-via-rdp-4hkn</guid>
      <description>&lt;p&gt;Everything I'd built with AWS up to this point was S3 — storage, permissions, static hosting. Today moved into actual compute: launching a virtual machine on EC2, connecting into it remotely over RDP, and learning how to back it up and move that backup around using snapshots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics Covered
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Launching an EC2 instance&lt;/li&gt;
&lt;li&gt;Connecting to it via RDP&lt;/li&gt;
&lt;li&gt;Taking EBS snapshots&lt;/li&gt;
&lt;li&gt;Sending and receiving snapshots&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Launching an EC2 Instance
&lt;/h2&gt;

&lt;p&gt;EC2 (Elastic Compute Cloud) is AWS's virtual machine service — instead of storing objects like S3, it gives you an actual running server you can log into and use. Launching one means choosing an AMI (Amazon Machine Image, essentially the OS template), an instance type (which determines CPU/RAM), a key pair for access, and a security group controlling what traffic can reach it.&lt;/p&gt;

&lt;p&gt;For this lab, I launched a Windows instance on a &lt;code&gt;t3.micro&lt;/code&gt; — small, cheap, enough to test with. A few minutes after launch, it showed up in the console as &lt;strong&gt;Running&lt;/strong&gt;, with all status checks passed:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4876hituk2o2iusjd8p7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4876hituk2o2iusjd8p7.png" alt=" " width="798" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The instance state and status checks matter more than they look like at first glance — "running" just means the VM booted, while the status checks confirm the underlying hardware and the OS itself are actually healthy. A running instance that fails a status check is not one you want to trust yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Connecting via RDP
&lt;/h2&gt;

&lt;p&gt;Since this was a Windows instance, the way in is RDP (Remote Desktop Protocol) rather than SSH. The security group has to explicitly allow inbound traffic on port 3389 for this to work at all — by default, nothing gets in.&lt;/p&gt;

&lt;p&gt;The process: retrieve the administrator password using the key pair created at launch, then connect using any RDP client (Windows' own Remote Desktop Connection app works fine) pointed at the instance's public IP. Once connected, it behaves exactly like a normal Windows desktop — except it's running on AWS hardware somewhere in a data center rather than the physical machine in front of me.&lt;/p&gt;

&lt;p&gt;This is the part that made cloud computing feel tangible in a way S3 hadn't. A bucket is abstract. A full remote desktop you're actively controlling is not.&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4876hituk2o2iusjd8p7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4876hituk2o2iusjd8p7.png" alt=" " width="798" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Taking Snapshots
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;snapshot&lt;/strong&gt; is a point-in-time backup of an EBS volume (the virtual hard disk attached to an EC2 instance). Rather than backing up files individually, a snapshot captures the entire volume's state, incrementally — after the first full snapshot, later ones only store the blocks that changed.&lt;/p&gt;

&lt;p&gt;I took three snapshots over the course of the lab, each showing as &lt;code&gt;Completed&lt;/code&gt; with the full volume captured:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvwk5v0f4sm9spt6kpxlp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvwk5v0f4sm9spt6kpxlp.png" alt=" " width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Snapshots are the foundation for a lot of what makes EC2 usable in production: recovering from a bad update, migrating a volume to a new instance, or scaling by launching new instances directly from a known-good image.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Sending and Receiving Snapshots
&lt;/h2&gt;

&lt;p&gt;Beyond just creating them locally, snapshots can be copied — including across regions and across AWS accounts. Sharing a snapshot means modifying its permissions to grant another account access, after which that account can copy it into their own environment and create a volume from it.&lt;/p&gt;

&lt;p&gt;This is the piece that turns a snapshot from "personal backup" into an actual transfer mechanism — moving a fully configured server environment from one place to another without manually reinstalling anything, just by handing over the snapshot and letting the other side spin up a volume from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;S3 taught me about storage and access control in the abstract. EC2 and snapshots are the first time I was working with something that behaves like a real, persistent machine — one that can be backed up, broken, restored, and handed off. That distinction between object storage and block storage tied to a running instance is a core piece of the AWS mental model, and this was the lab where it actually clicked instead of just being a definition I'd read.&lt;/p&gt;

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

&lt;p&gt;Now that I can launch, connect to, and snapshot an instance, the next logical step is automating this instead of doing it by hand through the console — looking at either the AWS CLI or Infrastructure as Code (Terraform or CloudFormation) to spin up the same setup repeatably.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Deploying a React E-Commerce Frontend on AWS S3</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Fri, 25 Sep 2026 20:32:37 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/deploying-a-react-e-commerce-frontend-on-aws-s3-1iie</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/deploying-a-react-e-commerce-frontend-on-aws-s3-1iie</guid>
      <description>&lt;p&gt;Most of what I've built on S3 so far has been about infrastructure — buckets, permissions, presigned URLs, events. Today was different: I took an actual frontend, a tech/gaming products landing page, and got it live on the internet using the same S3 static hosting setup I'd worked with before, just applied to something real this time instead of a placeholder template.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Page Itself
&lt;/h2&gt;

&lt;p&gt;It's a storefront-style landing page — hero section, top-rated products, featured categories, a trending products carousel, brand logos, and a footer. Nothing backend-driven yet, just the frontend shell of an e-commerce site: gaming peripherals, RAM, SSDs, cooling gear, that kind of catalog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting It Onto S3
&lt;/h2&gt;

&lt;p&gt;The deployment side was the same pattern I'd already built muscle memory for by this point: create the bucket, enable static website hosting, set &lt;code&gt;index.html&lt;/code&gt; as the index document, turn off Block Public Access, and attach a bucket policy granting public &lt;code&gt;s3:GetObject&lt;/code&gt; read access. What's different this time is that instead of one HTML file, this was a full asset folder — multiple image directories, nested paths, a real project structure instead of a single page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live here:&lt;/strong&gt; &lt;a href="http://laptop-605365943139-us-east-1-an.s3-website-us-east-1.amazonaws.com/index.html" rel="noopener noreferrer"&gt;http://laptop-605365943139-us-east-1-an.s3-website-us-east-1.amazonaws.com/index.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Actually Different About a Real Project vs a Test Upload
&lt;/h2&gt;

&lt;p&gt;Uploading one file to test hosting is a five-minute task. Uploading an entire project with a proper folder structure surfaces a different set of problems — relative paths that assumed a different root, asset folders that need to preserve their structure exactly, and making sure every referenced file actually made it into the bucket at the path the HTML expects it at. S3 doesn't care about folder structure conceptually (it's really just keys with slashes in them), but the moment an HTML file references &lt;code&gt;./icon/cart.png&lt;/code&gt; and that path doesn't resolve to an actual key in the bucket, you get a broken image instead of a build error — no failure message, just something quietly not showing up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This One Felt Different
&lt;/h2&gt;

&lt;p&gt;Every previous S3 lab was a controlled exercise — one bucket, one file, one concept being tested. This was the first time it was "take something that looks like a real product and put it in front of people," asset pipeline and all. It's a small step, but it's the difference between knowing how static hosting works and actually shipping something with it.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Building a Netflix-Inspired Frontend with React</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Thu, 24 Sep 2026 17:25:51 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/building-a-netflix-inspired-frontend-with-react-22p2</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/building-a-netflix-inspired-frontend-with-react-22p2</guid>
      <description>&lt;h1&gt;
  
  
  Building and Deploying a Netflix-Inspired React Landing Page on AWS S3 🎬☁️
&lt;/h1&gt;

&lt;p&gt;I recently finished building and deploying a &lt;strong&gt;Netflix-inspired frontend landing page using React&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The project started as a way to practice React and frontend development, but I also wanted to take it one step further and actually put the finished application online using &lt;strong&gt;Amazon S3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So instead of keeping the project running only on &lt;code&gt;localhost&lt;/code&gt;, I built the production version and deployed it as a live website using AWS S3.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌐 Live Demo
&lt;/h2&gt;

&lt;p&gt;🎬 &lt;strong&gt;Live Website:&lt;/strong&gt; &lt;a href="http://netflixlanding-605365943139-us-east-1-an.s3-website-us-east-1.amazonaws.com" rel="noopener noreferrer"&gt;http://netflixlanding-605365943139-us-east-1-an.s3-website-us-east-1.amazonaws.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/himbukharidev" rel="noopener noreferrer"&gt;https://github.com/himbukharidev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can open the live website and interact with the frontend directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ Technologies Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; — frontend development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite&lt;/strong&gt; — development/build tool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt; — application logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML &amp;amp; CSS&lt;/strong&gt; — structure and styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Router&lt;/strong&gt; — navigation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Axios&lt;/strong&gt; — HTTP requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lucide React&lt;/strong&gt; — icons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS S3&lt;/strong&gt; — static website hosting&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🎬 The Project
&lt;/h1&gt;

&lt;p&gt;The goal was to build a complete Netflix-inspired landing page rather than just recreating a single section.&lt;/p&gt;

&lt;p&gt;The page includes multiple sections and interactive elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hero Section
&lt;/h3&gt;

&lt;p&gt;The landing page starts with a large hero section designed around the visual style of a modern streaming platform.&lt;/p&gt;

&lt;p&gt;It contains the main promotional content and call-to-action elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎞️ Movie &amp;amp; Show Posters
&lt;/h3&gt;

&lt;p&gt;The page contains different sections displaying movie and show posters.&lt;/p&gt;

&lt;p&gt;I used reusable React components to avoid creating completely separate markup for every poster and section.&lt;/p&gt;

&lt;h3&gt;
  
  
  🖱️ Interactive Movie Details
&lt;/h3&gt;

&lt;p&gt;The posters aren't just static images.&lt;/p&gt;

&lt;p&gt;When a user clicks on a poster, a &lt;strong&gt;movie details popup/modal appears&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The selected movie's information is displayed inside the popup along with its poster, giving the interface a more interactive experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  🃏 Cards
&lt;/h3&gt;

&lt;p&gt;The landing page also contains additional card-based sections to make the page feel more complete rather than just being a collection of movie posters.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❓ FAQ Section
&lt;/h3&gt;

&lt;p&gt;I added an FAQ section where users can interact with the questions and view their answers.&lt;/p&gt;

&lt;p&gt;This was another opportunity to practice interactive React components.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Footer
&lt;/h3&gt;

&lt;p&gt;The page finishes with a complete footer containing additional navigation and information.&lt;/p&gt;




&lt;h1&gt;
  
  
  ⚛️ Building the UI with React
&lt;/h1&gt;

&lt;p&gt;One of the main things I wanted to practice was &lt;strong&gt;component-based development&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of putting everything into one large component, I separated the interface into reusable pieces.&lt;/p&gt;

&lt;p&gt;A simplified structure looks something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App
├── Navbar
├── Hero
├── Movie Sections
│   └── Movie Cards
├── Movie Details Modal
├── Cards
├── FAQ
└── Footer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The movie details popup was particularly useful for practicing React state.&lt;/p&gt;

&lt;p&gt;When a user selects a poster, the application keeps track of the selected movie and displays the appropriate information inside the modal.&lt;/p&gt;

&lt;p&gt;This allowed me to practice the basic React flow of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User clicks poster
       ↓
Update state
       ↓
Selected movie changes
       ↓
Modal appears
       ↓
Movie information is displayed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  📱 Making the Landing Page Responsive
&lt;/h1&gt;

&lt;p&gt;I also worked on making the frontend responsive across different screen sizes.&lt;/p&gt;

&lt;p&gt;The layout changes depending on the available screen space, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Movie poster dimensions&lt;/li&gt;
&lt;li&gt;Card sizes&lt;/li&gt;
&lt;li&gt;Spacing&lt;/li&gt;
&lt;li&gt;Typography&lt;/li&gt;
&lt;li&gt;Hero section&lt;/li&gt;
&lt;li&gt;Navigation&lt;/li&gt;
&lt;li&gt;Content layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was to keep the same overall design while making the page usable on smaller screens.&lt;/p&gt;




&lt;h1&gt;
  
  
  ☁️ Deploying the React Application to AWS S3
&lt;/h1&gt;

&lt;p&gt;This was one of the most useful parts of the project for me.&lt;/p&gt;

&lt;p&gt;Building the application locally is one thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Taking that application and making it accessible through a public URL is another.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since this project is a frontend/static application, &lt;strong&gt;Amazon S3&lt;/strong&gt; is suitable for hosting the production build.&lt;/p&gt;

&lt;p&gt;The deployment process was essentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React Application
       ↓
npm run build
       ↓
Production Build
       ↓
Upload Build Files
       ↓
Amazon S3 Bucket
       ↓
Static Website Hosting
       ↓
Live Website
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1. Creating the Production Build
&lt;/h2&gt;

&lt;p&gt;Once the React application was finished, I generated the production build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vite generated the production-ready files in the &lt;code&gt;dist&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;These are the files that need to be served to visitors instead of the development files used by &lt;code&gt;npm run dev&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Creating the S3 Bucket
&lt;/h2&gt;

&lt;p&gt;I created an S3 bucket specifically for the website.&lt;/p&gt;

&lt;p&gt;The bucket is used to store the static files generated by the React build.&lt;/p&gt;

&lt;p&gt;Instead of running a development server on my computer, the files are stored in AWS and served from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Uploading the Build
&lt;/h2&gt;

&lt;p&gt;I uploaded the contents of the production build to the S3 bucket.&lt;/p&gt;

&lt;p&gt;The important part here is uploading the &lt;strong&gt;contents of &lt;code&gt;dist&lt;/code&gt;&lt;/strong&gt;, rather than simply uploading the entire project folder.&lt;/p&gt;

&lt;p&gt;The bucket therefore contains the files needed by the browser to load the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Configuring Static Website Hosting
&lt;/h2&gt;

&lt;p&gt;I configured the S3 bucket for &lt;strong&gt;static website hosting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This tells S3 that the bucket is being used to serve a website rather than simply storing files.&lt;/p&gt;

&lt;p&gt;The website's entry point is the React application's &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Making the Website Accessible
&lt;/h2&gt;

&lt;p&gt;After configuring the required S3 settings and permissions, the files could be accessed through the S3 website endpoint.&lt;/p&gt;

&lt;p&gt;This allowed the React application to be opened from a browser without running anything locally.&lt;/p&gt;

&lt;p&gt;And that's the part I liked most about the deployment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The application went from a local React project to an actual live website hosted on AWS.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  🔄 Updating the Deployed Application
&lt;/h1&gt;

&lt;p&gt;Another useful thing I learned was that deployment doesn't mean the project is permanently finished.&lt;/p&gt;

&lt;p&gt;When I make changes to the React application, I can create a new production build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and upload the updated build files to S3.&lt;/p&gt;

&lt;p&gt;So the workflow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Make changes
     ↓
Test locally
     ↓
npm run build
     ↓
Upload updated files
     ↓
Refresh live website
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gave me a simple introduction to the basic idea of a &lt;strong&gt;frontend deployment workflow&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧠 What I Learned
&lt;/h1&gt;

&lt;p&gt;This project helped me practice both frontend development and basic cloud deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  React
&lt;/h3&gt;

&lt;p&gt;I became more comfortable with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reusable components&lt;/li&gt;
&lt;li&gt;Props and state&lt;/li&gt;
&lt;li&gt;Interactive UI&lt;/li&gt;
&lt;li&gt;Modals&lt;/li&gt;
&lt;li&gt;Rendering movie data&lt;/li&gt;
&lt;li&gt;Component organization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Frontend Development
&lt;/h3&gt;

&lt;p&gt;I practiced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responsive layouts&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;UI structure&lt;/li&gt;
&lt;li&gt;Cards&lt;/li&gt;
&lt;li&gt;Navigation&lt;/li&gt;
&lt;li&gt;FAQ interactions&lt;/li&gt;
&lt;li&gt;Designing a complete landing page&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AWS
&lt;/h3&gt;

&lt;p&gt;Most importantly, I got hands-on experience with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon S3&lt;/li&gt;
&lt;li&gt;S3 buckets&lt;/li&gt;
&lt;li&gt;Static website hosting&lt;/li&gt;
&lt;li&gt;Uploading production files&lt;/li&gt;
&lt;li&gt;Hosting a frontend application on AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AWS part was especially useful because it showed me that cloud services aren't only something to read about — I can actually use them to deploy something I've built.&lt;/p&gt;




&lt;h1&gt;
  
  
  🚧 What's Not Included
&lt;/h1&gt;

&lt;p&gt;This is a &lt;strong&gt;frontend project&lt;/strong&gt;, so it does not currently include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User authentication&lt;/li&gt;
&lt;li&gt;User accounts&lt;/li&gt;
&lt;li&gt;Watchlists&lt;/li&gt;
&lt;li&gt;Custom backend&lt;/li&gt;
&lt;li&gt;Database&lt;/li&gt;
&lt;li&gt;Personalized recommendations&lt;/li&gt;
&lt;li&gt;Actual video streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those would require additional backend and infrastructure work.&lt;/p&gt;

&lt;p&gt;For this project, I intentionally focused on the &lt;strong&gt;frontend experience and deployment&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  🎯 Final Thoughts
&lt;/h1&gt;

&lt;p&gt;This project was more than just recreating a familiar UI.&lt;/p&gt;

&lt;p&gt;I got to take the project through the complete basic workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build
  ↓
Test
  ↓
Create production build
  ↓
Deploy
  ↓
Make it publicly accessible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The combination of &lt;strong&gt;React + AWS S3&lt;/strong&gt; gave me practical experience with taking a frontend application from local development to a real deployed website.&lt;/p&gt;

&lt;p&gt;The project is now live, so feel free to check it out.&lt;/p&gt;

&lt;p&gt;🎬 &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="http://netflixlanding-605365943139-us-east-1-an.s3-website-us-east-1.amazonaws.com" rel="noopener noreferrer"&gt;http://netflixlanding-605365943139-us-east-1-an.s3-website-us-east-1.amazonaws.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/himbukharidev" rel="noopener noreferrer"&gt;https://github.com/himbukharidev&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;If you're interested in following my journey as I continue learning &lt;strong&gt;Java, Spring Boot, React, and AWS&lt;/strong&gt;, you can connect with me on LinkedIn:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="http://www.linkedin.com/in/bilalbukhari-dev" rel="noopener noreferrer"&gt;www.linkedin.com/in/bilalbukhari-dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>aws</category>
    </item>
    <item>
      <title>Presigned URLs and Event Notifications with S3 and SNS</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Sat, 19 Sep 2026 20:34:05 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/presigned-urls-and-event-notifications-with-s3-and-sns-56m0</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/presigned-urls-and-event-notifications-with-s3-and-sns-56m0</guid>
      <description>&lt;p&gt;Up until now, every file I've touched in S3 has gone through the console, or through a bucket policy that made things public for everyone. Today's problem was different: how do you let one specific person upload or download one specific file, temporarily, without making anything public and without giving them AWS credentials at all? That's what presigned URLs solve. Alongside that, I set up SNS to get notified whenever something actually happens in a bucket, instead of having to go check manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With "Just Make It Public"
&lt;/h2&gt;

&lt;p&gt;Public bucket policies work fine for something like a static website, where everyone should see the same content. They fall apart the moment access needs to be temporary or user-specific — a private document one customer should download, or an upload slot for one user that shouldn't stay open forever. Making the whole bucket public to solve that is the wrong tool for the job, and it's the kind of shortcut that turns into a real security problem later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Presigned URLs
&lt;/h2&gt;

&lt;p&gt;A presigned URL is a normal S3 object URL with a signature and expiry baked into the query string, generated using AWS credentials that already have permission on that object. Anyone holding that URL can perform the specific action it was signed for — a GET to download, a PUT to upload — until it expires, without needing any AWS credentials of their own.&lt;/p&gt;

&lt;p&gt;I generated these using the AWS SDK rather than the console, since that's how this actually gets used in a real app: the backend decides someone is allowed to access a specific file, generates a short-lived signed URL for it, and hands that URL back to the client. The backend never has to stream the file itself, and the client never touches an AWS secret key.&lt;/p&gt;

&lt;p&gt;The part worth paying attention to is the expiry window. Set it too long and you've basically recreated a public link with extra steps. Set it too short and legitimate users start hitting expired links mid-download. I ended up treating this as something to tune per use case rather than a single fixed number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding SNS for Event Notifications
&lt;/h2&gt;

&lt;p&gt;The second half of today was hooking up &lt;strong&gt;SNS (Simple Notification Service)&lt;/strong&gt; to S3, so that instead of periodically checking a bucket to see if anything changed, the bucket tells me when something does. S3 can publish an event — object created, object removed, etc. — directly to an SNS topic, and anything subscribed to that topic (an email address, an endpoint, another service) gets notified.&lt;/p&gt;

&lt;p&gt;Wiring this up is less about writing code and more about configuration: create the SNS topic, give the S3 bucket permission to publish to it, then configure the bucket's event notifications to fire on the events that matter (I focused on object creation for now, since "someone just uploaded something" is the one I actually needed to react to). Once that was in place, uploading a test file into the bucket produced a notification within seconds, with no polling involved anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why These Two Belong Together
&lt;/h2&gt;

&lt;p&gt;On their own, presigned URLs and SNS solve different problems — one is about controlled access, the other is about knowing when something happened. Put together, they start to look like the shape of a real upload pipeline: a backend issues a presigned URL so a user can upload directly to S3, and the moment that upload lands, an SNS notification fires so the rest of the system can react — kick off processing, update a database record, whatever needs to happen next — without the backend ever having to sit there polling the bucket to find out.&lt;/p&gt;

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

&lt;p&gt;Right now the SNS notification just proves the event fired — nothing is actually consuming it yet. The obvious next step is subscribing something more useful than my own inbox to that topic, likely an SQS queue or a Lambda function, so the notification actually triggers work instead of just being observed.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>sns</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Replacing Basic Auth with JWT and OAuth2 in Spring Security</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Fri, 18 Sep 2026 20:17:10 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/replacing-basic-auth-with-jwt-and-oauth2-in-spring-security-h9k</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/replacing-basic-auth-with-jwt-and-oauth2-in-spring-security-h9k</guid>
      <description>&lt;p&gt;Basic auth was always the placeholder. It worked, but sending credentials on every single request never sat right — no real session, no expiry, no way to log someone out without changing their password. This week I finally replaced it with JWT, and wired up OAuth2 alongside it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Move Off Basic Auth
&lt;/h2&gt;

&lt;p&gt;The app was already stateless, so on paper basic auth and JWT look similar — no server-side session either way. The difference is what's actually being sent. With basic auth, the raw username and password go out with every request, base64-encoded, which is not encryption, just encoding. With JWT, credentials are exchanged once at login, and after that a signed token carries the identity and role claims — the password never has to leave the client again after that first request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing JWT
&lt;/h2&gt;

&lt;p&gt;The flow ended up looking like this: a user logs in with username/password, the server verifies it, and issues a signed JWT containing the username and role as claims. Every request after that carries the token in the &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header instead of credentials.&lt;/p&gt;

&lt;p&gt;On the server side, I added a filter that runs before Spring Security's normal authentication step — it pulls the token out of the header, validates the signature, checks it hasn't expired, and if everything checks out, builds an &lt;code&gt;Authentication&lt;/code&gt; object from the claims and sets it into the security context. From that point on, the rest of the role-based access control I'd already built (USER vs ADMIN) just works unchanged, because it was always checking the authority on the authenticated principal, not caring how that principal got authenticated in the first place.&lt;/p&gt;

&lt;p&gt;That was actually the most satisfying part — the RBAC layer didn't need to be touched at all. Swapping the authentication mechanism underneath it and having the authorization layer keep working exactly as before is a good sign the earlier design was reasonably sound.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding OAuth2
&lt;/h2&gt;

&lt;p&gt;Alongside JWT, I set up OAuth2 login so users can authenticate through an external provider instead of only the app's own username/password flow. Spring Security's OAuth2 client support handles most of the heavy lifting here — the redirect to the provider, the callback, and pulling back user info — but I still had to decide how an OAuth2-authenticated user maps onto the same role system as everyone else, since a first-time OAuth2 login doesn't come with a role attached the way a normal registration does.&lt;/p&gt;

&lt;p&gt;The approach I landed on: on first OAuth2 login, create a local user record with a default role, so from that point forward they're indistinguishable from a normal registered user as far as the rest of the app is concerned. Two different front doors, same house once you're inside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I Got Stuck
&lt;/h2&gt;

&lt;p&gt;Token expiry handling was the annoying part. It's easy to issue a token that works — it's less obvious, at first, how to handle a client whose token has expired mid-session without just throwing a generic 401 and leaving them confused. I ended up making sure expired-token responses are distinguishable from invalid-token responses, so the client side can actually tell "log in again" apart from "something is wrong," instead of treating every failure the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Different Now
&lt;/h2&gt;

&lt;p&gt;Basic auth is gone. Every request now carries a token instead of raw credentials, that token has a real expiry, and there are two legitimate ways to authenticate — direct login or OAuth2 — both of which land in the same role-based system underneath. It's a lot more moving parts than the app had a week ago, but each part is doing something basic auth genuinely couldn't.&lt;/p&gt;

&lt;p&gt;Next up: refresh tokens, since right now an expired token just means logging in again from scratch, which isn't going to hold up once this is actually deployed somewhere.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>security</category>
      <category>jwt</category>
    </item>
    <item>
      <title>Implementing Role-Based Access Control in Spring Boot — Users, Admins, and Where the Line Gets Drawn</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Tue, 15 Sep 2026 19:53:24 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/implementing-role-based-access-control-in-spring-boot-users-admins-and-where-the-line-gets-23bp</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/implementing-role-based-access-control-in-spring-boot-users-admins-and-where-the-line-gets-23bp</guid>
      <description>&lt;p&gt;There's a moment in every backend project where "anyone can call any endpoint" stops being acceptable, and you have to actually decide who gets to see what. That moment hit me this week, and the answer was Spring Security with role-based access control (RBAC).&lt;/p&gt;

&lt;p&gt;Here's what I built: a registration system where a user can sign up as either a regular &lt;strong&gt;USER&lt;/strong&gt; or an &lt;strong&gt;ADMIN&lt;/strong&gt;, and depending on which one they are, they see a completely different slice of the application. A regular user can only view their own basic info — username, email, that's it. An admin, on the other hand, can pull up the full list of every registered user in the system.&lt;/p&gt;

&lt;p&gt;Simple to describe. Not quite as simple to get right the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Letting Users Pick a Role at Registration
&lt;/h2&gt;

&lt;p&gt;The registration endpoint takes a role field alongside the usual username/password/email — but I didn't want to just trust whatever the client sends blindly forever, since that's an easy way to let anyone register as an admin. For now, at this stage of the project, the role is accepted at signup and stored against the user, tied to Spring Security's &lt;code&gt;GrantedAuthority&lt;/code&gt; model, so every user ends up carrying a &lt;code&gt;ROLE_USER&lt;/code&gt; or &lt;code&gt;ROLE_ADMIN&lt;/code&gt; authority from the moment their account exists.&lt;/p&gt;

&lt;p&gt;That authority is what everything downstream checks against — not a name, not a flag scattered through the code, just one consistent thing Spring Security already knows how to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Locking Down Endpoints by Role
&lt;/h2&gt;

&lt;p&gt;This is where Spring Security actually earns its keep. Instead of writing &lt;code&gt;if (user.getRole().equals("ADMIN"))&lt;/code&gt; checks inside every controller method — which gets messy and easy to forget — the access rules live in the security configuration itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/api/users/me&lt;/code&gt; → accessible to any authenticated user, returns only their own data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/admin/users&lt;/code&gt; → accessible only to &lt;code&gt;ROLE_ADMIN&lt;/code&gt;, returns the full user list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a regular user tries hitting the admin endpoint directly, Spring Security shuts it down before the request even reaches the controller — a clean 403, no leaked data, no custom guard clause needed. That was honestly satisfying to see work correctly on the first real test.&lt;/p&gt;

&lt;p&gt;Worth noting: the app is already configured stateless (no server-side sessions), but JWT isn't in the picture yet — right now, authentication happens via HTTP Basic on each request. It works, but it's clearly a placeholder until token-based auth is in place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part That Actually Took Time
&lt;/h2&gt;

&lt;p&gt;The RBAC rules themselves weren't the hard part — wiring up the &lt;code&gt;UserDetailsService&lt;/code&gt; correctly so that authorities actually loaded and attached to the authenticated user on every request was where I spent most of my time. It's one of those things where the code looks fine, compiles fine, and then silently doesn't work because the authority string format doesn't match what the security config is checking for (&lt;code&gt;ADMIN&lt;/code&gt; vs &lt;code&gt;ROLE_ADMIN&lt;/code&gt; cost me a solid chunk of debugging time — Spring Security expects the &lt;code&gt;ROLE_&lt;/code&gt; prefix by convention, and it fails quietly rather than yelling at you about it).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters Beyond the Exercise
&lt;/h2&gt;

&lt;p&gt;This is the first time in this project that "the backend works" and "the backend is secure" stopped being the same statement. A working endpoint that returns data to anyone who asks isn't done — it's just functional. Adding the role layer is what actually makes it something you could put in front of real users without immediately regretting it.&lt;/p&gt;

&lt;p&gt;Next up: extending this with proper password hashing policies and actually implementing JWT for authentication — the app is already configured stateless, so this is the natural next piece rather than a rework.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>backend</category>
      <category>security</category>
    </item>
    <item>
      <title>Static Website Hosting on Amazon S3: From Bucket to Live URL</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Mon, 14 Sep 2026 20:07:26 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/static-website-hosting-on-amazon-s3-from-bucket-to-live-url-2hhi</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/static-website-hosting-on-amazon-s3-from-bucket-to-live-url-2hhi</guid>
      <description>&lt;p&gt;Continuing from where I left off with S3 fundamentals, today's focus was turning a plain bucket into an actual live website using S3's static website hosting feature — no EC2 instance, no server management, just a bucket serving HTML directly over the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics Covered
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Static website hosting configuration&lt;/li&gt;
&lt;li&gt;Index and error documents&lt;/li&gt;
&lt;li&gt;Public access blocking&lt;/li&gt;
&lt;li&gt;Bucket policies for public reads&lt;/li&gt;
&lt;li&gt;Testing the live endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Enabling Static Website Hosting
&lt;/h2&gt;

&lt;p&gt;By default, an S3 bucket is just object storage — it doesn't know how to behave like a website. Enabling &lt;strong&gt;static website hosting&lt;/strong&gt; (found under the bucket's Properties tab) turns it into one by telling S3 two things: which file to serve when someone visits the root URL, and which file to show if a requested page doesn't exist.&lt;/p&gt;

&lt;p&gt;Once enabled, S3 generates a dedicated &lt;strong&gt;website endpoint&lt;/strong&gt; in the form:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://&amp;lt;bucket-name&amp;gt;.s3-website.&amp;lt;region&amp;gt;.amazonaws.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For this lab, I set up the bucket &lt;code&gt;firststaticsite-605365943139-eu-north-1-an&lt;/code&gt; in &lt;code&gt;eu-north-1&lt;/code&gt;, uploaded a landing page template, and had it live at that endpoint within minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="http://firststaticsite-605365943139-eu-north-1-an.s3-website.eu-north-1.amazonaws.com/" rel="noopener noreferrer"&gt;http://firststaticsite-605365943139-eu-north-1-an.s3-website.eu-north-1.amazonaws.com/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Index and Error Documents
&lt;/h2&gt;

&lt;p&gt;Two settings drive how the site behaves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Index document&lt;/strong&gt; — the file served when someone visits the root of the site (almost always &lt;code&gt;index.html&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error document&lt;/strong&gt; — an optional custom page shown when a requested file doesn't exist, instead of S3's default XML error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Getting these right matters more than it seems — a missing or misconfigured index document is one of the most common reasons a freshly enabled static site fails to load.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Public Access Block
&lt;/h2&gt;

&lt;p&gt;By default, AWS blocks public access to every new bucket as a safety measure — which makes sense for general storage, but breaks a static website, since visitors need to reach the files without any AWS credentials.&lt;/p&gt;

&lt;p&gt;To fix this, &lt;strong&gt;Block Public Access&lt;/strong&gt; has to be explicitly turned off at the bucket level (Permissions tab). This is a deliberate extra step AWS added specifically to prevent people from accidentally exposing private data — so it's a conscious trade-off, not a default you stumble into.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Bucket Policy for Public Reads
&lt;/h2&gt;

&lt;p&gt;Turning off Block Public Access alone isn't enough — the bucket also needs an explicit &lt;strong&gt;bucket policy&lt;/strong&gt; granting read access to everyone. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PublicReadGetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::firststaticsite-605365943139-eu-north-1-an/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This grants &lt;code&gt;s3:GetObject&lt;/code&gt; (read-only) to anyone, scoped strictly to objects inside this one bucket — it doesn't expose anything else in the account.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Testing the Live Endpoint
&lt;/h2&gt;

&lt;p&gt;Once hosting is enabled, public access is unblocked, and the policy is in place, the site becomes reachable by anyone with the URL — not just the account owner logged into the AWS console. That last part is an easy trap: a page can look "live" while you're logged in and still fail for an outside visitor if permissions aren't fully open. Testing in an incognito window (or asking someone else to open the link) is the real test of whether the site is actually public.&lt;/p&gt;

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

&lt;p&gt;Static website hosting is a good next step after learning buckets and objects, because it forces you to actually deal with the permission model instead of just uploading files. The distinction between "the object exists in the bucket" and "the object is publicly reachable" is the core lesson here, and it's one that carries over directly into more advanced AWS work later on — IAM policies, CloudFront distributions, and beyond.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Amazon S3 Fundamentals: Buckets, Objects, Storage Classes, and Access Control</title>
      <dc:creator>Bilal Bukhari</dc:creator>
      <pubDate>Sun, 13 Sep 2026 18:57:32 +0000</pubDate>
      <link>https://dev.to/bilal_bukhari_75aeb34a969/amazon-s3-fundamentals-buckets-objects-storage-classes-and-access-control-published-false-5ll</link>
      <guid>https://dev.to/bilal_bukhari_75aeb34a969/amazon-s3-fundamentals-buckets-objects-storage-classes-and-access-control-published-false-5ll</guid>
      <description>&lt;p&gt;Amazon S3 (Simple Storage Service) is typically the first AWS service most engineers encounter when they begin working with cloud infrastructure. It is deceptively simple on the surface, but has considerable depth once access control, storage tiering, and cost optimization enter the picture. This post covers the core S3 concepts I worked through, supported by a short hands-on lab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics Covered
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Buckets&lt;/li&gt;
&lt;li&gt;Objects&lt;/li&gt;
&lt;li&gt;Uploading files&lt;/li&gt;
&lt;li&gt;Storage classes&lt;/li&gt;
&lt;li&gt;Bucket policies&lt;/li&gt;
&lt;li&gt;ACLs and permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Buckets
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;bucket&lt;/strong&gt; is the top-level container in S3 — the root under which every object is stored. Bucket names must be &lt;strong&gt;globally unique&lt;/strong&gt; across all of AWS, not just within a single account, which is why they often follow a pattern like &lt;code&gt;firstbucket-&amp;lt;account-id&amp;gt;-&amp;lt;region&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each bucket is also tied to a specific &lt;strong&gt;region&lt;/strong&gt; at creation time (e.g., &lt;code&gt;eu-north-1&lt;/code&gt;, Stockholm). This choice affects latency, cost, and data residency, since the underlying data physically resides in that region's data centers.&lt;/p&gt;

&lt;p&gt;For this lab, I created a bucket named &lt;code&gt;firstbucket-605365943139-eu-north-1-an&lt;/code&gt;. Immediately after creation, it was empty — zero objects — and ready to receive uploads.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Objects
&lt;/h2&gt;

&lt;p&gt;Everything you store inside a bucket — images, videos, documents, backups, logs — is called an &lt;strong&gt;object&lt;/strong&gt;. Each object consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;data&lt;/strong&gt; itself (the file)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;key&lt;/strong&gt; (essentially its full path/name inside the bucket)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt; (content type, size, last modified date, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's no real folder structure in S3 under the hood — folders are a UI convenience. What actually exists is a flat namespace of keys, and prefixes (like &lt;code&gt;images/photo.jpg&lt;/code&gt;) just simulate folder hierarchy.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Uploading
&lt;/h2&gt;

&lt;p&gt;Uploading is the process of adding an object to a bucket. In the AWS console, this is a straightforward &lt;strong&gt;Upload&lt;/strong&gt; action, though the same operation is typically automated through the CLI or an SDK in production systems.&lt;/p&gt;

&lt;p&gt;For this lab, I uploaded two JPEG images directly into the bucket. Once uploaded, S3 surfaces key metadata for each object — type, size, last modified timestamp, and storage class:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Storage Class&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WhatsApp Image ...11.01.41 PM.jpg&lt;/td&gt;
&lt;td&gt;jpeg&lt;/td&gt;
&lt;td&gt;201.5 KB&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WhatsApp Image ...11.17.02 PM.jpeg&lt;/td&gt;
&lt;td&gt;jpeg&lt;/td&gt;
&lt;td&gt;123.0 KB&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  4. Storage Classes
&lt;/h2&gt;

&lt;p&gt;Not all data needs to be instantly available all the time, and S3 gives you multiple &lt;strong&gt;storage classes&lt;/strong&gt; to balance cost vs. retrieval speed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 Standard&lt;/strong&gt; — frequently accessed data, highest availability, most expensive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Intelligent-Tiering&lt;/strong&gt; — automatically moves objects between tiers based on access patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Standard-IA / One Zone-IA&lt;/strong&gt; — infrequently accessed data, cheaper storage but a retrieval fee.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Glacier / Glacier Deep Archive&lt;/strong&gt; — long-term archival, very cheap storage, but retrieval can take minutes to hours.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, newly uploaded objects land in &lt;strong&gt;Standard&lt;/strong&gt;, which is exactly what I saw in the lab. Picking the right class for the right data is one of the easiest ways to cut cloud storage costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Bucket Policies
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;bucket policy&lt;/strong&gt; is a JSON document attached to the bucket itself that defines who can do what — for example, allowing public read access to a bucket used for a static website, or restricting access to specific IAM roles or AWS accounts.&lt;/p&gt;

&lt;p&gt;Because a bucket policy applies at the bucket level, it's the go-to tool when you want a single, centralized rule for everything inside that bucket (e.g., "only this Lambda function's role can write objects here").&lt;/p&gt;

&lt;h2&gt;
  
  
  6. ACLs and Permissions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Access Control Lists (ACLs)&lt;/strong&gt; are an older, more granular way to control access — at the level of individual buckets &lt;em&gt;or&lt;/em&gt; individual objects. They predate bucket policies and IAM, and AWS now recommends disabling ACLs in favor of bucket policies and IAM policies for most use cases, since ACLs can get messy to manage at scale.&lt;/p&gt;

&lt;p&gt;Broadly, S3 access boils down to three tools working together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IAM policies&lt;/strong&gt; — control what an AWS identity (user/role) can do across services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bucket policies&lt;/strong&gt; — control access to a specific bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ACLs&lt;/strong&gt; — legacy, fine-grained access on buckets/objects (mostly discouraged today).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding how these layers interact — and that they're evaluated together, not in isolation — is one of the more important "aha" moments when learning S3.&lt;/p&gt;

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

&lt;p&gt;This lab was intentionally small in scope, but it establishes the core mental model required before working with S3 in more advanced contexts — static website hosting, data lake architectures, or backend integrations. The next step in this learning path is exploring IAM in more depth and integrating S3 into a Spring Boot application.&lt;/p&gt;

&lt;p&gt;If you're working through AWS fundamentals as well, I'd be interested to hear which concept took longest to click. For me, it was distinguishing bucket policies, ACLs, and IAM policies — three mechanisms that all govern access, but at different layers and with different intended use cases.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
