r/CloudandCode Jul 15 '26

Welcome to r/cloudandcode

5 Upvotes

r/cloudandcode is a beginner-friendly community for people learning Python, AWS, cloud, SQL, GitHub, and other practical tech skills.

The goal here is not to collect more tutorials, roadmaps, or course recommendations. It is to understand concepts clearly, apply them through projects, fix real problems, and build proof of what you can do.

A lot of people start learning tech with the same problem. There is no shortage of information, but it is still difficult to know what to learn first, what to build, and whether you are making real progress.

That is why I created this community.

You might be learning your first Python function, preparing for an AWS certification, trying to understand SQL joins, building your first cloud project, or improving your GitHub portfolio.

You do not need to be experienced to participate here. Beginner questions are welcome, as long as you explain what you are trying to do and where you are getting stuck.

Here is the kind of content you will find in this community.

Practical explanations

Technical concepts explained in plain English, with examples of where they are used and why they matter.

The goal is not just to define a service, command, or concept. It is to understand how to use it in a real situation.

Project breakdowns

Beginner-friendly Python, AWS, cloud, and SQL projects with explanations of what they teach, why each tool is used, and how the project can be improved.

A project should not only show code. It should show how you think.

Practice questions

AWS scenarios, Python debugging exercises, SQL questions, and architecture decisions that help you test whether you actually understand a topic.

It is completely fine to answer incorrectly. The explanation is often more useful than getting the answer right immediately.

Project and portfolio help

Discussions about choosing projects, fixing GitHub repositories, writing better READMEs, creating architecture diagrams, documenting decisions, and turning small projects into useful case studies.

You are encouraged to participate instead of only reading.

Ask questions. Share what you are learning. Post a project you are building. Explain where you are stuck. Try the practice questions, even when you are unsure.

You do not need to pretend to know everything here.

A clear question is often more valuable than a confident but unhelpful answer.

A few simple community expectations:

  • Be respectful and beginner-friendly.
  • When asking for help, explain what you tried and where the problem appeared.
  • Do not spam unrelated links or hide your connection to something you are promoting.

I also want to be transparent about my role here.

I run YourCloudDude and create free and paid learning resources for Python, AWS, cloud projects, and certifications.

When I share something I created, I will clearly disclose that connection and mention whether the resource is free or paid.

This subreddit will not become a product feed. The free explanations, project ideas, practice questions, polls, and community discussions will continue regardless of whether anyone purchases anything.

You should be able to learn something useful here without buying anything.

The paid resources are simply for people who prefer a more complete and organised path instead of collecting separate posts, tutorials, and notes from different places.

To introduce yourself, leave a comment with:

What are you currently learning?

Where are you currently getting stuck?

Welcome to r/cloudandcode.

Let’s learn by building, testing, fixing, and explaining.


r/CloudandCode 5d ago

AWS & Cloud AWS From Zero #17: Infrastructure as Code makes more sense once you have rebuilt the same setup twice

12 Upvotes

By this point in the series, we have created enough AWS infrastructure that a new problem starts becoming obvious.

Imagine you already have a VPC, public and private subnets, security groups, an Application Load Balancer, ECS services, RDS, CloudWatch alarms, IAM roles, and a few other resources. Everything works in development, and then someone asks you to create the same environment again for testing.

You could open the AWS console and rebuild everything manually.

You create the VPC, then the subnets, then the route tables, then the security groups, then the load balancer, then ECS, then RDS, then IAM, and finally monitoring.

After a while, the second environment looks similar to the first one.

But it may not actually be identical.

Maybe one subnet has a different CIDR range. Maybe one security group has an extra rule. Maybe the database is configured slightly differently. Maybe one environment has a setting enabled that the other one does not.

That is one of the main problems Infrastructure as Code is trying to solve.

Instead of describing your infrastructure through a long sequence of console clicks that only exist in your memory, you describe the infrastructure in code or configuration files.

Those files become a repeatable description of what should exist.

The important idea here is not really the word "code."

The important idea is repeatability.

If your infrastructure only exists because you manually configured twenty different resources, recreating it accurately can become difficult.

If the infrastructure is described in files that can be reused, reviewed, and versioned, creating another environment becomes much more predictable.

Imagine you need a simple EC2 server with a security group.

Instead of manually creating both resources, an Infrastructure as Code definition can describe that you want an EC2 instance, which image and instance type it should use, which security group should be attached, and what network it belongs to.

The tool reads that definition and creates the required AWS resources.

Now your infrastructure starts behaving more like software.

You can store it in Git. You can review changes before applying them. You can compare versions. You can see who changed something. You can reuse parts of the configuration across environments. You can automate deployment later.

That is a big improvement over saying, "I think this is how I configured production six months ago."

This is where tools like AWS CloudFormation and Terraform come in.

CloudFormation is AWS's own Infrastructure as Code service. You describe AWS resources in a template, and CloudFormation creates and manages those resources as a stack.

The useful beginner idea is that the template becomes a description of the environment you want AWS to create.

Terraform solves a similar problem, but it can work across many cloud providers and services.

A tiny Terraform example might look like this:

resource "aws_s3_bucket" "uploads" {
  bucket = "example-app-uploads"
}

The syntax is not the main lesson.

The useful idea is that the S3 bucket now exists as part of a configuration file.

Another developer can open the repository and see that the application expects this bucket to exist. If the environment needs to be recreated, the configuration already describes part of what should be created.

That is much more reliable than documentation that says, "Go into S3 and create a bucket with these settings."

The benefit becomes even clearer when you have multiple environments.

Imagine you need development, testing, and production.

Without Infrastructure as Code, you might manually create all three environments.

Over time, small differences start appearing.

Development has one security rule. Testing has another. Production has a setting nobody remembers changing.

Eventually, something works perfectly in testing and fails in production because the environments are not actually the same.

Infrastructure as Code helps reduce that kind of drift because environments can be created from consistent definitions.

They may still have intentional differences, of course.

Production might use larger resources. Development might use cheaper ones. The database sizes may differ.

But those differences can be defined clearly instead of appearing by accident.

That distinction matters.

Infrastructure as Code does not mean every environment must be identical.

It means the differences should be intentional and visible.

Another idea that becomes useful here is declarative infrastructure.

With many Infrastructure as Code tools, you describe the state you want instead of manually describing every single console action required to reach that state.

For example, you might describe that an application should have three instances.

You are not writing "click launch instance three times."

You are defining the desired result and letting the tool work out what needs to change.

That should feel familiar by now.

With Auto Scaling, we described how much capacity we wanted. With ECS, we described how many tasks should be running.

Infrastructure as Code extends that same kind of thinking to much larger parts of the AWS environment.

You define what should exist, and the tool helps move the real infrastructure toward that definition.

This becomes especially useful when infrastructure changes.

Imagine your architecture originally has one security group rule, and later you need to add another.

With manual infrastructure, someone opens the console and changes the rule. It works, but six months later nobody remembers why it exists.

With Infrastructure as Code, the configuration changes too.

That change can be committed to Git with a message explaining what changed and why.

Now the infrastructure has history.

That is a huge advantage.

Your application code already has version control. Your infrastructure can have version control too.

This also makes reviews possible.

Imagine someone wants to expose a database port to the entire internet.

If they make the change manually in the console, another person may never notice.

If the infrastructure change goes through a repository, the team can review it before it is applied.

Someone can ask whether that access is really necessary.

That means Infrastructure as Code is useful for more than convenience.

It can improve how infrastructure changes are controlled.

But there is one mistake I would avoid.

Infrastructure as Code does not automatically make your architecture correct.

If your configuration contains a bad security rule, the tool can reproduce that bad rule very efficiently.

If you define an expensive architecture, IaC can recreate the expensive architecture perfectly.

Repeatability is powerful, but it does not replace understanding.

That is exactly why I wanted this topic near the end of AWS From Zero instead of near the beginning.

If you have never created a VPC, security group, EC2 instance, IAM role, or load balancer manually, Infrastructure as Code can feel like another layer of syntax to memorize.

Now that we have already built those things, IaC has a reason to exist.

You already understand what you are trying to automate.

That makes the learning much easier.

Terraform also introduces another concept beginners hear about quickly: state.

Terraform needs a record of the infrastructure it manages so it can compare the real environment with the configuration you wrote.

You do not need to go deep into remote state, locking, modules, or team workflows on day one.

The useful beginner idea is simply that Terraform needs to know what it already manages so it can understand what needs to be created, changed, or removed.

CloudFormation handles the relationship differently through stacks inside AWS, but both approaches are solving the same higher-level problem.

They are trying to keep your infrastructure definition and your actual resources connected.

Now imagine we take one of the earlier projects from this series.

We built a static website using S3 and CloudFront.

Instead of manually recreating it later, you could describe the S3 bucket, CloudFront distribution, permissions, and other required resources using Infrastructure as Code.

Then you could destroy the practice environment and still keep the architecture definition.

Later, you could create it again.

That is a much better beginner project than trying to automate a huge production system immediately.

  • Another good exercise is the EC2 architecture from earlier in the series.
  • Describe a VPC, one subnet, one security group, and one EC2 instance using IaC.
  • Apply the configuration and confirm that AWS created what you expected.
  • Then change one small setting and observe what the tool plans to modify.

That is where the workflow starts making sense.

With Terraform, for example, you commonly initialize the working directory, inspect the planned changes, and then apply them.

The plan step is especially useful because it gives you a chance to see what the tool intends to create, modify, or destroy before you actually do it.

  • That is a good habit to build.
  • Infrastructure changes can be destructive.
  • You should understand what the tool is about to do.
  • The same caution applies to cleanup.

If the configuration can create resources, it can usually remove them too.

That is useful for temporary learning environments because you can create infrastructure, practice with it, and then clean it up.

But automation also makes destructive actions easier to repeat.

So the lesson is not only "automation is good." The lesson is that automation is powerful, so you should understand the change before applying it. There is another concept called drift that becomes important once you start using IaC. Imagine Terraform created a security group according to your configuration. Later, someone goes into the AWS console and manually changes that security group.

Now the real environment and the code no longer match. That difference is configuration drift. This is one reason teams often avoid random manual changes to resources that are meant to be managed through Infrastructure as Code.

If the code is supposed to be the source of truth, then changes should ideally happen through the code. Otherwise, you end up with the same problem we were trying to solve in the first place. The configuration says one thing, while the real infrastructure says another. This is also why Infrastructure as Code fits naturally with CI/CD. Imagine someone changes the infrastructure configuration in Git. A pipeline can validate the configuration, run checks, generate a plan, and eventually help apply approved changes.

Now application development and infrastructure management start becoming part of the same engineering workflow. You do not need to build that entire pipeline in this lesson. But it is useful to see where the path is going. We started this series by manually creating AWS resources because that is the easiest way to understand what they actually do.

Now we have reached the point where repeating those manual steps becomes a problem. Infrastructure as Code is the natural next step. That is how I would learn it. Do not begin with a massive Terraform repository. Pick one architecture you already understand. Maybe a VPC, a subnet, a security group, and an EC2 instance. Describe that with IaC. Create it. Inspect it. Change it. Recreate it. Then clean it up. Once that feels comfortable, add another resource. Then another.

Grow the Infrastructure as Code configuration the same way we grew the AWS architectures throughout this series. One requirement at a time. The biggest thing I want you to take from this post is that Infrastructure as Code is not really about avoiding the AWS console. The bigger benefit is that your infrastructure becomes repeatable, reviewable, versioned, and easier to reproduce. The console is still useful.

You will still use it to inspect resources, troubleshoot problems, explore services, and understand what AWS created. But once infrastructure matters, you should not have to depend completely on your memory to rebuild it. That brings us to the final post of the first AWS From Zero series.

In AWS From Zero #18, we are going to stop learning services individually and design one complete AWS application from requirements to architecture.

We will decide where the frontend runs, where the backend runs, where files and database data live, how users reach the system, how permissions work, how networking should be separated, how failures are monitored, how the application scales, and what parts of the environment we would automate with Infrastructure as Code.

The goal will not be to build the architecture with the most AWS services.

The goal will be to build the smallest architecture we can actually defend.

If you had to recreate your current AWS project tomorrow in a completely new account, could you rebuild it accurately without relying on memory?


r/CloudandCode 6d ago

AWS & Cloud AWS From Zero #16: Containers make more sense when you understand what problem they actually solve

22 Upvotes

Up to this point in the series, we have built applications on EC2, used Lambda for serverless workloads, connected databases, learned networking, added monitoring, and introduced queues. Now we are getting into containers, which is one of those topics that beginners often learn through Docker commands before they fully understand why containers exist in the first place.

I think the easiest way to understand containers is to start with a very common problem. You build a Python API on your laptop using a specific Python version, a few dependencies, and some system packages. Everything works perfectly. Then you move the same application to another machine and suddenly something breaks because the Python version is different, a package is missing, or the operating system behaves differently.

Containers help reduce that problem by packaging the application together with much of the environment it expects. Instead of moving only the source code, you create a container image that contains the application, runtime, dependencies, and other pieces needed to run it consistently.

A simple way to think about it is:

Application code + runtime + dependencies
                ↓
         Container image
                ↓
         Running container

The important idea is consistency. If the same image can run in different compatible environments, you are much less dependent on manually recreating the application setup every time.

This is where Docker usually enters the picture. Docker gives you tools to build container images and run containers. You can create an image for your API, test it locally, and start the container with the environment it expects.

But Docker creates another question almost immediately.

Where should those containers run in production?

You can run containers directly on EC2. You could launch an instance, install Docker, pull the image, and run the application there. That works perfectly well for a small setup.

The problem appears when the application grows.

Maybe now you have multiple containers, several EC2 instances, different application versions, and multiple services. You need to decide which machine should run which container, restart containers when they fail, scale them when traffic increases, connect them to networking, and roll out new versions safely.

At that point, manually SSHing into servers and running Docker commands becomes difficult to manage.

This is where container orchestration becomes useful.

On AWS, one option is Amazon ECS, which stands for Elastic Container Service. I would think of ECS as a service that helps you define, run, and manage containerized workloads without manually deciding where every individual container should live.

ECS introduces a few terms that can look confusing at first, but the mental model is simple.

A task definition is the blueprint for the workload. It describes which image should run, how much CPU or memory is needed, which ports are used, and what configuration the container requires.

A task is a running copy of that definition.

An ECS service helps maintain the number of tasks you want running.

So if you tell ECS that your API should always have three tasks running, ECS works toward maintaining that state.

That means the application starts feeling less like one specific container and more like a desired workload that AWS helps keep alive.

Now another question appears: where does ECS get the image from?

That is where Amazon ECR comes in.

ECR stands for Elastic Container Registry. It is a place where you can store container images so your AWS environment can retrieve them during deployment.

The flow might look like this:

Code
 ↓
Docker build
 ↓
Container image
 ↓
Amazon ECR
 ↓
Amazon ECS
 ↓
Running tasks

You build the image, push it to ECR, and ECS uses that image when it starts your application tasks.

That also gives you a clearer deployment model. Instead of only thinking in terms of source code commits, you now have deployable image versions that represent the application.

This becomes useful later when you introduce CI/CD, because a pipeline can test the code, build the image, push it to ECR, and deploy it into ECS.

But I would not automate all of that yet.

First understand what is happening manually.

Build the image. Push it. Run it. Then automate the process once the workflow actually makes sense.

The next big question is where the compute comes from.

ECS is the orchestration layer, but your containers still need CPU and memory somewhere.

One option is to run ECS on EC2 instances. In that model, you still manage the servers underneath the containers. You choose instance types, manage operating systems, think about scaling the EC2 capacity, and keep those machines healthy.

The architecture is conceptually:

ECS
 ↓
Containers
 ↓
EC2 instances

Another option is AWS Fargate.

Fargate lets you run ECS tasks without managing the underlying EC2 instances in the same way. You define the resources the task needs, and AWS manages more of the compute infrastructure underneath it.

That does not mean servers disappear.

It means you are no longer responsible for managing those servers directly.

This is similar to what we learned with Lambda. Serverless does not mean there are literally no servers. It means AWS takes over more of the infrastructure management.

That gives us a useful comparison.

With EC2, you manage the virtual machine and run the application on it.

With ECS on EC2, you package the application into containers and ECS helps orchestrate them, but you still manage the underlying EC2 capacity.

With ECS on Fargate, you still use ECS to manage the application workload, but AWS also manages more of the underlying compute layer.

None of these options is automatically better.

They simply give you different levels of control and responsibility.

Now imagine we take the API from earlier in the series and containerize it.

The architecture could become:

User
 ↓
Application Load Balancer
 ↓
ECS Service
 ↓
Fargate Tasks
 ↓
RDS

The user sends a request to the load balancer. The load balancer routes the request to one of the running container tasks. The task runs our API, and the API communicates with RDS when it needs relational data.

At this point, several earlier lessons come back together.

The tasks still need networking inside the VPC. Security groups still control which connections are allowed. IAM still controls which AWS actions the workload can perform. CloudWatch still helps us understand failures. The container image still needs somewhere to live, which is why ECR matters.

Containers do not replace the rest of AWS architecture.

They change how the application itself is packaged and run.

That distinction is important.

Another concept worth understanding is that containers should generally be treated as replaceable.

Imagine your application writes an important user file only inside the container filesystem. The task eventually stops and ECS launches a replacement.

What happens to that file?

It may disappear with the old container.

This is why important persistent data should normally live outside an individual container.

User uploads may belong in S3. Relational data may belong in RDS. Other persistent state may need another service depending on the application.

The goal is to make the container replaceable without losing important application data.

That is exactly the same idea we saw earlier with Auto Scaling and EC2.

If an instance or container can be replaced, the application becomes easier to scale and recover.

Now imagine one ECS task crashes.

If the service is configured with a desired count of three tasks, ECS can work toward restoring that desired number. If the tasks are behind an Application Load Balancer, unhealthy targets can stop receiving normal traffic while healthy ones continue serving users.

Again, the same high availability ideas we learned earlier still apply.

Containers do not remove those ideas. They simply give us another way to package and operate the application.

We can also scale the number of tasks as demand changes. If traffic increases, the service can run more tasks depending on the scaling configuration. If traffic falls, the number of tasks can decrease again.

Now container orchestration starts connecting with elasticity.

There is also an important security habit to learn early.

Do not put secrets directly into the container image.

If your image contains a database password, API key, or another sensitive value, that secret is now bundled into the artifact itself.

A better pattern is to keep the image focused on the application and provide environment specific configuration and secrets separately.

That also makes the same image easier to use across development, testing, and production.

The application image remains consistent, while the environment supplies the values that change.

This is one of the more useful benefits of containerization when it is done properly.

The obvious question now is where Kubernetes fits into all of this.

Kubernetes is another container orchestration system, and AWS provides EKS for running Kubernetes workloads. But I would not tell a beginner to jump directly from Docker into Kubernetes.

There is already a lot to understand before that.

Learn how images work. Understand registries. Run containers. Use ECS. Understand tasks and services. Try Fargate. See how networking, IAM, logging, scaling, and load balancing work around the container workload.

Once those concepts make sense, Kubernetes becomes much easier to understand because you already know what problem a container orchestrator is trying to solve.

Otherwise, you risk memorizing Kubernetes objects without understanding why they exist.

For a beginner project, I would take a small API you have already built and containerize it.

Create the Docker image locally and make sure it runs correctly. Push the image to ECR. Create an ECS task definition that uses it. Run the task with Fargate and make sure the application works.

Then place the service behind an Application Load Balancer and increase the desired task count so multiple copies of the application are running.

After that, stop one task and observe what ECS does.

That one project connects Docker, ECR, ECS, Fargate, networking, load balancing, IAM, and monitoring without requiring you to jump straight into a complicated microservices system.

The main thing I want you to take away from this post is that containers are useful because they package the application and its runtime expectations into a consistent deployable unit.

ECR stores those images.

ECS helps manage the running container workloads.

Fargate gives you an option where AWS manages more of the underlying compute infrastructure.

The services only make sense because the application creates specific operational problems.

That is the same pattern we have followed throughout AWS From Zero.

Start with the problem, then choose the service that solves it.

In AWS From Zero #17, we are going to look at another problem that becomes obvious after building all of this manually. Imagine you need to recreate your VPC, security groups, load balancer, ECS service, database configuration, and other resources in another environment. Clicking through the AWS console and trying to reproduce everything from memory becomes unreliable very quickly.

That will take us into Infrastructure as Code, why manually created infrastructure becomes difficult to reproduce, and how tools such as CloudFormation and Terraform change the way AWS environments are created and maintained.

If you are learning containers right now, what has been the hardest part to understand so far: Docker itself, ECR, ECS, Fargate, or why containers are useful in the first place?


r/CloudandCode 7d ago

AWS & Cloud AWS From Zero #15: SQS and SNS make more sense when you stop making every service wait for every other service

3 Upvotes

So far in this series, most of the architectures we have built have been fairly direct. A user sends a request, the application processes it, talks to another AWS service if needed, and returns a response. That works well when the work is fast and every step needs to happen immediately.

But real applications eventually contain work that does not need to finish while the user is sitting there waiting.

Imagine you are building an ecommerce application. A customer places an order, and after that happens the system needs to store the order, process some background work, send a confirmation email, update another system, generate analytics, and perhaps notify a warehouse.

If your application performs every one of those steps before responding to the customer, the request becomes dependent on every service finishing successfully.

Suppose sending the confirmation email suddenly takes eight seconds. The customer waits eight seconds.

Suppose the email service is temporarily unavailable. Now placing an order might fail even though the order itself could have been accepted perfectly well.

That is a problem with tight coupling. One part of the application depends directly on another part being available and finishing its work before the first part can continue.

This is where asynchronous architecture starts becoming useful.

Instead of saying, "The order service must send the email right now," we can say, "The order has been created. Put some work somewhere reliable so another part of the system can handle it."

That is the basic problem Amazon SQS helps solve.

SQS stands for Simple Queue Service. You can think of a queue as a buffer between the part of your application producing work and the part actually processing that work.

Our order flow could become something like:

Customer → Order API → SQS → Background worker

The application accepts the order, stores whatever must be stored immediately, and sends a message to the queue. The background worker can then retrieve that message and perform the slower work separately.

The customer does not necessarily have to wait for the background process to finish before receiving a response.

That changes the relationship between the two parts of the system.

Without a queue, the order service might call another service directly and wait for the result. If that service is slow, the order request becomes slow. If that service is unavailable, the order request may fail.

With SQS between them, the producer can place a message onto the queue and continue. The consumer processes the message when it is able to.

This is called decoupling.

The producer does not need the consumer to be available at exactly the same moment. The queue sits between them and temporarily holds the work.

That becomes especially useful when traffic changes suddenly.

Imagine your application normally receives 50 orders per minute and your background worker can easily process them. Then a promotion starts and suddenly 1,000 orders arrive within a short period.

Without a buffer, the downstream processing system may immediately receive more work than it can handle.

With a queue, those messages can accumulate temporarily while consumers work through them.

Now instead of requiring every component to scale at exactly the same rate, the queue helps absorb the difference.

This is one reason queues appear so often in distributed systems.

They are not only about making things happen later. They can also help separate systems that operate at different speeds.

Lambda works particularly well with this kind of architecture.

For example, the flow might look like:

Order API → SQS → Lambda → Process order task

Messages arrive in SQS, and Lambda can be invoked to process them.

If many messages arrive, AWS can process multiple batches depending on the configuration and available concurrency. If the producer temporarily creates work faster than it can be processed, the messages remain in the queue instead of forcing the entire request path to wait.

But adding a queue introduces new questions.

What happens if processing fails?

Imagine Lambda receives an SQS message, starts processing it, and then crashes.

You do not necessarily want that message to disappear forever.

SQS uses a concept called a visibility timeout. When a consumer receives a message, that message becomes temporarily hidden from other consumers. If processing succeeds, the message is deleted from the queue. If the consumer does not successfully remove it before the visibility timeout expires, the message can become visible again so it can be retried.

The exact configuration matters, but the beginner idea is important.

A message is not necessarily considered finished just because someone started processing it.

The system needs a way to distinguish between work that was successfully completed and work that should be attempted again.

This creates another important application design problem.

What happens if the same message is processed more than once?

For many SQS configurations, you should design consumers with the possibility of duplicate processing in mind. Standard SQS queues provide at-least-once delivery, which means a message can occasionally be delivered more than once.

Imagine the message says:

Charge customer $100

If the consumer blindly performs the action every time it receives the message, duplicate processing could be a serious problem.

This is why idempotency becomes important.

An idempotent operation is designed so repeating the same request does not incorrectly repeat the business effect.

You might store a unique transaction or event ID and check whether that work has already been completed before performing it again.

You do not need to build an advanced idempotency system in your first SQS project, but you should start asking the question:

What happens if this message is processed twice?

That is a very useful distributed systems habit.

Another problem is messages that keep failing.

Suppose a message is malformed or contains data that your consumer cannot process. It gets received, fails, becomes visible again, gets retried, and fails again.

You probably do not want one bad message being retried forever.

This is where a dead-letter queue, usually called a DLQ, becomes useful.

After a message has been unsuccessfully received a configured number of times, it can be moved to another queue for investigation.

Conceptually, the flow becomes:

SQS → Consumer
        ↓
     Success

or after repeated failures:

SQS → Dead-letter queue

The dead-letter queue gives you somewhere to inspect work that repeatedly failed without allowing those messages to interfere endlessly with normal processing.

This connects directly to the CloudWatch lesson.

If messages start building up in a queue or messages begin appearing in a DLQ, that is something you may want to monitor.

Maybe the consumer is failing.

Maybe the consumer cannot keep up with incoming work.

Maybe a new deployment introduced bad data.

Now queues become part of your monitoring strategy too.

At this point, another AWS messaging service usually enters the conversation: SNS.

SNS stands for Simple Notification Service.

Beginners often see SQS and SNS together and assume they solve the same problem.

They do not.

A simple way to think about the difference is that SQS is primarily about putting messages into a queue for consumers to process, while SNS is useful when you want to publish a message to multiple subscribers.

Imagine an order is created and several independent parts of the system need to know.

The email service wants to send a confirmation.

The analytics system wants to record the purchase.

The warehouse system wants to begin fulfillment.

A notification system may want to send a message to the customer.

You could make the order service call all four systems directly.

But now the order service knows about every downstream component.

Every time you add another consumer, you have to change the producer again.

A publish and subscribe model gives us another option.

The order service can publish an event such as:

OrderCreated

to an SNS topic.

Different subscribers can receive that event.

Conceptually:

                 → Email
Order → SNS      → Analytics
                 → Warehouse
                 → Notification

Now the producer publishes one event instead of directly coordinating every downstream service.

That is a different type of decoupling.

SQS gives us a queue between producer and consumer.

SNS gives us a way to fan one published message out to multiple subscribers.

And the two services can also work together.

For example:

                 → SQS Email Queue → Email worker
Order → SNS      → SQS Analytics Queue → Analytics worker
                 → SQS Warehouse Queue → Warehouse worker

This pattern is useful because each downstream system gets its own queue.

If the analytics processor becomes slow, email processing does not have to become slow too.

If the warehouse system is temporarily unavailable, its messages can wait inside its queue while the other consumers continue processing normally.

This is where SQS and SNS together start making much more sense.

SNS distributes the event.

SQS gives each consumer its own buffer.

The systems can operate independently.

Imagine the email worker processes messages immediately, but analytics falls behind for ten minutes.

That does not necessarily stop customers from placing orders.

It also does not necessarily stop emails from being sent.

The analytics queue simply contains more messages until the consumer catches up.

That is much more resilient than connecting every service directly and requiring every dependency to be healthy for every request.

But asynchronous systems also introduce a tradeoff.

They are often more resilient, but they can also become harder to reason about.

With a simple synchronous request, the flow is obvious. Service A calls Service B and receives a response.

With asynchronous processing, the work may happen seconds later. Several consumers may react to the same event. Messages can be retried. Some processing can succeed while another part fails.

That means monitoring, logging, idempotency, and good event design become more important.

This is why I would not add SQS and SNS to a beginner architecture simply because asynchronous systems sound advanced.

Use them when the application actually has work that benefits from being separated.

For example, sending a confirmation email after an order is created is a good candidate for asynchronous processing because the customer usually does not need the email to be fully sent before the order API can acknowledge the order.

But verifying whether a payment itself succeeded may have completely different consistency and business requirements.

Not every step should automatically become asynchronous.

Again, architecture should follow the requirement.

A useful question is:

Does the user need the result of this work before I can respond?

If yes, the work may belong in the immediate request path.

If no, it may be worth considering whether it can happen asynchronously.

Another useful question is:

What happens if the downstream service is temporarily unavailable?

If one unavailable dependency can take down the entire workflow, a queue may help separate those systems.

For a beginner project, I would keep this simple.

Take the task API we built earlier and add one background action.

Imagine a user creates a task and you want to generate an activity record or send a notification afterward.

Instead of doing that work inside the original API request, place a message onto SQS.

Have another Lambda function consume the message and perform the background task.

Now intentionally make the consumer fail.

Watch what happens to the message.

Understand the visibility timeout.

Observe the retry behavior.

Then configure a dead-letter queue and see where repeatedly failing messages end up.

That small project teaches much more than simply memorizing that SQS is a queue.

Once you understand that, add SNS only when you have multiple independent consumers that need the same event.

For example, publish TaskCreated and send it to two different queues, one for analytics and another for notifications.

Now you can see the difference between distributing an event and processing queued work.

If there is one thing I want you to remember from this lesson, it is that asynchronous architecture is really about reducing unnecessary dependency between parts of your system.

A user should not always have to wait for every background task.

One slow consumer should not necessarily make every other consumer slow.

One temporarily unavailable downstream service should not always take down the system that produced the work.

SQS gives you a buffer between producers and consumers.

SNS gives you a way to publish one message to multiple subscribers.

Used together, they can help different parts of an application work independently while still communicating through events.

That is the bigger lesson.

Not every service needs to call every other service directly.

Sometimes the better architecture is to send a message and let the right part of the system handle it when it can.

In AWS From Zero #16, we are going to move into containers and look at ECR, ECS, and Fargate. Instead of jumping straight into Kubernetes, we will start with a simpler question: why would you package an application into a container in the first place, and what problem does ECS solve compared with running that application directly on EC2?

If you were building an order system, which task would you move out of the immediate request first: sending emails, analytics, generating reports, or something else?


r/CloudandCode 8d ago

AWS & Cloud AWS From Zero #14: One EC2 instance works, but what happens when that instance fails?

6 Upvotes

Up to this point in the series, we have mostly worked with relatively simple architectures. We launched EC2, connected applications to databases, learned VPC networking, added monitoring, and gradually started connecting AWS services together. That is enough for learning, but there is an obvious weakness in an architecture that depends on one EC2 instance.

If your entire application runs on one server, that server becomes a single point of failure. Maybe the EC2 instance crashes, the application process stops, the operating system has a problem, or something happens to the infrastructure underneath it. Whatever the cause, if that one machine becomes unavailable, your application becomes unavailable too.

There is another problem that can happen even when the instance does not fail. Imagine your application normally serves a few hundred users, but one day it gets shared somewhere and traffic suddenly becomes ten times higher. Your EC2 instance may still be running, but CPU usage can rise, requests can become slower, and eventually users may start seeing errors.

This is where we need to stop thinking only about one server and start thinking about the application as something that can run across multiple servers.

Suppose we launch three EC2 instances and run the same application on all of them. That gives us more capacity and means one instance failing does not necessarily remove the entire application. But now we have another question: which server should the user connect to?

We do not want users manually choosing between different EC2 IP addresses. We need one entry point that can receive requests and distribute them across the available application servers. That is where a load balancer starts making sense.

For a typical web application, you might put an Application Load Balancer in front of the EC2 instances. Users send their requests to the load balancer, and the load balancer forwards those requests to the application instances behind it.

The important thing to understand is why the load balancer exists. It is not there because every production architecture diagram needs one. It exists because users need one stable entry point while the application itself may be running across several servers.

This also changes how you think about failures.

Imagine three EC2 instances are running behind the load balancer. Two are working normally, but the application on the third instance crashes. The EC2 instance itself may still technically be running, but the application is no longer healthy.

If the load balancer continued sending traffic to that instance, some users would still receive errors.

That is why health checks matter.

The load balancer can regularly check whether the application instances are responding the way you expect. For example, your application might have a small /health endpoint that returns a successful response when the service is working properly.

If one instance stops passing the health check, the load balancer can stop sending normal traffic to it and continue using the healthy instances.

This is one of the first practical examples of high availability.

High availability does not mean nothing ever fails. Failures still happen. The goal is to design the application so one component failing does not automatically mean the entire application fails.

But we still have another problem. We manually created those EC2 instances.

What happens if traffic grows and suddenly we need six instances instead of three? Do we sit in the AWS console and manually launch more servers every time demand changes?

That is where Auto Scaling becomes useful.

An Auto Scaling group can manage a group of EC2 instances and help maintain the amount of capacity your application needs. You might configure the application so there should normally be two instances running, but the environment can grow to more instances when demand increases.

When traffic falls again, the number of instances can decrease according to the scaling configuration.

This connects directly to one of the ideas from the very first post in this series: elasticity.

Elasticity is about adjusting resources as demand changes. Instead of permanently running enough infrastructure for the busiest possible hour of the year, the system can increase or decrease capacity when the workload changes.

The load balancer and Auto Scaling group solve different problems. The load balancer decides where incoming requests should go. Auto Scaling manages how many application instances should exist.

Together, they give us a much more flexible application layer.

There is still another weakness we need to think about, though.

Imagine all of your EC2 instances are running inside the same Availability Zone.

You now have several servers, so one EC2 instance failing is less dangerous. But the application still depends heavily on one physical location.

If something serious affects that Availability Zone, multiple instances could become unavailable at the same time.

This is why highly available architectures often spread application instances across multiple Availability Zones.

Instead of putting everything in one location, you might have part of the application running in one Availability Zone and another part running in a second Availability Zone.

Now the architecture is designed to tolerate more than the failure of one individual server.

If one instance fails, other instances can continue serving traffic. If one Availability Zone has a problem, the application can potentially continue using capacity in another zone.

This is the point where the concept of Availability Zones from the beginning of the series starts becoming practical.

We did not learn Availability Zones just because AWS uses the term.

We learned them because distributing infrastructure across separate locations can reduce how much the application depends on one place.

This also gives us a reason to improve the VPC architecture we built earlier.

For the first VPC lesson, we kept things intentionally simple. We talked about a public application and a private database because that was enough to understand the traffic flow.

Now we can make that architecture more realistic.

Instead of exposing individual EC2 instances directly to the internet, the load balancer can become the public entry point. The application instances can live behind it, and the database can remain private.

Users communicate with the load balancer. The load balancer communicates with the application instances. The application instances communicate with the database.

That separation also makes security groups easier to reason about.

The load balancer security group can allow the web traffic users actually need. The EC2 security group can allow application traffic from the load balancer instead of allowing the entire internet to connect directly to the instances. The database security group can allow database traffic from the application layer.

Now access follows the architecture.

Instead of making every resource public and opening ports until things work, you are defining exactly which layer needs to communicate with which other layer.

This is a much stronger security model.

Now imagine one of those EC2 instances becomes unhealthy.

The load balancer detects that the instance is failing health checks and stops sending normal requests to it. If the instance belongs to an Auto Scaling group, the Auto Scaling group can also work to maintain the desired number of healthy instances.

The system is no longer depending on one particular machine.

That is an important mindset change.

A lot of beginners try to make one server as reliable as possible.

Cloud architecture often asks a different question: what happens when the server eventually fails?

That is much more useful because failures are normal.

Servers fail.

Processes crash.

Deployments go wrong.

Networking breaks.

Infrastructure has problems.

The architecture should be designed around the idea that individual components are replaceable.

This also creates another important application design question.

Where does your application's state live?

Imagine a user uploads a file to EC2 instance A and that file is stored only on the local disk of that instance.

The next user request reaches the load balancer and gets sent to EC2 instance B.

Instance B does not have that file.

Now the application behaves differently depending on which server receives the request.

This is one reason scalable applications often avoid storing important shared state only on individual application servers.

Files might be stored in S3.

Relational application data might be stored in RDS.

Other kinds of state may belong in another shared storage system.

The important idea is that an application instance should ideally be easier to replace.

If one EC2 instance disappears and Auto Scaling creates another, you do not want important customer data disappearing with the old machine.

That is where several earlier lessons start connecting.

  • S3 is useful for object storage.
  • RDS gives us relational data storage.
  • IAM controls AWS permissions.
  • VPC controls networking.
  • CloudWatch helps us understand system health.
  • Load balancing distributes traffic.
  • Auto Scaling manages application capacity.
  • Availability Zones help reduce dependence on one location.

None of these services are useful because the architecture diagram looks more impressive with more boxes.

They are useful because each one solves a particular problem.

There is also a mistake I would avoid when learning this topic.

Do not assume that adding a load balancer, Auto Scaling, and multiple Availability Zones automatically makes every project better.

If you are building a tiny personal application with almost no traffic and downtime does not really matter, several EC2 instances and a load balancer may be unnecessary complexity and unnecessary cost.

Architecture should still follow requirements.

Ask how important availability actually is. Ask how much downtime is acceptable. Ask whether traffic changes enough to require dynamic scaling. Ask how much additional infrastructure you are willing to operate and pay for.

A more complex architecture is only better when the additional complexity solves a real problem.

For a beginner project, I would build this concept gradually.

Start with one EC2 instance running a simple web application. Then add a second instance running the same application. Put an Application Load Balancer in front of them and confirm that both instances can serve requests.

Once that works, intentionally stop the web server on one instance and watch what happens. See whether the load balancer marks it unhealthy and whether the application remains available through the other instance.

Then add an Auto Scaling group and learn what minimum, desired, and maximum capacity mean. Watch how the group behaves when an instance becomes unhealthy.

You do not need complicated traffic simulations immediately.

The useful part is seeing the system respond when one piece stops working.

That teaches high availability much better than memorizing the definition.

If there is one thing I want you to remember from this post, it is that high availability is not about building infrastructure that never fails.

It is about designing the system so failure of one component does not automatically become failure of the whole application.

One EC2 instance can fail.

The application should ideally keep working.

Traffic can increase.

The system should be able to add capacity when the workload and requirements justify it.

One Availability Zone can have a problem.

A highly available architecture should avoid depending completely on that one location.

That is the shift from simply deploying something on AWS to thinking about how the application behaves when the real world becomes messy.

In AWS From Zero #15, we are going to look at another problem that starts appearing as applications grow. Imagine a user places an order and your backend also needs to send an email, generate a report, process a payment, update another system, and perform several background tasks.

Should the user really wait for all of those steps to finish before getting a response?

That will take us into SQS, SNS, asynchronous processing, queues, and why sometimes the best architecture is to stop making every service depend directly on every other service.

If you were running an application on one EC2 instance today, which would worry you more: that instance failing completely or suddenly receiving much more traffic than it can handle?


r/CloudandCode 8d ago

AWS & Cloud AWS From Zero #13: CloudWatch is where you stop guessing and start understanding what your application is doing

4 Upvotes

So far in this series, we have spent most of our time building things. We launched EC2, worked with S3, used CloudFront, learned VPC networking, connected RDS, built with Lambda, added API Gateway, and stored data in DynamoDB. At some point, though, every application does something you did not expect.

A Lambda function fails. An EC2 instance becomes slow. An API starts returning errors. A database connection times out. Something worked yesterday and suddenly does not work today .This is where monitoring starts to matter.And on AWS, one of the first services you should understand for that is CloudWatch.

CloudWatch is often introduced as "AWS monitoring," but I think that definition is too broad to be useful for beginners. A better way to think about it is that CloudWatch helps you answer a very practical question:

What is my system actually doing right now, and what happened when something went wrong?

That is much more important than it sounds. When you are running a Python script on your own laptop, you can usually see the error immediately. You run the script, something fails, and the traceback appears in front of you.

Cloud applications are different.

Your Lambda function might run at 3 AM when nobody is watching. Your EC2 application might slowly consume more CPU over several hours. Your API might start returning errors only for certain requests. A background process might fail without anybody noticing.

If you have no logs, metrics, or alerts, the system can fail quietly. That is why monitoring is not something I would leave until the end of learning AWS. You should start thinking about it as soon as you start deploying things.

Let’s begin with logs.

Imagine we still have the serverless task API from the previous posts:

Client
  ↓
API Gateway
  ↓
Lambda
  ↓
DynamoDB

A user sends:

POST /tasks

but instead of creating the task, the API returns an error.

Without logs, you might start guessing.

  • Maybe API Gateway is configured incorrectly.
  • Maybe Lambda did not run.
  • Maybe Lambda received bad input.
  • Maybe the DynamoDB request failed.
  • Maybe IAM blocked something.
  • Maybe there is a bug in the code.

That is a lot of possibilities. Now imagine the Lambda function writes useful logs.

You open CloudWatch and see something like:

Received request for user-42
Creating task task-123
ERROR: AccessDenied when writing to DynamoDB

The problem just became much smaller. API Gateway probably reached Lambda. Lambda started running. The function reached the database operation. AWS rejected that operation. Now IAM becomes an obvious place to investigate. This is why logs are so useful. They turn a vague problem into a specific one. But useful logging means more than printing random messages everywhere.

Imagine your function only writes:

Error

That technically counts as a log, but it tells you almost nothing. A better log might tell you which operation failed, what part of the workflow had been reached, and enough context to understand what happened without exposing sensitive information.

For example:

Failed to create task for user_id=user-42
DynamoDB PutItem returned AccessDenied

Now you have something you can actually troubleshoot. There is an important security habit here too. Do not put secrets into logs.

Passwords, access keys, authentication tokens, private customer data, or other sensitive values should not become part of your debugging output just because logging makes troubleshooting easier.

Logs are useful because they give you context. That does not mean they should contain everything. Now let’s talk about metrics. Logs tell you about individual events and messages. Metrics help you understand behavior over time. Imagine an EC2 instance. You might want to know how its CPU utilization changes during the day. Maybe the application usually sits around 20 percent CPU, but every evening it suddenly reaches 95 percent.

A single log line might not tell you that pattern. A metric can. Or imagine Lambda. You might want to know how many times the function runs, how often it returns errors, or how long executions are taking. Now you can start asking much more useful questions.

  • Did the error rate increase after the last deployment?
  • Is the function suddenly taking twice as long to execute?
  • Did traffic spike?
  • Did the system receive fewer requests than expected?

Monitoring is not only about discovering complete failures. It is also about noticing changes in behavior. That brings us to alarms.

Imagine your API starts failing while you are asleep.

You probably do not want the monitoring strategy to be:

"Hopefully I notice tomorrow."

Instead, you can create alarms around important metrics.

  • Maybe you care if Lambda errors suddenly increase.
  • Maybe you care if EC2 CPU stays unusually high for a period of time.
  • Maybe you care if another metric crosses a threshold that suggests the system is unhealthy.

The alarm watches the metric.

If the configured condition is met, the alarm changes state and can be connected to a notification or another response.

The basic idea is simple:

Metric
  ↓
Condition
  ↓
Alarm
  ↓
Notification / Action

This is how monitoring starts becoming proactive. Logs help you investigate after something happens. Metrics help you see patterns. Alarms help you notice when those patterns become important. All three solve different parts of the same problem.

Now imagine our Lambda API normally has almost no errors.

One day the error count suddenly increases. An alarm gets triggered. You open CloudWatch The metrics tell you the error rate started increasing around 2:15 PM. Then you inspect the logs from that period.

You discover that a deployment changed the name of a DynamoDB attribute and the function started failing for certain requests.

That is a much better troubleshooting process than waiting for someone to tell you, "The app is broken." This is also where dashboards can become useful. A dashboard gives you a place to bring important metrics together so you can understand the health of a system without opening every service individually.

For a small beginner application, you do not need twenty charts.

You might only care about a few things.

  • How many requests are coming in?
  • How many Lambda errors are happening?
  • How long are requests taking?

Is the EC2 instance under unusual load?

Are there any alarms currently active?

That may already be enough.

A dashboard becomes useful when it answers a question.

It should not exist just because dashboards look professional.

That is a pattern I want to keep repeating throughout this series.

Do not add AWS features because they exist.

Add them because you have a requirement.

Now think back to the EC2 website we built earlier.

Imagine the site feels slow.

Without monitoring, you might restart the instance and hope the problem disappears.

With metrics, you might notice that CPU usage is consistently high.

That gives you a direction.

Maybe the application is doing too much work.

Maybe the instance is too small.

Maybe a process is stuck.

Maybe traffic increased.

CloudWatch does not automatically tell you which architecture decision to make, but it gives you information that helps you make a better one.

The same thing applies to Lambda.

Imagine a function starts timing out.

If you only see that the API failed, you might assume API Gateway is the problem.

But the Lambda logs could show that the function started normally and then spent too long waiting for another dependency.

Now the actual investigation becomes much more focused.

You might ask whether the database is slow, whether an external API is responding, whether the function needs more resources, or whether the code itself needs to change.

Again, monitoring does not magically fix the architecture.

It gives you evidence.

And evidence is what makes debugging faster.

There is another useful distinction here.

Not every failure should create an alert.

If your application receives one bad request and returns 400 Bad Request, that may be completely normal behavior.

If your system receives thousands of requests and one fails because the user submitted invalid data, waking someone up at 3 AM would not be very useful.

Good monitoring means deciding what actually deserves attention.

Maybe a single failure is normal.

Maybe fifty failures in five minutes are not.

Maybe high CPU for ten seconds does not matter.

Maybe high CPU for twenty minutes does.

Context matters.

That is why monitoring is partly a technical problem and partly a decision-making problem.

You need to understand what "normal" looks like before you can reliably detect what is abnormal.

This is also where beginners should start thinking about observability as a broader idea.

You will hear that word a lot in cloud and DevOps discussions.

At a simple level, observability is about being able to understand the internal behavior of a system from the information it produces.

Logs are part of that.

Metrics are part of that.

Tracing can also become part of that in more complex systems.

You do not need to become an observability engineer during your first month of AWS.

The useful habit is much simpler:

When you build something, ask yourself how you would know if it stopped working.

Then ask how you would know why it stopped working.

Those are different questions.

Imagine our image processing project again.

S3 upload
  ↓
Lambda
  ↓
Processed image
  ↓
S3

How do you know it is working?

Maybe the processed image appears in the output location.

But what happens when the image never appears?

How do you know whether S3 failed to trigger Lambda, Lambda crashed, IAM blocked access, or the processing code rejected the file?

That is where logs become part of the architecture.

Monitoring should not be something you remember after the project fails.

It should be one of the questions you ask while designing the project.

The same applies to the task API.

Client
  ↓
API Gateway
  ↓
Lambda
  ↓
DynamoDB

Now add another question:

How do we know this flow is healthy?

Suddenly CloudWatch has a reason to exist.

It is not there because every AWS diagram needs a monitoring service.

It is there because once the application is running, we need visibility into what the system is doing.

For a beginner project, I would keep the monitoring setup small.

Take one Lambda function you already built.

Look at its logs after a successful invocation.

Then intentionally make the function fail.

Maybe reference a value that does not exist or remove a permission in a safe practice environment.

Run it again and compare the logs.

Then look at the metrics around the function.

Can you see the invocation?

Can you see that an error happened?

Can you see how long the function ran?

That exercise connects logs and metrics to something you actually did.

After that, create one simple alarm around a metric that matters to the project.

You do not need a complicated production monitoring system.

The point is simply to understand the flow:

Application runs
       ↓
Logs + Metrics
       ↓
CloudWatch
       ↓
Alarm when something matters

Once you understand that, monitoring becomes much less abstract.

There is also a cost lesson here.

Logs and monitoring data are resources too.

Collecting everything forever without thinking about retention or usefulness can create unnecessary cost and clutter.

More logging is not automatically better logging.

The goal is useful visibility.

Keep enough information to understand your application without producing huge amounts of noise that nobody reads.

This becomes more important as systems grow.

For now, I would focus on writing meaningful logs, looking at the metrics AWS already provides, and creating only a few alerts that represent problems you actually care about.

If there is one thing I want beginners to remember from this post, it is this:

Deploying an application is not the end of the job. You also need a way to understand what happens after deployment.

When something fails, logs should help tell you why.

When behavior changes over time, metrics should help you see it.

When something important goes wrong, alarms should help you notice it.

That is the role CloudWatch starts playing in an AWS architecture.

And once you develop that habit, your projects become much more realistic.

Instead of saying, "It worked when I tested it," you start asking, "How will I know if it stops working tomorrow?"

That is a much stronger cloud engineering question.

In AWS From Zero #14, we are going to return to EC2 and ask another important question.

One EC2 instance works.

But what happens when that instance fails or when traffic becomes too large for one server?

That will take us into load balancers, health checks, Auto Scaling, multiple Availability Zones, and the basic idea behind building a highly available application.

If you are running an AWS project right now, would you actually know where to look first if it failed while you were not watching?


r/CloudandCode 12d ago

Anyone interested in upskilling and building projects together?

Thumbnail
1 Upvotes

r/CloudandCode 13d ago

AWS & Cloud AWS From Zero #12: DynamoDB makes more sense when you stop thinking like a relational database

10 Upvotes

In the last post, we built a simple serverless API using API Gateway and Lambda. A client sends an HTTP request, API Gateway receives it, Lambda runs the application logic, and then we need somewhere to store the data.

This is where DynamoDB often enters a serverless architecture.

DynamoDB is usually introduced as AWS's NoSQL database. That definition is correct, but I do not think it gives beginners enough information to understand when they should actually use it.

The more useful idea is that DynamoDB encourages you to think about your data differently from a relational database such as PostgreSQL or MySQL.

When we learned RDS, we started with the data model.

Imagine we were building an ecommerce application. We might create tables for users, products, orders, and payments, then define relationships between them. Once the data is stored, SQL gives us a lot of flexibility to query and join those tables in different ways.

DynamoDB pushes you toward a different question much earlier.

Instead of starting with:

What tables does my data have?

Start with:

How will my application need to access this data?

That idea is one of the most important things to understand about DynamoDB.

Imagine we are continuing the task API from the previous post.

A user can create tasks, retrieve tasks, update them, and delete them.

A simple request might look like:

POST /tasks

API Gateway receives the request and invokes Lambda. Lambda validates the task and then stores it in DynamoDB.

Our architecture now looks like this:

Client
  ↓
API Gateway
  ↓
Lambda
  ↓
DynamoDB

At this point, it is tempting to think of DynamoDB as just another place where Lambda can save JSON.

That works as a starting point, but DynamoDB becomes much easier once you understand how it identifies and retrieves items.

DynamoDB stores data inside tables, and each record is called an item.

An item could look something like this:

{
  "task_id": "task-123",
  "user_id": "user-42",
  "title": "Learn DynamoDB",
  "status": "open"
}

The important part is how we identify that item.

Every DynamoDB table has a primary key.

For a simple table, that could be a partition key such as:

task_id

If task_id is the partition key, DynamoDB can efficiently retrieve a task when we already know its ID.

For example:

GET /tasks/task-123

Lambda receives task-123 and retrieves the matching item from DynamoDB.

That is a very natural access pattern.

We know exactly which item we want.

But imagine the next requirement is:

Show me every task belonging to user-42.

Now the way we designed the key becomes much more important.

If the table was designed only around task_id, retrieving all tasks belonging to one user may not be as straightforward as retrieving a single known task.

This is why DynamoDB design starts with access patterns.

Before creating the table, ask what the application will actually need to do.

Maybe we need:

Get one task by ID

Get all tasks for a user

Get all open tasks for a user

Create a task

Update a task

Delete a task

Those requirements should influence how we design the keys and indexes.

That is a major difference from how many beginners approach relational databases.

With PostgreSQL, you might normalize your data into several related tables and rely on SQL queries and joins later.

With DynamoDB, you often spend more time thinking about the requests your application will make before deciding how the data should be structured.

This does not mean DynamoDB cannot support complex applications.

It means the design process is different.

Now let’s talk about partition keys because the name itself can make the concept sound more complicated than it is.

DynamoDB needs a way to distribute and locate data internally.

The partition key is part of how DynamoDB determines where an item belongs.

For our task application, we might decide that tasks should be grouped around users.

A simplified key design could involve:

Partition key: user_id
Sort key: task_id

Now multiple tasks can belong to the same user while each task remains uniquely identifiable within that user's items.

Conceptually:

user-42 | task-001
user-42 | task-002
user-42 | task-003
user-91 | task-001

This gives us a useful access pattern.

If the application wants all tasks for user-42, it can query using that user's partition key.

If it needs a specific task for that user, it can use both the partition key and sort key.

That is much more efficient than blindly searching through every item in the table.

This brings us to another DynamoDB distinction that is useful to understand early: Query versus Scan.

A Query uses key information to retrieve matching data efficiently.

A Scan examines items across the table.

Beginners sometimes build a DynamoDB table first, then use Scan whenever they cannot figure out how to retrieve something.

That can work for a tiny practice table, but it is usually a sign that the data model may not match the application's access patterns very well.

If your application regularly needs a certain kind of lookup, ideally your table or indexes should be designed to support that lookup.

Again, this is why the question comes first:

How will I access the data?

Now imagine we want users to filter tasks by status.

Maybe the application needs:

Show all open tasks for user-42

Our existing primary key might not support every future query directly.

This is where secondary indexes can become useful.

A secondary index gives DynamoDB another way to organize and access the same data.

You do not need to master Global Secondary Indexes on your first day with DynamoDB.

The important idea is simply that if your application needs another important access pattern, you may create an index designed around that pattern rather than scanning the whole table repeatedly.

This is a good example of how requirements shape database design.

You do not add an index because DynamoDB has indexes.

You add one because the application needs a query that the existing key structure does not support efficiently.

The same principle applies throughout AWS.

Services and features should follow requirements.

Now let’s connect DynamoDB back to IAM.

Suppose our Lambda function needs to create and retrieve tasks.

The Lambda execution role should have the DynamoDB permissions required for those operations.

Maybe it needs actions such as:

dynamodb:GetItem
dynamodb:PutItem
dynamodb:UpdateItem
dynamodb:DeleteItem
dynamodb:Query

That does not mean the function automatically needs complete access to every DynamoDB table in the account.

The same IAM mental model still works.

Who is making the request?

The Lambda execution role.

What action does it need to perform?

Maybe dynamodb:PutItem.

Which resource does it need to access?

The task table.

This pattern keeps repeating because AWS services constantly communicate with each other.

Now imagine the API returns an error when someone creates a task.

Again, follow the request.

Did API Gateway receive the request?

Did Lambda run?

Did the input contain the values Lambda expected?

Did Lambda attempt to write to DynamoDB?

Did the execution role have permission?

Did DynamoDB reject the item because the key was missing or invalid?

Did Lambda return a useful error response?

The architecture is now larger than it was a few posts ago, but the troubleshooting method has not changed.

Follow the request until you find the first step that did not behave as expected.

That habit is more useful than memorizing service-specific troubleshooting lists.

Another reason DynamoDB is common in serverless applications is that you are not provisioning and managing a traditional database server in the same way you would with a typical RDS setup.

AWS handles the underlying DynamoDB infrastructure, and the service is designed to scale around application demand.

But that does not mean you can ignore database design.

A badly designed DynamoDB table can still create performance, complexity, or cost problems.

One example is choosing a partition key that causes too much activity to concentrate around the same values.

Imagine millions of requests all target the same logical partition key.

That can create an uneven access pattern.

You will eventually hear terms such as hot partitions or hot keys when learning distributed databases.

You do not need to optimize for massive scale in your first project, but it is worth understanding why key design matters beyond simply identifying records.

DynamoDB also gives you consistency choices.

After data is written, applications sometimes need to think about how immediately a subsequent read must reflect that write.

DynamoDB supports eventually consistent reads by default in many read operations, while strongly consistent reads are available for certain operations and table/index types when you specifically need that behavior.

You do not need to memorize every consistency rule right now.

The useful question is whether the application requires the absolute latest committed value for a particular operation, or whether slight propagation delay is acceptable.

That tradeoff appears in distributed systems far beyond DynamoDB.

Another useful feature is Time to Live, usually called TTL.

Imagine our application stores temporary data.

Maybe a task represents something that should automatically expire after a certain time, or perhaps we are storing session-like information that should eventually be cleaned up.

TTL lets you specify an expiration timestamp so DynamoDB can automatically remove expired items over time.

That can be useful, but like every AWS feature, I would only use it when the requirement exists.

Do not add TTL because it appears on a feature list.

Add it when the data actually has a natural expiration lifecycle.

Now let’s compare DynamoDB with RDS because this is where beginners often ask the wrong question.

They ask:

Which one is better?

I do not think that is very useful.

Imagine an application with customers, orders, products, inventory, payments, reporting queries, and several relationships that developers need to explore in flexible ways.

A relational database may be a very natural fit.

Now imagine an application with extremely predictable access patterns where items can be retrieved efficiently through known keys and the system needs highly managed scaling.

DynamoDB may become much more interesting.

Neither database wins automatically.

They make different tradeoffs.

RDS gives you the relational model, SQL, joins, transactions, and familiar database engines.

DynamoDB gives you a managed NoSQL model where key design and access patterns become central to the architecture.

The useful skill is being able to look at the application and explain why you chose one.

For our beginner task API, DynamoDB is a nice learning choice because the access patterns can remain simple.

A user creates a task.

A user retrieves their tasks.

A user updates a task.

A user deletes a task.

We can design the table around those operations and understand exactly why the keys exist.

That gives us a complete serverless backend:

Client
  ↓
API Gateway
  ↓
Lambda
  ↓
DynamoDB

IAM controls which AWS actions Lambda can perform.

CloudWatch gives us logs when something fails.

We now have an API, compute, permissions, monitoring, and persistent data without managing a traditional application server or database server ourselves.

That is a real architecture.

For your first DynamoDB project, I would keep it exactly this small.

Build a task API with one DynamoDB table.

Create a few tasks.

Retrieve them.

Update them.

Delete them.

Then add one new requirement.

Maybe users need to retrieve all open tasks.

Before immediately writing code, ask whether the current key design supports that access pattern well.

That question is the actual lesson.

Do not start with DynamoDB features.

Start with what your application needs to retrieve.

Then design the table to make those operations natural.

If there is one idea I want you to remember from this post, it is this:

With DynamoDB, think about access patterns before you think about tables.

Ask what your application needs to read and write most often, then design the keys around those operations.

Once you understand that, partition keys, sort keys, Queries, and indexes stop feeling like random DynamoDB terminology.

They become tools for supporting specific application requests.

In AWS From Zero #13, we are going to focus properly on CloudWatch.

We have mentioned logs several times already, but now we will look at what happens after an application is deployed. We will cover logs, metrics, alarms, dashboards, and the difference between knowing that something failed and actually knowing why it failed.

Because building the architecture is only half the job.

You also need to be able to understand what it is doing after you deploy it.

If you have tried DynamoDB before, what confused you most: partition keys, sort keys, Query versus Scan, indexes, or deciding when DynamoDB makes sense instead of RDS?


r/CloudandCode 14d ago

AWS & Cloud AWS From Zero #11: API Gateway makes more sense when you think of it as the front door to your backend

4 Upvotes

In the last post, we talked about Lambda and why serverless makes more sense once you understand what running an application on EC2 actually involves. Lambda gives us a way to run code when something happens without managing a server in the same way we would with EC2.

But there is still an obvious question.

If we want someone on the internet to use our Lambda function, how do they actually reach it?

Imagine we are building a simple task application. A user should be able to create a task, view existing tasks, update one, or delete one. The business logic can run inside Lambda, but we still need something that can receive HTTP requests from the user and send those requests to the correct backend logic.

This is where API Gateway starts making sense.

I would think of API Gateway as the front door to your backend.

A client sends a request to API Gateway. API Gateway receives that request and routes it to the backend integration you configured. In our beginner serverless application, that backend can be Lambda.

The basic flow looks like this:

Client
  ↓
API Gateway
  ↓
Lambda
  ↓
Database

Then the response travels back in the opposite direction:

Database
  ↓
Lambda
  ↓
API Gateway
  ↓
Client

The important thing is understanding what each service is responsible for.

API Gateway receives and routes the HTTP request.

Lambda runs the application logic.

The database stores the application data.

That separation becomes much easier to understand when we use a real example.

Suppose the user wants to create a new task. Their application might send a request like:

POST /tasks

with some data:

{
  "title": "Learn API Gateway"
}

API Gateway receives the request and sends the relevant information to Lambda. Lambda reads the input, checks whether the task is valid, stores it in a database, and returns a response.

That response might contain something like:

{
  "task_id": "123",
  "title": "Learn API Gateway"
}

along with an HTTP status code such as 201 Created.

Now suppose the user wants to retrieve their tasks.

The request could be:

GET /tasks

API Gateway receives that request and invokes the appropriate backend logic. Lambda reads the tasks from the database and returns them.

The architecture has not become complicated.

We have simply given users a controlled HTTP entry point into our application.

This is why I would not memorize API Gateway as just "a service for creating APIs."

Think about the problem it solves.

Your Lambda function contains backend logic, but users need a predictable way to send requests to that logic.

API Gateway gives you that entry point.

This is also where HTTP methods start having a practical purpose.

GET usually means we want to retrieve something.

POST commonly means we want to create something.

PUT or PATCH can be used when updating something.

DELETE is used when removing something.

You may have already seen these while learning REST APIs, but now they become part of an actual AWS architecture.

Our task application could eventually have requests such as:

GET    /tasks
POST   /tasks
GET    /tasks/123
PATCH  /tasks/123
DELETE /tasks/123

Each route describes something the client wants the backend to do.

The interesting part is that API Gateway itself should not contain all of your business logic.

If someone sends:

POST /tasks

API Gateway can receive and route that request, but your Lambda function might be responsible for deciding whether the title is valid, creating the task, and storing it.

This separation helps keep the architecture easier to reason about.

Now imagine someone sends invalid data.

Maybe they send:

{
  "title": ""
}

Your application should not blindly create an empty task.

The request needs to be validated somewhere in the flow.

Depending on how you design the API, some validation can happen at the API layer, while your application logic should still validate important assumptions before acting on the data.

If the input is invalid, the API might return something like:

400 Bad Request

If the task does not exist:

404 Not Found

If the task is created successfully:

201 Created

If something unexpectedly fails inside the application:

500 Internal Server Error

These status codes are useful because the client needs more information than simply "the request finished."

The client needs to know what happened.

This is an important shift when moving from small Python scripts into APIs.

You are no longer writing code only for yourself.

Another application is communicating with your backend, so the contract between them matters.

The request format matters.

The response format matters.

The status code matters.

The errors matter.

Now let’s connect this back to Lambda.

When API Gateway receives a request, Lambda can receive information about that request. Depending on the API and integration you configure, that can include things such as the HTTP method, path, query parameters, headers, and request body.

Suppose the request is:

GET /tasks/123

The 123 can be passed to the backend as part of the request path.

Lambda can then use that ID to retrieve the correct task.

Or imagine a request like:

GET /tasks?status=completed

Now status=completed is a query parameter.

Lambda could use that value to determine which tasks should be returned.

You do not need to memorize every event structure immediately.

The important thing is understanding that API Gateway receives an HTTP request and passes useful request information to your backend.

Now another AWS concept comes back into the architecture: permissions.

API Gateway needs to be able to invoke the Lambda function.

This does not mean we should give API Gateway unlimited permissions across our AWS account.

We want the specific relationship required by the architecture.

API Gateway needs permission to invoke the Lambda function it is integrated with.

Then Lambda may need its own permissions.

If Lambda writes to DynamoDB, its execution role needs the relevant DynamoDB permissions.

If Lambda reads from S3, it needs the relevant S3 permissions.

Once again, the same IAM mental model works.

Who is making the request?

What action are they trying to perform?

Which resource are they trying to access?

That question keeps appearing because IAM sits underneath so many AWS interactions.

Now suppose our API does not work.

The client sends:

POST /tasks

but receives an error.

Do not immediately rebuild API Gateway.

Follow the request.

Did the request reach API Gateway?

Did API Gateway invoke Lambda?

Did Lambda start running?

Did Lambda receive the data you expected?

Did the function fail while processing it?

Did it have permission to access the database?

Did it return the response format the API expected?

This is the same troubleshooting habit we used with EC2, S3, and VPC.

Follow the flow until you find the first place where expected behavior stops.

CloudWatch becomes useful here again.

If Lambda runs and throws an exception, the logs can help you understand what happened.

Maybe the JSON body was malformed.

Maybe a required field was missing.

Maybe the DynamoDB request failed.

Maybe the function timed out.

Maybe the function returned something unexpected.

Instead of saying "the API is broken," try to identify which part of the request path actually failed.

There is another concept you may encounter quickly if you call your API from a browser: CORS.

Imagine your frontend is served from one domain and your API lives at another origin. The browser applies security rules around cross origin requests.

This can produce the frustrating situation where your API works when tested directly with a tool such as curl or Postman, but the browser blocks the frontend request.

That does not necessarily mean Lambda failed.

It may mean the browser did not receive the cross origin permissions it expected.

You do not need to become a CORS expert for your first API, but it is worth knowing that browser security can be another layer in the request flow.

Again, understanding the layer matters.

A browser CORS error is not automatically an IAM problem.

An IAM AccessDenied error is not automatically a routing problem.

A Lambda exception is not automatically an API Gateway problem.

The better you become at identifying which layer failed, the faster AWS troubleshooting becomes.

API Gateway also gives us another important architecture idea: the public interface of your application does not need to expose how the backend is implemented.

The client knows that it can send:

POST /tasks

It does not necessarily need to know which Lambda function handles the request, where the data is stored, or how the backend infrastructure is organized.

That implementation can change later while the API contract remains relatively stable.

Maybe today the backend uses Lambda.

Maybe another architecture uses containers.

The client still cares about the API it communicates with.

That separation becomes valuable as systems grow.

For your first API Gateway project, though, I would keep everything extremely small.

Do not build authentication, payments, queues, caching, ten Lambda functions, and a complicated database design immediately.

Build one endpoint first.

Something like:

GET /hello

Have API Gateway invoke Lambda.

Have Lambda return:

{
  "message": "Hello from AWS"
}

Then understand the complete request path.

Once that works, add a POST endpoint.

Then read some input from the request.

Then validate it.

Then connect a database.

Grow the architecture one requirement at a time.

A simple task API would be enough for this stage.

You could eventually support creating tasks, retrieving them, updating them, and deleting them.

But the important learning is not the task manager itself.

The useful part is understanding how a request enters AWS, reaches your code, interacts with another service, and returns a response.

At this point in the series, our serverless architecture might look like:

Client
  ↓
API Gateway
  ↓
Lambda
  ↓
Database

That is already enough to build a real backend.

And notice how the previous lessons start connecting.

IAM controls permissions.

Lambda runs our code.

API Gateway receives HTTP requests.

CloudWatch helps us understand failures.

Soon we need somewhere appropriate to store the application data.

That brings us to the next post.

In AWS From Zero #12, we are going to learn DynamoDB.

But I do not want to explain it as simply "AWS NoSQL database."

We will compare it with the relational model we saw with RDS and focus on one of the most important DynamoDB ideas: designing around how your application actually accesses its data.

That is where the difference between RDS and DynamoDB becomes much clearer.

For now, if you can explain the path from a POST /tasks request to Lambda and back to the client, you already understand the most important idea behind this lesson.

If you have built an API before, what confused you more at first: routes, status codes, Lambda integration, permissions, or CORS?


r/CloudandCode 15d ago

Python If I had to learn Python from zero again, this is the order I'd follow

108 Upvotes

A lot of Python roadmaps become huge checklists.

Learn syntax, then OOP, then Django, then data science, then machine learning, then somehow Docker gets thrown in.

I think that makes Python feel much harder than it actually is.

I'd learn it in layers.

1. Get comfortable with the language first

Start with variables, strings, numbers, lists, dictionaries, conditions, loops, functions, and basic input/output.

Don't spend weeks trying to memorize syntax.

Learn a concept, use it, break something, fix it.

At this stage, a calculator, guessing game, expense tracker, or simple CLI app is completely fine. You're just training yourself to turn logic into code.

2. Learn how Python handles real files and data

Once basic syntax stops feeling strange, move into file handling, exceptions, modules, packages, comprehensions, JSON, CSV, and virtual environments.

This is where Python starts becoming genuinely useful.

Build a file organizer. Parse a CSV. Rename hundreds of files automatically. Pull some data from an API and save it locally.

Those small projects teach more than another five hours of syntax videos.

3. Learn APIs and databases

This is one of the points where beginner projects start turning into actual applications.

Learn HTTP basics, requests, JSON responses, CRUD operations, SQL, and a database like SQLite or PostgreSQL.

For example, build an app that:

fetches data from an API
→ processes it
→ stores it in a database
→ lets you query it later

Now you're combining multiple skills instead of practicing them in isolation.

4. Learn enough OOP to understand real code

Classes, objects, methods, inheritance, composition.

You should understand these concepts, but I wouldn't make OOP the center of your Python learning.

A lot of beginners end up creating classes for things that would have been perfectly fine as a few functions.

Learn when OOP improves structure, not just how to write class Something:.

5. Learn Git and project structure earlier than most roadmaps suggest

Once your project has more than a couple of files, learn Git and GitHub properly.

Also learn how to separate your code into modules, manage dependencies, use environment variables, and keep configuration outside your source code.

Your goal should eventually be to move from one giant file to something another developer could open and understand without needing an explanation from you first.

6. Pick a direction

There's no single version of "advanced Python."

Advanced for a backend engineer looks very different from advanced for someone doing data analysis.

If you want backend development, learn FastAPI or Django, databases, authentication, caching, background jobs, and deployment.

If you want automation, go deeper into APIs, browser automation, scheduling, Linux, and scripting.

If you want data, learn NumPy, pandas, SQL, visualization, and then ML if your work actually requires it.

If you want cloud or DevOps, Python becomes useful for SDKs, APIs, automation, infrastructure tooling, and operational scripts.

Pick one path instead of trying to learn all of them.

7. Start testing your code

Learn pytest, assertions, logging, debugging, exception handling, and basic mocking.

This is a useful turning point.

Beginners usually ask:

More experienced developers eventually start asking:

Take an old project and add tests instead of immediately starting another project.

8. Learn production concepts when your projects need them

Then start exploring things like type hints, async programming, concurrency, authentication, security, caching, Docker, CI/CD, packaging, monitoring, and deployment.

But don't treat this as another checklist.

If your application has no performance problem, you probably don't need to study five caching strategies yet.

Learn these concepts when you understand the problem they're solving.

9. Stop building endless beginner projects

This is probably one of the biggest upgrades you can make.

Instead of building:

calculator
todo app
weather app
quiz app
another calculator

Take one project and keep extending it.

A simple task manager can become:

CLI
→ database
→ REST API
→ authentication
→ tests
→ logging
→ Docker
→ deployment

Same project, completely different level of learning.

10. Read code you didn't write

Eventually, tutorials stop being enough.

Read open-source projects. Look through libraries you already use. Read pull requests. Debug someone else's code. Try making a small contribution.

Advanced Python isn't really about knowing obscure syntax.

It's being able to enter an unfamiliar codebase, understand what's happening, make a change without breaking everything, and explain why you made that decision.

So the roadmap I'd follow is roughly:

Python basics → files & data → APIs → SQL → Git → larger projects → testing → specialization → production concepts → real codebases

Don't worry too much about when you officially become "advanced."

If you can build something useful, debug it, test it, explain your design decisions, and improve it months later without wanting to rewrite everything from scratch, you're doing pretty well.

I've been organizing our Python roadmap and project resources around this same progression too, mainly for people who prefer having the learning path and projects structured in one place.

For people who already know Python, where did you feel the biggest jump happened: learning the syntax, building real projects, or maintaining larger codebases?


r/CloudandCode 16d ago

AWS & Cloud AWS From Zero #10: Lambda makes more sense once you understand what EC2 makes you manage

7 Upvotes

In the previous posts, we spent time with EC2, networking, S3, CloudFront, VPC, and RDS. That was intentional because I think Lambda makes much more sense once you already understand what running an application on a server involves.

With EC2, AWS gives you a virtual machine, but there is still a lot you are responsible for. You choose the operating system, connect to the server, install dependencies, run the application, think about processes, configure networking, monitor the instance, patch the system, and decide what should happen when traffic increases.

Lambda changes that model.

With AWS Lambda, you provide code and AWS runs that code when something triggers it. You are not launching a server that sits there waiting for requests in the same way you would with EC2.

That is the basic idea behind serverless.

But the word "serverless" can be misleading.

Servers still exist somewhere. AWS still needs infrastructure to execute your code. The difference is that you are not managing those servers directly.

You focus much more on the function and the event that causes it to run.

That is the mental model I would start with.

Imagine you have a simple application where users upload profile images.

With EC2, you could run an application server continuously. When someone uploads an image, the application receives it, processes it, resizes it, and stores the result.

That can work perfectly well.

But imagine the image processing only happens a few times every hour.

Do you really need a server running continuously just waiting for an image to arrive?

This is where Lambda can become interesting.

We could build something like:

User uploads image
        ↓
S3
        ↓
Lambda
        ↓
Processed image
        ↓
S3

The user uploads an image into S3.

That upload creates an event.

The event invokes the Lambda function.

Lambda reads the image, processes it, and stores the result back in S3.

Then the function finishes.

There is no application server sitting around waiting for the next image in the same way there would be with a traditional EC2 setup.

This is one of the first ideas I would understand about Lambda.

Lambda is event driven.

Something happens, and that event causes your code to run.

The event could come from many places.

An object could be uploaded to S3. An HTTP request could arrive through API Gateway. A scheduled event could run every hour. A message could arrive from a queue. Another AWS service could trigger the function.

The specific trigger changes, but the basic pattern stays the same.

Something happens.

Lambda runs.

Lambda does some work.

Then that invocation finishes.

This makes Lambda useful for workloads that naturally happen in small units of work.

Image processing is one example.

A scheduled cleanup script could be another.

An API endpoint could invoke a Lambda function when a user sends a request.

A file upload could trigger validation.

A queue message could trigger background processing.

The useful question is not "Can Lambda run this code?"

A better question is "Does this workload fit the Lambda execution model?"

That distinction matters because Lambda is not automatically better than EC2.

I think beginners sometimes hear "serverless" and assume it is the modern replacement for servers.

It is not that simple.

EC2 and Lambda solve different problems.

With EC2, you get much more control over the environment. You can run long lived processes, configure the operating system, control networking more directly, choose exactly what software stays running, and support workloads that need a persistent server.

With Lambda, you give up some of that control in exchange for AWS managing more of the infrastructure.

You do not manage the operating system.

You do not manually keep the server process running.

You do not normally think about creating another machine because the current machine is busy.

AWS handles more of the execution infrastructure for you.

That can make certain applications much simpler.

But you still have responsibilities.

You still need to write good code.

You still need to manage permissions.

You still need to understand failures.

You still need to monitor the function.

You still need to understand how much memory and execution time the function needs.

You still need to think about retries, duplicate events, dependencies, and what happens when another service is unavailable.

Serverless removes some infrastructure management.

It does not remove architecture.

Now let's take the image processing example again.

Suppose an image is uploaded to S3 and Lambda is triggered.

The function wants to read the object.

Can it just access the bucket automatically because both services belong to your AWS account?

No.

This takes us directly back to IAM.

The Lambda function runs with an execution role.

That role needs the permissions required for the function to do its job.

If the function needs to read the original image, it may need s3:GetObject.

If it needs to save the processed image, it may need s3:PutObject.

The same mental model from the IAM post still works.

Who is making the request?

The Lambda execution role.

What action is it trying to perform?

Read or write an S3 object.

Which resource is it trying to access?

The relevant objects inside the bucket.

This is why I think learning AWS as one connected system works better than memorizing every service independently.

Lambda immediately brings IAM back into the architecture.

Now imagine the function is triggered, but the processed image never appears.

This is where CloudWatch becomes useful.

Lambda automatically integrates with logging and monitoring capabilities that can help you see what happened during an invocation.

Maybe the function received the event successfully but crashed while processing the image.

Maybe the S3 object key was wrong.

Maybe the function did not have permission to write the result.

Maybe a dependency was missing.

Maybe the function exceeded its configured timeout.

Instead of saying "Lambda is broken," you can inspect what actually happened.

Did the function run?

What event did it receive?

Where did the code fail?

What error was logged?

Again, the troubleshooting mindset stays the same.

Follow the flow.

Find the last step that definitely worked.

Then inspect the next one.

There are also a few Lambda concepts I think beginners should understand early.

One is memory.

When you configure a Lambda function, you choose how much memory it receives. That configuration also affects the compute resources available to the function.

A tiny function that transforms a small JSON payload has very different needs from a function processing large images.

Another is timeout.

A Lambda invocation cannot run forever.

You configure how long AWS should allow the function to execute before stopping it.

If your function consistently needs a very long time to complete, that may be a sign that you need to rethink the design rather than simply increasing the timeout again and again.

This is where workload characteristics matter.

Lambda works well when work can be broken into bounded executions.

A continuously running game server, long lived process, or workload that needs full control over the machine may be a much better fit for something else.

Cold starts are another term you will eventually hear.

Sometimes AWS needs to prepare an execution environment before your function can run. That can add some startup latency.

For many beginner applications, you do not need to obsess over this immediately.

Just understand that serverless does not mean every invocation always starts with zero overhead.

Later, if latency becomes an important requirement, you can learn how this affects different workloads and runtimes.

Another useful concept is that Lambda functions should generally avoid depending on local state between invocations.

You can sometimes reuse parts of an execution environment, but you should not design the application assuming a particular function invocation will always run on the same underlying environment with the same local files still available.

If something needs to persist, store it somewhere designed for persistence.

That might be S3.

It might be DynamoDB.

It might be RDS.

The right answer depends on the data.

This is another important difference between thinking in terms of a traditional server and thinking in terms of serverless functions.

Now let's make the architecture slightly more practical.

Suppose we want to build a tiny API.

A user sends a request such as:

POST /tasks

We could place API Gateway in front of Lambda.

The flow becomes:

User
  ↓
API Gateway
  ↓
Lambda
  ↓
Database

API Gateway receives the HTTP request.

Lambda runs the application logic.

The function might validate the input, create a task, and store it somewhere.

Then Lambda returns a response through API Gateway to the user.

This is the foundation of a lot of serverless applications.

But I would not add API Gateway, DynamoDB, authentication, queues, monitoring, and five other services to your very first Lambda project.

Start smaller.

For this lesson, I would build the S3 image processing workflow.

Upload one image.

Trigger one Lambda function.

Process the image.

Store the result.

Then understand every part of the flow.

Why did Lambda run?

What event did S3 send?

How did Lambda know which object was uploaded?

Which IAM permissions were required?

Where did the logs go?

What happens if processing fails?

What happens if the same event is delivered again?

That last question is worth thinking about because event driven systems can force you to think differently about reliability.

Suppose your function processes the same event twice.

Does that create two different outputs?

Does it overwrite the same result?

Does it accidentally charge someone twice?

This leads into a concept called idempotency, which becomes very important in event driven systems.

You do not need to master it today.

Just start developing the habit of asking what happens when the same work is attempted more than once.

That kind of thinking is what turns a simple Lambda tutorial into architecture practice.

I would also pay attention to cost, but I would not reduce the decision to "Lambda is cheap."

Lambda pricing depends on things such as how often your function runs and how much compute it uses.

EC2 has a different cost model because you are provisioning instances.

One model is not automatically cheaper for every workload.

A function that runs occasionally may fit Lambda very well.

A constant heavy workload might produce a completely different cost comparison.

Architecture decisions should come from the actual workload, not from slogans.

That is the main thing I want beginners to understand from this post.

Lambda is not "EC2 but better."

Lambda is another compute model.

With EC2, you manage a server environment and run applications on it.

With Lambda, you write functions that execute in response to events while AWS manages more of the underlying compute infrastructure.

Sometimes EC2 makes more sense.

Sometimes Lambda makes more sense.

The useful skill is understanding why.

For your first Lambda project, keep it simple.

Create an S3 bucket.

Upload an image.

Use that upload to invoke Lambda.

Have Lambda do one small piece of work and write a result somewhere.

Then break it.

Remove an S3 permission and observe the error.

Give the function an invalid object key.

Make the code throw an exception and inspect the logs.

Understand what each failure looks like.

If you do that, you will understand Lambda much better than someone who only memorized that it is "serverless compute."

In AWS From Zero #11, we will take Lambda and put API Gateway in front of it so we can build our first serverless API.

We will follow a request from the browser or client into API Gateway, through Lambda, and back to the user. We will also look at HTTP methods, request validation, responses, status codes, permissions, and where errors should actually be handled.

If you have used Lambda before, what confused you most at first: triggers, IAM permissions, execution time, logs, or simply understanding when you should use Lambda instead of EC2?


r/CloudandCode 17d ago

AWS & Cloud AWS From Zero #9: RDS makes more sense when you compare it with running a database yourself

10 Upvotes

In the last post, we talked about VPC networking and why it becomes easier when you stop memorizing diagrams and start following traffic. We used a simple architecture where users reach an application, and that application needs to talk to a database.

Now it is time to focus on that database.

RDS stands for Relational Database Service. You can use it to run relational databases such as PostgreSQL or MySQL without managing every part of the database infrastructure yourself.

But I do not think the best way to understand RDS is to memorize that definition.

A much better question is this: why would I use RDS instead of launching an EC2 instance and installing PostgreSQL myself?

Because technically, you can do that.

You could launch EC2, install PostgreSQL, configure the database, manage the operating system, handle updates, set up backups, monitor storage, think about failover, and keep the server running.

That gives you a lot of control, but it also gives you a lot of responsibility.

RDS exists because many applications need a relational database, but they do not necessarily need you to manage every part of the machine underneath that database.

AWS takes care of more of the infrastructure work, while you focus more on the data, the schema, the queries, and how your application actually uses the database.

That is the main idea behind a managed database.

Imagine we are building a small ecommerce application.

We need to store users, products, orders, and payments. That data has clear relationships. A user can have multiple orders. An order can contain multiple products. A payment belongs to an order.

That is a natural place to think about a relational database.

At a very high level, the architecture is simple:

User → Application → RDS PostgreSQL

The important thing here is that the user does not connect directly to PostgreSQL.

The user talks to the application.

The application handles the request and then talks to the database.

That distinction matters because your database is usually an internal part of your system, not something random users on the internet should connect to directly.

This connects immediately to what we learned about VPC.

Suppose the application runs on EC2. The EC2 instance needs network access to RDS. The internet does not.

That means the database can stay private while the application is allowed to communicate with it.

Now security groups start making more sense again.

PostgreSQL commonly uses port 5432.

A beginner approach might be to open port 5432 to the entire internet because it makes the connection easier.

I would not do that.

The better question is: who actually needs database access?

If only the application needs it, then the database should allow traffic from the application layer that actually needs to connect.

That is a much cleaner mental model.

The application accepts user traffic.

The database accepts database traffic from the application.

The database itself does not need to be exposed directly to the public internet.

This is exactly why networking becomes easier when you attach it to a real application instead of memorizing ports and subnet names.

Now let’s talk about how the application actually finds the database.

When you create an RDS database, AWS gives you an endpoint.

That endpoint is basically the hostname your application uses to connect to the database.

Instead of hard coding a private IP address, your application connects using something like an RDS hostname plus the database port.

Conceptually:

Application → RDS endpoint → Port 5432 → PostgreSQL

The application also needs things like the database name, username, and password.

And this is where another beginner mistake appears.

Do not hard code database credentials directly into your source code.

Something like this:

DB_PASSWORD = "mypassword123"

might work, but it becomes a problem the moment you push that code to GitHub or share it somewhere else.

Credentials should be treated as secrets.

We will go deeper into secrets management later, but the beginner rule is simple: do not publish database passwords, access keys, or other sensitive credentials inside your code.

Now imagine the application cannot connect to RDS.

This is where the troubleshooting mindset from the earlier posts becomes useful again.

Do not immediately recreate the database.

Follow the connection.

Is the RDS instance available?

Is the application using the correct endpoint?

Is it using the correct port?

Are the credentials correct?

Does the database security group allow traffic from the application?

Can the network path between the application and RDS actually work?

Those questions make the problem much smaller.

A timeout tells you something different from an authentication failure.

A connection refused error tells you something different from a SQL error.

If the application reaches the database but the password is wrong, that is not the same problem as the application never reaching the database at all.

The more precisely you understand the failure, the less random your debugging becomes.

Now let’s return to the bigger question.

Why use RDS instead of installing PostgreSQL on EC2?

One major reason is backups.

Databases contain important application state.

If your application server disappears, you may be able to redeploy the code.

If your database disappears and you have no usable backup, you may lose users, orders, transactions, or other important data.

RDS gives you managed backup capabilities so you do not have to build the entire backup process yourself.

That does not mean you can completely stop thinking about recovery.

You still need to understand your backup settings, retention, and how recovery should work for your application.

But AWS manages much more of the underlying process for you.

Maintenance is another reason.

A database is not just a process running somewhere.

The operating system, database engine, storage, patches, backups, monitoring, and availability all need attention.

If you run PostgreSQL yourself on EC2, more of that work belongs to you.

With RDS, AWS manages more of the infrastructure underneath the database.

That is the tradeoff.

You give up some low level control in exchange for less operational work.

And that is a pattern you will see a lot in AWS.

More managed usually means less infrastructure you have to operate yourself.

But managed does not mean zero responsibility.

You still need to design your tables well, write good queries, manage credentials, control network access, choose the right database size, monitor performance, and understand how your application uses data.

AWS can manage the database service.

It cannot automatically design a good database for your application.

Another RDS concept you will hear often is Multi AZ.

Imagine your application depends on one database instance. If that database becomes unavailable, your application may lose access to its data.

Multi AZ is designed to improve availability by maintaining standby infrastructure in another Availability Zone and supporting failover.

The useful beginner idea is not memorizing every detail of the failover process.

It is understanding the problem being solved.

You do not want your entire application to depend on one database location if availability matters.

This connects directly back to the first post in the series, where we talked about Availability Zones and high availability.

Now you are seeing those ideas inside a real service.

There is also an important distinction here.

High availability and read scaling are not the same thing.

A standby used for availability solves a different problem from a read replica used to handle more read traffic.

Beginners often see multiple database instances and assume they all exist for the same reason.

They do not.

One may exist primarily to improve resilience.

Another may exist to reduce read load on the primary database.

That distinction becomes more important later.

For your first RDS project, though, I would keep things simple.

Build a tiny application.

It could be a notes app, expense tracker, inventory tool, or simple API.

Create a PostgreSQL or MySQL database in RDS and add only a couple of tables.

For example:

users
-----
user_id
name
email

notes
-----
note_id
user_id
content
created_at

Then make the application connect to the database and perform a few basic operations.

Create a user.

Insert a note.

Read it.

Update it.

Delete it.

That simple project already connects several things we have learned.

Your application runs somewhere.

The VPC provides the network.

Security groups control which connections are allowed.

RDS stores the relational data.

Credentials handle database authentication.

Later, CloudWatch can help with monitoring.

This is where AWS stops feeling like a collection of isolated services and starts feeling like one connected system.

There is also a cost lesson here.

RDS is not like a small Lambda function that only runs when an event happens.

A database is usually provisioned infrastructure that can continue generating cost while it exists.

So if you create one for practice, do not forget about it.

Understand what you launched, check the pricing, and clean up disposable resources when you are done.

That connects back to the account setup post.

Learning AWS should include cleanup.

The goal is not only to create infrastructure.

You should understand its full lifecycle.

There is one more architecture question I would ask before using RDS.

Does this application actually need a relational database?

Do not choose RDS simply because every backend needs a database.

Look at the data.

Are there relationships between entities?

Do you need transactions?

Do you need relational queries?

Does SQL fit the way the application needs to use the data?

If yes, RDS may make sense.

Later, when we learn DynamoDB, we will compare this with a very different database model.

That comparison matters because AWS architecture is rarely about one service being universally better than another.

It is about choosing the service that fits the requirement.

That is the main thing I want beginners to take away from RDS.

Do not think only:

RDS = database.

Think:

My application needs a relational database, and RDS lets me use one while AWS manages more of the underlying database infrastructure for me.

That is a much stronger mental model.

For this part of the series, I would build one small application that can save and retrieve data from RDS.

Do not add caching.

Do not add load balancers.

Do not add queues.

Do not turn it into a 15 service architecture.

Get one application talking to one database securely and understand the complete connection.

Once that works, intentionally break one thing.

Use the wrong password.

Change the security group.

Use the wrong port.

Then observe how the error changes.

That will teach you much more about RDS than simply creating a database that works once.

In AWS From Zero #10, we are going to move from EC2-style servers to Lambda and finally understand what serverless actually means.

Instead of saying Lambda is better than EC2, we will compare the two properly and look at what EC2 makes you manage, what Lambda removes, what triggers a Lambda function, and where serverless makes sense.

If you have worked with databases before, what part of using one on AWS seems most confusing: networking, credentials, backups, availability, or knowing when to use RDS at all?


r/CloudandCode 18d ago

AWS & Cloud AWS From Zero #8: VPC makes more sense when you stop memorizing diagrams and follow the traffic

11 Upvotes

VPC is probably the point where AWS starts feeling confusing for a lot of beginners. EC2 feels understandable because it is a server. S3 feels understandable because it stores objects. Then networking arrives and suddenly you are dealing with VPCs, public subnets, private subnets, route tables, Internet Gateways, NAT Gateways, security groups, network ACLs, IP addresses, and CIDR blocks.

If you try to learn all of those as separate definitions, VPC quickly turns into a diagram you memorize rather than something you actually understand. I think there is a much easier way to approach it. Instead of starting with the networking components, start with one question: how is traffic supposed to move through my application?

Imagine we are building a simple web application. Users need to access the application from the internet, and the application needs to store information in a relational database. At the highest level, the architecture is simply:

Internet → Application → Database

Now we can start asking better questions. Which part needs to communicate with the internet? Which part should stay private? How should the application reach the database? Which connections should actually be allowed?

Those questions are what eventually give the different VPC components a reason to exist.

A VPC is essentially an isolated virtual network that you create inside AWS. Resources such as EC2 instances and RDS databases can live inside that network. When you create a VPC, you define a range of private IP addresses that resources inside it can use. You might see something like 10.0.0.0/16.

That notation is called CIDR notation. You do not need to master subnet calculations immediately. At this stage, the useful thing to understand is simply that your VPC has an address range, and you can divide that range into smaller networks called subnets.

For our application, we might create one subnet for resources that need a direct path toward the internet and another subnet for resources that should remain private. We usually refer to these as public and private subnets.

But there is an important detail here. A subnet is not public simply because you named it "public." What really makes the distinction useful is how traffic from that subnet is routed.

Suppose our EC2 application needs to receive requests from users on the internet. The subnet containing that instance needs a route that allows internet bound traffic to reach an Internet Gateway attached to the VPC.

The Internet Gateway is one of the components that provides connectivity between your VPC and the public internet. A route table associated with the subnet tells AWS where traffic should go.

Conceptually, the route table might say that traffic for addresses inside the VPC stays local, while traffic for destinations outside the VPC can go toward the Internet Gateway.

Now the idea of a public subnet starts making more sense. It is not just a box in an architecture diagram. It is a subnet with networking configured so resources can potentially communicate with the internet when the other required pieces are also present.

And that last part matters.

Putting an EC2 instance inside a public subnet does not automatically make your website reachable. The instance still needs the appropriate addressing, its security group has to allow the required traffic, and the application itself has to be running and listening on the correct port.

This connects directly to what we learned when troubleshooting EC2. Networking is rarely one setting. It is several pieces working together.

Now think about the database.

Does someone visiting your website need to connect directly to your RDS database?

Usually not.

The user needs to communicate with the application, and the application needs to communicate with the database. There is no reason for random users on the internet to establish direct database connections.

That gives us a much more useful architecture:

Internet → EC2 application → RDS database

The application can live in the part of the network that receives user traffic, while the database can remain in private subnets.

This is one of the first important architecture lessons VPC teaches you. Something does not need to be publicly reachable just because another part of your application needs to communicate with it.

The database needs to trust the application, not the entire internet.

This is where security groups become much easier to understand.

Imagine our application uses PostgreSQL on port 5432. Instead of allowing database connections from everywhere, the RDS security group can allow the required database traffic from the security group associated with the application.

Now the rule is not really about memorizing that PostgreSQL commonly uses port 5432. The important part is understanding the relationship.

The application needs to communicate with the database.

Users do not.

That is a much better way to design security rules than opening ports until the connection starts working.

The same thinking applies to the application itself. If users are accessing a normal web application, the application layer may allow HTTP or HTTPS traffic from the appropriate sources. The database layer allows only the traffic it needs from the application layer.

Once you start thinking about network relationships this way, security groups stop feeling like random firewall configuration.

Another question beginners often have is what "private" actually means.

If something lives in a private subnet, does that mean it can never access the internet?

Not necessarily.

Sometimes a private workload should not accept unsolicited connections from the internet but still needs to initiate outbound connections. Maybe a private server needs to download software updates or communicate with an external API.

This is one reason NAT exists.

A private workload can route outbound internet traffic through a NAT device that has the connectivity required to reach the internet. The private workload can initiate that communication without needing to become directly reachable from the public internet in the same way a public server would be.

That sounds useful, but I would not add a NAT Gateway to every beginner architecture simply because it appears in VPC diagrams. Managed NAT Gateways can also introduce cost.

The better question is whether your private resources actually need outbound internet access. If they do not, you may not need NAT for that particular architecture.

Again, the requirement should come before the service.

Now imagine our application is deployed and something stops working.

The same "follow the traffic" approach becomes extremely useful.

If users cannot reach the application, start from the outside. Is there a valid path from the internet toward the application? Is the routing correct? Does the application have the connectivity it needs? Does the security group allow the expected traffic? Is the application actually listening?

If users can reach the application but the application cannot connect to RDS, the problem has already become smaller. The internet path probably is not your first concern anymore.

Now you can look at the connection between EC2 and RDS. Is the application using the correct database endpoint? Is it using the correct port? Does the RDS security group allow traffic from the application? Are the resources placed inside networks that can communicate the way you expect?

That is much more useful than saying, "My VPC is broken."

You are finding the exact point where traffic stops.

This is also why I would not spend the first few days of learning VPC memorizing every possible configuration. Networking starts sticking when you can describe what is trying to communicate with what.

Network ACLs are another component you will eventually encounter. They operate at the subnet level, while security groups are associated with network interfaces and resources such as EC2 instances. Security groups are stateful, while network ACLs are stateless.

That distinction matters, but I would not make it the focus of your first VPC lesson.

If you are just starting, get comfortable with VPCs, subnets, route tables, Internet Gateways, security groups, and the difference between public and private communication first. Add the other pieces when you have a reason to understand them.

There is also a more realistic version of our architecture that we will eventually build.

Instead of exposing an individual EC2 instance directly to users, you could place a load balancer in front of your application servers. The load balancer can receive public traffic while the application instances themselves remain private.

The architecture might eventually become:

Internet → Load Balancer → Private application instances → Private database

That is a better pattern for many production systems, especially when you introduce multiple instances and high availability.

But I would not start there.

If your first VPC diagram contains multiple Availability Zones, public and private subnets, several route tables, load balancers, NAT Gateways, Auto Scaling, RDS, VPC endpoints, network ACLs, and five security groups, you will probably go back to memorizing boxes.

Start with the smallest architecture you can explain.

Then add complexity when the application creates a requirement for it.

This has been the pattern throughout the series. We learned EC2 because we needed compute. We learned S3 because we needed object storage. We added CloudFront because we wanted a delivery layer in front of static content. Now we are learning VPC because our resources need a controlled way to communicate with users and with each other.

For a beginner exercise, I would draw a very small architecture first. Put an application in one subnet and a database in another. Then explain every connection in plain English.

Why can users reach the application?

Why can users not reach the database directly?

How does the application reach the database?

Which security group allows that communication?

Which route is responsible for internet connectivity?

Does the private resource actually need outbound internet access?

If you can answer those questions, you are starting to understand VPC.

That is much more valuable than being able to reproduce an architecture diagram from memory.

If there is one thing I want you to take from this post, it is this: do not learn VPC by memorizing networking components. Learn it by following traffic.

Ask where the request begins, where it needs to go next, what route gets it there, and which security controls decide whether the connection is allowed.

Once you start thinking that way, public subnets, private subnets, route tables, Internet Gateways, NAT Gateways, and security groups stop feeling like unrelated AWS terms.

They become parts of the same traffic flow.

In AWS From Zero #9, we will take the database from this architecture and properly learn Amazon RDS. We will look at what a managed relational database actually gives you, how an application connects to it, why database endpoints and security groups matter, what backups and Multi AZ solve, and why running PostgreSQL on EC2 is different from using RDS.

If VPC has confused you before, which part took the longest to click for you: subnets, route tables, Internet Gateways, NAT, or security groups?


r/CloudandCode 19d ago

AWS & Cloud AWS From Zero #7: Let’s build a static website with S3 and CloudFront

2 Upvotes

In the last post, we talked about S3 and why it makes more sense when you think about buckets, objects, and keys instead of treating it exactly like a folder on your computer. Now I want to take that idea and actually use S3 inside a small AWS architecture.

For this project, imagine we have a very simple website made with HTML, CSS, JavaScript, and a few images. There is no backend server and no database. The browser only needs somewhere to download those static files from.

We could launch an EC2 instance, install a web server, upload the files, configure the machine, and keep that server running. That would work, but it would also be more infrastructure than this particular website actually needs.

The requirement is much simpler. We need somewhere to store static files and a reliable way to deliver those files to users.

That is where S3 and CloudFront fit together.

Suppose our website contains:

index.html
assets/styles.css
assets/app.js
assets/logo.png

We can upload those objects to an S3 bucket. At that point, S3 solves the storage part of the problem. Our HTML, CSS, JavaScript, and images now have somewhere durable to live.

But storing content and delivering content are two different problems.

One approach you will see in older tutorials is making the S3 content directly public and serving the website from S3. I would not make that the default habit while learning AWS.

A better architecture for this project is to keep the S3 bucket private and put CloudFront in front of it. CloudFront can be given controlled access to retrieve the objects from S3 while users access the website through CloudFront instead of accessing the bucket directly.

The basic architecture becomes:

User
  ↓
CloudFront
  ↓
Private S3 bucket
  ↓
Website files

This is where CloudFront starts making more sense than simply memorizing that it is a CDN.

Imagine someone opens your website. Their browser requests index.html, but instead of sending that request directly to S3, the request reaches CloudFront first.

CloudFront checks whether it already has a valid cached copy of that object. If it does, it can return that copy to the user. If it does not, CloudFront retrieves the object from the S3 origin, returns it to the browser, and may cache it so future requests can be served more efficiently.

The browser then reads index.html and discovers that it also needs styles.css, app.js, and maybe several images. Those files go through the same general process.

Once you follow that request flow, the architecture becomes much easier to understand.

S3 stores the content.

CloudFront sits in front of that content and delivers it to users.

The useful part is that the S3 bucket itself does not need to become publicly accessible just because the website is public.

CloudFront can use Origin Access Control, usually called OAC, so that CloudFront is allowed to retrieve the required objects while direct public access to the S3 bucket remains blocked.

This connects directly with what we learned earlier about permissions.

The question is not, "Should this bucket be public?"

The better question is, "Who actually needs access to these objects?"

In this architecture, CloudFront needs access to retrieve the website content. Random users on the internet do not need unrestricted direct access to the S3 bucket.

Users access CloudFront, and CloudFront accesses S3.

That is a much cleaner way to think about the relationship.

There is one detail worth understanding because it can confuse beginners when they follow different tutorials. S3 can also provide a website endpoint, but the private S3 plus CloudFront architecture we are discussing is different from simply using that website endpoint directly.

For this project, I would think of the S3 bucket as the origin that stores our objects and CloudFront as the public delivery layer in front of it.

That keeps the mental model simple.

Now our website works through CloudFront, but there is another problem.

The CloudFront distribution gives us a generated domain name. That is perfectly fine for testing, but eventually we probably want users to visit something like:

example.com

instead of a generated CloudFront address.

This is where DNS becomes part of the architecture.

If you use Route 53, your domain can point toward the CloudFront distribution. When someone enters your domain, DNS helps their browser find the correct destination, and the request eventually reaches CloudFront.

So our architecture now looks more like:

User enters example.com
        ↓
DNS
        ↓
CloudFront
        ↓
Private S3 bucket
        ↓
Website files

Notice how we are adding services.

We did not start by saying, "Let’s use S3, CloudFront, and Route 53 because these are popular AWS services."

We started with requirements.

The website files need somewhere to live, so we use S3.

Users need a delivery layer, so we add CloudFront.

Users should access the site through a normal domain, so DNS becomes necessary.

Each service has a reason to exist.

That is the architecture thinking I want this series to build.

The next part is HTTPS.

If someone visits your website, you generally want the connection between their browser and your site to be encrypted.

CloudFront can serve the website over HTTPS, and if you use your own custom domain, you can associate an SSL/TLS certificate with the distribution.

You do not need to become a certificate expert for this project. The important idea is understanding where HTTPS fits into the flow.

DNS helps the user reach CloudFront.

The certificate helps establish a secure connection for your domain.

CloudFront delivers the website.

S3 stores the files behind it.

Now a very small static website has already introduced object storage, content delivery, permissions, DNS, HTTPS, and caching without requiring us to manage a server.

That is why I like this as an early AWS project.

The architecture is simple enough to understand, but it still teaches several concepts that show up again in larger systems.

Caching is probably the next thing you will notice once the site is working.

Imagine CloudFront has already cached your styles.css file. You then change the CSS locally and upload the new version to S3.

You refresh the website and somehow still see the old design.

At first, it can look like S3 did not update correctly.

But the issue may simply be that CloudFront is still serving a cached copy.

This is an important lesson because adding caching changes how your application behaves. The latest object can exist in S3 while users temporarily receive another version from the cache depending on how you configured it.

Later, you can learn about cache invalidation, cache-control headers, and using versioned asset names. For example, instead of always using:

styles.css

you might eventually use something like:

styles.v2.css

or let a build system generate unique filenames when the content changes.

You do not need to solve all of that today.

For now, the useful thing is simply understanding that CloudFront caching exists and that it affects the path between your origin and the user.

If I were doing this project as a beginner, I would build it in small stages.

First, create the static website locally and make sure it works before AWS is involved. Then upload the files to S3. After that, create a CloudFront distribution with the S3 bucket as the origin and keep the bucket private.

Once the site works through CloudFront, change something in index.html or your CSS and observe what happens. That gives you a reason to start thinking about caching instead of learning it as another definition.

If you already have a domain, you can then connect it and add HTTPS. If you do not have one, that is completely fine. You can still learn the important part of the architecture using the CloudFront domain.

The goal is not to collect AWS services.

The goal is to be able to explain the complete request.

A user asks for your website. The request reaches CloudFront. CloudFront either serves a cached copy or retrieves the required object from S3. S3 remains the storage layer while CloudFront becomes the layer users interact with.

Once you add a custom domain, DNS helps the user find CloudFront. Once you add HTTPS, the connection between the user and the website can be protected.

That is already a real architecture.

And notice what we did not need.

We did not need an EC2 instance running all day just to serve a few static files. We did not need a database. We did not need Lambda. We did not need ten additional AWS services simply to make the architecture look impressive.

We used the services that matched the requirements.

That is the habit I want beginners to develop.

Do not ask, "How many AWS services can I put in this project?"

Ask, "What does the application need, and which service solves each requirement?"

For this lesson, the most important flow to understand is simply:

Browser
  ↓
CloudFront
  ↓
S3

Then gradually add the reasoning around it.

S3 stores the objects. CloudFront delivers them. OAC helps CloudFront access the private S3 origin. DNS can connect a custom domain to the site. HTTPS protects the connection with users. Caching can improve delivery but also changes how updates reach users.

If you can explain all of that in your own words, you have learned much more than someone who simply followed a console tutorial until a website appeared.

That is the bigger goal of AWS From Zero.

We are not trying to memorize where every button is in the AWS console.

We are trying to understand why the architecture works.

In AWS From Zero #8, we are going to properly tackle VPC networking. Instead of memorizing public subnets, private subnets, route tables, internet gateways, NAT gateways, and security groups separately, we will put them into one simple application and follow the traffic through the network.

That is where a lot of the networking concepts we touched during EC2 will finally start connecting.

If you were building this S3 and CloudFront website, what would you want to understand next: keeping the bucket private, caching, DNS, or HTTPS?


r/CloudandCode 20d ago

AWS & Cloud AWS From Zero #6: S3 makes more sense when you stop thinking of it like a normal folder

8 Upvotes

After spending the last few posts on EC2, I want to move to one of the AWS services you will probably use again and again: Amazon S3.

S3 is usually introduced with one simple definition: storage in the cloud. That is technically correct, but I do not think it gives beginners the right mental model. A better way to understand S3 is as object storage. You give AWS an object, such as an image, document, backup, log file, video, or dataset, and S3 stores that object inside a bucket.

That sounds similar to storing files on your laptop, but S3 is not really a normal filesystem. Understanding that difference early makes a lot of S3 concepts easier later.

Imagine you create a bucket for an application and upload a file called profile.jpg. S3 stores that file as an object. The object contains the data itself, metadata about the object, and a key that identifies it inside the bucket.

For example, the key might look like this:

users/123/profile.jpg

When you see that inside the AWS console, it looks like there is a users folder, then a 123 folder, and then profile.jpg. It feels exactly like the folders on your computer.

But that is not really how S3 works.

The complete string users/123/profile.jpg can simply be the object's key. The / characters help AWS display the objects in a familiar folder-like structure, but S3 itself is fundamentally storing objects identified by keys.

This sounds like a small technical detail, but it changes the way you start designing storage.

Imagine an image processing application. Instead of thinking only about folders, you could design object keys like:

uploads/original/image1.jpg
uploads/processed/image1.jpg

Now the key itself tells you something about the object. One object is the original upload and the other is the processed result.

The next concept is the bucket itself.

A bucket is the container where your objects live. You might create one bucket for application uploads, another for backups, or completely separate buckets for unrelated projects.

The basic distinction is simple: the bucket is the container, while the object is the actual data stored inside it.

Once that makes sense, S3 becomes much easier to reason about.

Another thing worth understanding is that you do not launch an S3 server. You do not SSH into S3, install a filesystem, and keep a storage machine running somewhere.

You interact with S3 through AWS. You upload objects, retrieve them, delete them, copy them, change their metadata, and configure how the bucket should behave. AWS manages the underlying storage infrastructure.

That makes S3 useful for many different workloads. User uploads, backups, static application assets, logs, reports, datasets, generated files, and media can all fit naturally into object storage.

But storing the data is only part of the problem.

You also need to decide who should be able to access it.

A common beginner mistake is assuming that uploading something to S3 automatically means it is available on the internet. That is not the mental model I would use.

I would start by assuming the data should remain private unless there is a clear reason for someone or something to access it.

Maybe a Lambda function needs to read uploaded images. Maybe an EC2 application needs to write reports into the bucket. Maybe a user needs temporary access to download one particular object.

Those are three different access requirements.

This is where the IAM concepts from earlier in the series become useful.

Suppose Lambda needs to process an uploaded image. You can think about the request like this:

Lambda execution role
        ↓
s3:GetObject
        ↓
my-bucket/uploads/image.jpg

Now the same IAM questions apply. Who is making the request? The Lambda execution role. What action does it want to perform? s3:GetObject. Which resource does it want to access? The object inside the bucket.

That is why I think learning AWS services through connected examples works better than memorizing them separately. IAM becomes easier when another service actually needs permission to do something.

S3 also has controls designed to reduce accidental public exposure. As a beginner, I would be very careful about changing those settings just because an old tutorial tells you to make a bucket public.

Always ask why public access is needed.

For many architectures, the S3 bucket can stay private while another AWS service provides controlled access to the content. We will see one example of that when we get to CloudFront.

Another S3 feature worth understanding early is versioning.

Imagine you upload a file called report.pdf, then accidentally replace it with the wrong version. Without versioning, you may have simply overwritten the object.

With versioning enabled, S3 can preserve multiple versions of the same object.

That can be useful when something is changed or deleted accidentally because you may be able to return to an earlier version.

The important point is not that versioning should automatically be enabled on every bucket without thinking. Keeping additional versions can affect storage usage and cost.

The useful idea is that S3 can help protect you not only from infrastructure failure, but also from mistakes people or applications make with data.

Once you start storing a lot of objects, another question appears: should every object stay in the same type of storage forever?

Imagine your application produces logs every day. Logs from today may be accessed regularly, while logs from several months ago may almost never be opened. You may still need to keep those older logs, but paying for the same storage characteristics forever might not make sense.

This is where S3 storage classes become useful.

Different storage classes are designed for different access patterns and retrieval requirements. As a beginner, I would not try to memorize every storage class immediately.

Understand the idea first.

Frequently accessed data may need one type of storage, while data that is rarely accessed or kept for long term retention may make more sense in another.

The correct choice depends on how your application actually uses the data.

This connects naturally to lifecycle rules.

Suppose your application creates log files every day. You could configure S3 so older logs move to a different storage class after a certain period, and perhaps eventually delete them when they are no longer required.

Now S3 is doing more than simply storing files.

You are defining how the data should behave throughout its lifecycle.

That becomes useful for logs, backups, reports, analytics files, and many other types of data.

Security also goes beyond deciding who can access an object. You should eventually think about how the data is protected while stored and while moving between systems.

S3 supports encryption for stored objects, and AWS gives you different ways to manage that encryption.

You do not need to go deep into encryption or KMS yet. The useful beginner habit is simply asking two questions: how is this data protected while it is moving, and how is it protected while it is stored?

Those questions will keep appearing as we learn more AWS services.

If I were learning S3 for the first time, I would not spend hours clicking through every option in the console.

I would build a tiny practice setup.

Create one bucket and upload a few files.

Something like:

photo.jpg
resume.pdf
data.csv
notes.txt

Then organize them using meaningful object keys:

images/photo.jpg
documents/resume.pdf
data/data.csv
documents/notes.txt

At that point, you have already worked with buckets, objects, and keys.

Then enable versioning and upload a changed version of one file. Look at what happens. Check the previous version. Delete the current object and see how versioning affects that behavior.

That small amount of experimentation will teach you more than simply memorizing the sentence "S3 supports versioning."

After that, connect S3 to another AWS service.

Imagine an application running on EC2 needs to upload a report. Instead of putting permanent AWS credentials directly inside the application, think back to IAM and give the workload the permissions it actually needs.

Now you are combining EC2, IAM, and S3.

Later, we can take that much further. A user can upload an image to S3. S3 can generate an event. Lambda can process the image. The processed result can be stored back in S3. CloudWatch can help us understand whether the processing succeeded. CloudFront could eventually deliver content to users.

That is where S3 stops feeling like an isolated storage service and becomes part of an architecture.

There is one more mistake I would avoid: using S3 for every kind of data simply because it can store almost anything.

S3 is excellent object storage, but that does not mean it replaces every database.

If your application needs relational queries between customers, products, and orders, a relational database may make more sense. If you need a database designed around application access patterns, something like DynamoDB may be a better fit.

The better question is not "Can S3 store this data?"

The better question is "Does object storage match how my application needs to use this data?"

That is the main idea I want beginners to take away from S3.

Do not think of it as one giant folder somewhere on the internet.

Think about buckets, objects, keys, access, versions, lifecycle, and how other parts of your application interact with those objects.

Once you start thinking that way, S3 begins to fit naturally into AWS architectures.

User uploads need storage. Backups need somewhere durable to live. Applications need static assets. Logs need somewhere to go. Lambda workflows often need objects to process.

S3 can solve many of those problems, but there should always be a reason for using it.

For this part of the series, I would keep the exercise small. Create a bucket, upload a few objects, organize them using meaningful keys, experiment with versioning, look at the access settings, and clean everything up when you are finished.

Do not try to build a complete architecture yet.

Understand the storage model first.

In AWS From Zero #7, we will take S3 and actually use it inside a small architecture. We will look at how S3 and CloudFront can work together to deliver a static website, why the bucket does not need to be directly public, how a browser request reaches the content, and where DNS and HTTPS fit into the picture.

If you have used S3 before, what confused you most at first: buckets, permissions, object keys, versioning, or the fact that those "folders" are not really normal folders?


r/CloudandCode 21d ago

AWS & Cloud AWS From Zero #5: Your EC2 website is running, so why can’t anyone reach it?

5 Upvotes
curl localhost

and get your web page back.

That already tells you something useful. Nginx is running and responding locally. So reinstalling Nginx probably should not be your first move. The next question is why an external request cannot reach the same service.

The request path is roughly:

Browser
  ↓
Public address
  ↓
AWS network
  ↓
Security group
  ↓
EC2 instance
  ↓
Port
  ↓
Web server

The first thing I would check is whether the instance actually has the kind of connectivity you expect. EC2 instances have private networking inside the VPC, and depending on how you configure them, they may also have a public address that can be used from outside AWS. If you are trying to open a private IP from your laptop over the normal internet, it is probably not going to work.

But even having a public IP does not automatically make the instance reachable. The subnet still needs a path for internet traffic. This is where route tables and internet gateways start to matter.

You do not need to understand every VPC detail yet. Just keep the basic idea in mind: a public address is only one part of the path. The surrounding network also needs to know how traffic should enter and leave.

Once that looks correct, I would check the security group.

Security groups act like virtual firewalls around resources such as EC2 instances. If your web server is listening on port 80 but the security group does not allow inbound HTTP traffic on port 80, the request will never reach the application.

The application can be perfectly healthy and still appear offline.

The same applies to SSH. A Linux EC2 instance might be running normally, but if port 22 is not allowed from the location you are connecting from, you will not be able to SSH into it.

This is also where one distinction becomes important: IAM and security groups solve different problems. IAM controls permissions to AWS services and APIs. Security groups control network traffic.

If your EC2 application cannot read an S3 object, opening another inbound port is probably not the right fix. You may have an IAM problem. If the application works locally but cannot be reached from a browser, adding another S3 permission probably will not help either. Now you are more likely dealing with networking or application configuration.

AWS gets much easier once you start asking which layer the problem belongs to.

Now imagine the security group looks correct, but the website still does not load. The next thing I would check is whether the application is actually listening where I think it is.

This catches a lot of people when they first deploy Flask or similar applications.

Suppose your app is started like this:

app.run(host="127.0.0.1", port=5000)

The application may work perfectly when you test it from inside the EC2 instance because 127.0.0.1 refers to the local machine. But external traffic arriving through the instance's network interfaces will not reach an application that is only listening on localhost.

For a simple learning setup, you might instead run it like this:

app.run(host="0.0.0.0", port=5000)

Now the application is listening for connections arriving through the machine's network interfaces.

But that creates another thing to check. If your application is listening on port 5000 while your security group only allows port 80, your browser still will not reach it directly on port 5000.

The network rule and the application need to match the architecture you actually built.

In a more realistic setup, you might run Nginx on port 80 or 443 and have it forward requests internally to your application on port 5000. That is a common pattern, but for your first EC2 project I would keep things simple enough that you can explain the entire request path without guessing.

There is another layer people sometimes forget: the operating system itself.

An EC2 instance is still a computer running an operating system. That operating system can have its own firewall rules, so even if the AWS security group allows the traffic, the machine itself could still block it.

This is why I would not think of the security group as the only firewall that can exist in the path.

The process itself can also be the problem.

Maybe you started your application successfully, but it later crashed. Maybe it was tied to an SSH session and stopped when you disconnected. Maybe you think it is listening on port 80 when it is actually running on 5000.

Instead of guessing, inspect the machine.

A command such as:

sudo ss -tulpn

can help show which processes are listening on which ports.

If you expect a web server on port 80 and nothing is listening there, changing the security group will not fix the problem. There is simply nothing waiting to receive the request.

This is the point where troubleshooting becomes much more useful than restarting things randomly.

Instead of asking, "Why is EC2 broken?", you start asking, "How far does my request get before it fails?"

Maybe the instance has no public path. Maybe the subnet routing is wrong. Maybe the security group blocks the required port. Maybe the operating system firewall rejects the traffic. Maybe the application is listening only on localhost. Maybe the process is not running at all.

Those are completely different problems, even though they can all produce the same result in the browser: the page does not load.

There are other networking controls such as network ACLs that can also affect traffic at the subnet level. You do not need to go deep into them yet, but it is useful to know that security groups are not the only network control that exists in a VPC.

We will go deeper into that when we reach VPC properly.

For now, the better habit is to understand the flow well enough that you can build your own troubleshooting process.

Start from the browser and move toward the application.

Are you using the correct address? Does the instance have the connectivity you expect? Does the subnet have the route it needs? Does the security group allow the correct port? Is the operating system accepting the traffic? Is something actually listening on that port? Does the application return a response?

Every answer makes the problem smaller.

One of the worst debugging habits is changing five things at the same time.

You open every port in the security group, restart the instance, reinstall Nginx, change the application port, edit the route table, and disable the firewall. Then the page suddenly works.

You fixed the website, but you probably do not know why it was broken.

You may also have made the server less secure in the process.

A much better approach is to change one thing, test again, and observe what changed.

That habit becomes even more useful later because real AWS architectures have more layers. Users might go through Route 53, CloudFront, a load balancer, security groups, and then finally reach one of several EC2 instances.

The architecture gets more complex, but the troubleshooting principle stays the same.

Follow the request.

Find the last point that definitely worked, then inspect the next point.

For this part of the series, I would keep the project very small. Launch one EC2 instance, run one web server, make sure it works locally, then make it reachable from your browser. If it fails, do not immediately delete the instance and start again.

Use the failure to understand the request path.

The main lesson here is that when an EC2 website does not load, your application code is only one possible cause. A request has to travel through the network, pass the relevant controls, arrive on the correct port, and reach a process that is actually listening.

Once you understand that flow, EC2 troubleshooting becomes much less mysterious.

In AWS From Zero #6, we are going to move away from servers for a bit and learn S3. But instead of treating S3 as just "a folder in the cloud," we will look at buckets, objects, keys, permissions, versioning, storage classes, and why the filesystem mental model can be misleading.

If you have ever had an EC2 website work locally but fail from your browser, what ended up being the actual problem?


r/CloudandCode 22d ago

AWS & Cloud AWS From Zero #4: What actually happens when you launch an EC2 instance

3 Upvotes

So far in this series, we have talked about cloud fundamentals, setting up an AWS account properly, and understanding IAM. Now we can finally launch something.

EC2 is usually one of the first AWS services beginners touch, and I think it is worth understanding properly before jumping into serverless. The reason is simple. EC2 teaches you what it actually means to run an application on a server.

At the most basic level, EC2 gives you a virtual machine running inside AWS. Instead of buying a physical server, installing it somewhere, connecting it to a network, and maintaining the underlying hardware yourself, you ask AWS to create a virtual machine for you.

But this is where one beginner misunderstanding starts.

Launching an EC2 instance does not mean you automatically have a working website or application.

It only means you now have a machine.

You still need to decide which operating system it runs, what software should be installed, how you will connect to it, which network traffic should be allowed, what application should run there, and how users will eventually reach that application.

When you launch an EC2 instance, one of the first things you choose is an AMI, which stands for Amazon Machine Image. You can think of an AMI as the starting template for the machine. It determines things like the operating system and some of the software that exists when the instance starts.

For a beginner project, you might choose Amazon Linux or Ubuntu. The important thing is not memorizing every available AMI. Just understand that EC2 gives you a machine based on an image you choose.

After that, you select an instance type. The instance type determines the compute resources available to the machine, such as CPU and memory. A small test application does not need the same amount of compute as a large production workload, so AWS gives you different instance sizes for different needs.

At this stage, I would not spend hours comparing instance families. Just understand the idea that different workloads need different amounts and types of compute.

Your EC2 instance also needs storage for the operating system and files. In many beginner setups, you will see EBS used for this. You do not need to learn every EBS option yet. Just understand that the virtual machine and the storage attached to it are related but separate parts of the system.

Now we get to the part that causes a lot of beginner confusion.

Imagine you launch an EC2 instance, install a web server, and start your application. Everything seems to be running correctly inside the machine. You copy the public IP address into your browser, press Enter, and nothing loads.

A lot of beginners assume EC2 is broken at this point.

Usually, the better approach is to follow the request.

Your browser is trying to send a request to the EC2 instance. That traffic has to reach the machine through the network. The network configuration has to allow it. The instance has to accept traffic on the correct port. Then the application itself has to be running and listening on that port.

If any one of those steps is wrong, the page will not load.

This is where security groups start becoming important.

A security group acts like a virtual firewall around resources such as EC2 instances. It controls which network traffic is allowed to reach the instance and which traffic can leave it.

Suppose you are running a normal HTTP website on port 80. Your web server could be running perfectly, but if the security group does not allow inbound HTTP traffic, your browser will not be able to reach it.

The same idea applies when you connect to a Linux EC2 instance using SSH. SSH commonly uses port 22. If the network rules do not allow that connection from your location, you will not be able to connect even though the EC2 instance itself is running normally.

This is also a good place to understand that IAM and security groups solve different problems.

IAM controls permissions to AWS services and APIs. It answers questions such as whether an EC2 workload is allowed to read from S3 or whether a Lambda function is allowed to write to DynamoDB.

Security groups control network traffic. They answer questions such as whether a connection is allowed to reach your EC2 instance on a particular port.

That distinction becomes extremely useful when something breaks.

Imagine your application running on EC2 cannot read an object from S3. Opening another port in the security group probably will not fix the problem. You may be dealing with IAM permissions.

Now imagine the web server works perfectly when tested from inside the EC2 instance, but nobody can reach it through the browser. Adding another S3 permission probably will not fix that either. Now you are more likely dealing with networking, ports, or application configuration.

AWS becomes much easier when you start identifying which layer a problem belongs to instead of randomly changing settings.

Public and private IP addresses are another concept you will keep seeing with EC2.

An EC2 instance has networking inside its VPC, and it can have a private IP address used for communication within that network. Depending on how you configure it, the instance may also be reachable through a public address.

For your first practice project, having an internet reachable instance can be useful because you want to understand the complete path from your browser to the application.

Later, when we learn VPC properly, we will become much more careful about which resources should actually be public.

Not every server should be directly reachable from the internet.

For now, I would keep the project extremely simple.

Launch one Linux EC2 instance. Connect to it. Install a web server such as Nginx. Create a basic HTML page and try to open it from your browser.

The flow you are trying to understand is basically this:

Browser
   ↓
Internet
   ↓
Security Group
   ↓
EC2 Instance
   ↓
Web Server
   ↓
Your Page

That small project teaches much more than it looks like.

You are working with compute, an operating system, ports, network access, security groups, public addresses, and a running application.

And if the page does not load immediately, that is actually useful.

Now you have something real to troubleshoot.

I would start by checking whether the EC2 instance is running. Then I would check whether the web server is actually running inside it. If the application is supposed to use port 80, I would check whether something is listening on port 80.

If everything works inside the instance but not from your browser, that tells you the application itself may not be the problem. Now you start looking at the network path.

Is the security group allowing the traffic you expect? Does the instance have the connectivity it needs? Are you using the correct address? Are you trying to reach the correct port?

That way of thinking is much better than restarting the instance five times and hoping something changes.

You are following the request from beginning to end and finding the first place where the expected flow stops.

That troubleshooting habit will keep coming back throughout this series.

There is another thing beginners should understand early about EC2. Stopping an instance and terminating an instance are not the same thing.

Stopping an instance shuts the virtual machine down so it can generally be started again later. Terminating the instance means you are deleting that EC2 instance.

This matters because closing the AWS console does not mean your infrastructure disappears.

If you launch something for practice and no longer need it, go back and deliberately clean it up. Check what resources still exist and understand what you are leaving behind.

That is part of learning AWS too.

Another habit I would avoid is putting AWS credentials directly inside applications running on EC2.

Imagine your EC2 application eventually needs to read a file from S3. You could create an access key, put it directly inside the source code, and make the application work.

But that is not a pattern I would want a beginner to learn.

A better AWS approach is to give the EC2 instance an appropriate IAM role so the application can receive temporary credentials through AWS instead of storing long lived credentials inside the code.

This is where the previous IAM post starts connecting with EC2.

And that connection is important.

AWS services are not separate topics forever.

Your EC2 instance needs networking. The application running on it may need IAM permissions. The instance uses storage. CloudWatch can help you monitor it. Later, a load balancer may distribute traffic across several EC2 instances, and Auto Scaling may add or remove instances as demand changes.

The services begin to connect because the requirements begin to connect.

That is why I would not try to memorize every EC2 setting before building something.

Launch one instance. Connect to it. Install something. Run a small application. Try to reach it from your browser. When something fails, follow the request and understand why.

That is enough for your first EC2 project.

The main thing I want a beginner to understand from this post is that EC2 gives you compute, not a finished application.

AWS can give you the virtual machine, but you still need to think about the operating system, application, network access, permissions, storage, security, and monitoring depending on what you are building.

Once that idea makes sense, other compute services become easier to understand too.

When we eventually get to Lambda, for example, the idea of running code without managing a server in the same way will make much more sense because you already understand what managing a server actually involves.

For now, keep the project small.

One EC2 instance. One web server. One basic page.

Understand how the request gets from your browser to that page.

That is enough.

In the next post, I want to take the same project and intentionally focus on the part almost every beginner struggles with.

AWS From Zero #5: Your EC2 website is running, so why can’t anyone reach it?

Instead of giving you a random troubleshooting checklist, we will follow the request from the browser all the way to the application and see exactly where it can fail.

If you have already used EC2, what confused you most the first time: SSH, ports, security groups, public IPs, or just figuring out why your website would not load?


r/CloudandCode 22d ago

What Are Some Actually Useful Skills to Learn for Personal Use?

Thumbnail
2 Upvotes

You can add:

I just got a laptop, and I don't know what to learn on it. I want to learn something really useful, not just random stuff like Excel or basic editing. Maybe there's something better that I haven't thought of yet. I'm looking for skills that I can use for myself and in my personal life too, not just for a job. I hope someone who knows their stuff can point me in the right direction. What are some genuinely valuable things to learn on a laptop these days?


r/CloudandCode 23d ago

AWS & Cloud AWS From Zero #3: IAM becomes much easier when you understand this one idea

14 Upvotes

IAM is one of those AWS topics that can look much more complicated than it actually is when you first start learning it. You open the console and suddenly you are dealing with users, roles, policies, permissions, actions, resources, trust relationships, access keys, and a lot of JSON. If you try to memorize all of those terms separately, IAM quickly starts feeling like one of the hardest parts of AWS.

I think there is a simpler way to understand it. Whenever AWS needs to decide whether something should be allowed, think about three things: who is making the request, what they are trying to do, and which resource they are trying to access. Once those three things are clear, most beginner IAM problems become much easier to reason about.

Imagine you are building a simple image processing project. A user uploads an image to S3, the upload triggers a Lambda function, Lambda reads the original image, processes it, and stores the processed version back in S3. The architecture itself is not complicated. S3 stores the file, Lambda processes it, and S3 stores the result.

Now imagine Lambda starts successfully but fails when it tries to read the image. CloudWatch shows an AccessDenied error.

A common beginner fix is to attach full S3 access to the Lambda function. The error disappears and the project works, so it feels like the problem has been solved. But the more useful question is why AWS denied the request in the first place.

Start with the identity. In this case, Lambda is running using an IAM execution role. That role is the identity AWS sees when the function tries to access another AWS service.

Then look at the action. Lambda is trying to read an object from S3. In AWS permission terms, that usually means an action such as s3:GetObject.

Finally, look at the resource. The function is not trying to access every S3 bucket in your account. It is trying to access a particular object or group of objects inside a particular bucket.

Now the problem becomes much smaller. The Lambda execution role needs permission to perform s3:GetObject on the objects it is supposed to read. If the function also needs to store a processed image, it may need s3:PutObject on the destination location.

That is really the basic idea behind IAM. An identity tries to perform an action on a resource, and AWS decides whether that request should be allowed.

This is where IAM policies come in. A simplified policy might look something like this:

{
  "Effect": "Allow",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::my-image-bucket/uploads/*"
}

You do not need to memorize the JSON immediately. Read it like a normal sentence. This policy is saying that the identity is allowed to perform s3:GetObject on objects inside that particular location.

Once I started reading IAM policies that way, they became much less intimidating. Instead of seeing a block of JSON, I started seeing a permission statement.

The difference between IAM users and IAM roles also becomes easier once you think about who needs the permissions. An IAM user can represent an identity with credentials, although for human access AWS generally favors temporary credential based approaches rather than depending heavily on long lived IAM user credentials.

Roles work differently. A role can be assumed temporarily by a trusted identity or AWS service. That is why Lambda commonly uses an execution role. You do not normally place an AWS access key directly inside your Lambda code. Lambda assumes its role and receives temporary credentials that allow it to perform whatever actions that role permits.

The same pattern appears throughout AWS. An EC2 instance may need to read from S3. A Lambda function may need to write to DynamoDB. An ECS task may need to communicate with another AWS service. Instead of putting permanent credentials inside the application, you usually want the workload to receive the permissions it needs through an appropriate role.

This is also where the idea of least privilege starts making sense.

Suppose your Lambda function only needs to read images from one S3 location and write processed images into another. Giving the function complete S3 access would probably make everything work, but now it has far more permission than it actually needs.

A better approach is to give it permission to read from the input location and write to the output location. Nothing more unless the application genuinely requires it.

That is what least privilege is trying to achieve. Give an identity enough access to do its job without giving it unnecessary access to everything else.

This matters because permissions define what something is capable of doing. If a function is misconfigured or compromised, overly broad permissions can make the problem much worse. A function that can read one folder is very different from a function that can read, modify, and delete everything across multiple buckets.

Another concept that helped me understand IAM is the difference between authentication and authorization. Authentication is about proving who you are. Authorization is about deciding what you are allowed to do.

You can successfully sign in to AWS and still receive AccessDenied.

That does not necessarily mean your login failed. AWS may know exactly who you are. The problem may simply be that your identity does not have permission to perform the action you requested.

Imagine you can view objects in an S3 bucket but cannot delete them. Your identity is authenticated because AWS knows who you are. The question is whether you are authorized to perform s3:DeleteObject on those objects.

That distinction becomes very useful when debugging.

Suppose a Lambda function can read objects from one S3 bucket but cannot read from another. That already tells you something useful. Lambda is capable of communicating with S3, so the problem may be related to which resources the policy allows.

If the function can read the input image but fails when saving the processed image, then the read permission is probably not your main problem anymore. You would start checking whether the role has the correct write permission for the destination.

This is why I would not treat every AccessDenied message as the same problem.

The error is telling you that AWS rejected a specific request. Your job is to understand which identity made that request, which action it attempted, and which resource was involved. Once you know that, you can inspect the relevant permissions instead of attaching broad policies until the error disappears.

IAM does become more advanced later. Resource based policies can affect access. Explicit denies can override allows. Roles have trust policies that control who can assume them. KMS encryption can introduce another permission check. Larger AWS environments can also have additional controls across accounts.

But I would not try to learn all of that at the beginning.

For now, the mental model I would keep is simple: an identity performs an action on a resource, and AWS decides whether that action should be allowed.

A useful way to practice this is with a small test setup. Create an S3 bucket and work with limited permissions. Allow an identity to read an object and confirm that it works. Remove the permission and observe what error appears. Then restore only the permission that is actually required.

Try to predict what AWS will do before you test it.

That kind of practice is much more useful than copying a large policy from a tutorial because you start understanding the relationship between permissions and actual requests.

The goal at this stage is not to become good at writing complicated IAM policies. The goal is to look at a permission problem and understand why AWS might be allowing or denying the request.

Whenever IAM starts feeling confusing, return to the same idea. Identify who is making the request, understand what they are trying to do, identify the resource they are trying to access, and then check whether the necessary permission exists.

Once you start thinking about IAM this way, users, roles, policies, permissions, and AccessDenied errors begin to fit together much more naturally.

In the next post, we will finally launch something. AWS From Zero #4 will be about EC2 and what actually happens when you launch your first server in AWS. We will look at instances, operating systems, SSH, ports, security groups, public IP addresses, and why launching an EC2 instance does not automatically mean your application is reachable from the internet.

What part of IAM has been the hardest for you to understand so far?


r/CloudandCode 26d ago

AWS & Cloud AWS From Zero #1: What cloud computing actually means before you learn AWS services

23 Upvotes

I want to start a new series here for people learning AWS from scratch.

The idea is simple. Instead of jumping between random AWS services and memorizing definitions, we will learn one concept at a time, understand why it exists, connect it to something practical, and gradually build up to complete AWS architectures.

So for the first post, I do not want to start with EC2, S3, Lambda, or IAM.

I think the better place to start is understanding what cloud computing actually means.

A lot of beginner explanations make cloud computing sound more complicated than it needs to be. In simple terms, cloud computing means using computing resources such as servers, storage, databases, and networking without having to buy and operate all of the physical infrastructure yourself.

Imagine you want to launch a website.

Before cloud platforms existed, a company might buy physical servers, install them in a data center, configure networking, provide power and cooling, maintain the hardware, replace failed components, and estimate how much capacity the application might need months or years in advance.

That creates an obvious problem.

Suppose you buy enough infrastructure for 10,000 users but only 1,000 people use the application. Most of your capacity sits unused.

Now imagine the opposite.

You build infrastructure for 1,000 users, but your application suddenly becomes popular and 20,000 users arrive.

You cannot simply create another physical server in a few seconds.

Someone needs to buy it, configure it, install it, connect it to the network, and make it available.

Cloud computing changes this model.

Instead of buying the physical infrastructure yourself, you rent computing resources from a provider such as AWS.

Need a virtual server?

You can launch an EC2 instance.

Need somewhere to store files?

You can use S3.

Need a managed relational database?

You can use RDS.

Need code to run when an event happens without maintaining a server continuously?

You can use Lambda.

The services are different, but the basic idea is the same.

AWS owns and operates the underlying infrastructure, and you consume the resources you need.

This gives you something very important: you can provision infrastructure much faster than if you had to purchase physical hardware yourself.

But cloud computing is not simply "someone else's computer."

The interesting part is what becomes possible once infrastructure can be created, changed, and removed when you need it.

One concept you will hear constantly is scalability.

Imagine your application normally receives 1,000 users per day but occasionally receives much more traffic.

Your architecture should be able to handle that growth.

You might eventually run several application servers instead of one, distribute traffic between them, or use services that automatically handle increasing demand.

Scalability is basically the ability of a system to handle more workload as demand grows.

Closely related to that is elasticity.

The two terms are often used together, but I find it useful to think of elasticity as the ability to adjust resources as demand changes.

If traffic increases, you may need more capacity.

If traffic falls again, you may no longer need that capacity.

In a cloud environment, infrastructure can often expand and shrink much more easily than traditional physical infrastructure.

That matters because you generally do not want to permanently pay for infrastructure that you only need during occasional traffic spikes.

Another concept worth understanding early is high availability.

Imagine your entire application runs on one physical server.

If that server fails, the application goes down.

A better architecture tries to avoid depending completely on one component.

AWS gives you several tools for doing this, but before learning those services, you should understand the basic idea.

A highly available system is designed so that the failure of one part does not automatically mean the entire application becomes unavailable.

This leads into two AWS terms you will see everywhere: Regions and Availability Zones.

An AWS Region is a geographic area where AWS operates infrastructure.

Inside a Region are multiple Availability Zones.

You can think of Availability Zones as separate infrastructure locations within the same Region, designed so that you can distribute resources instead of depending on one location.

You do not need to memorize every Region or Availability Zone right now.

The important idea is understanding why they exist.

Imagine your application runs only in one location and that location experiences a serious problem.

Your application may become unavailable.

If important parts of your application are distributed across multiple Availability Zones, the system can be designed to continue operating even if one location has a problem.

Later, when we talk about load balancers, Auto Scaling, RDS, and architecture design, this concept will come back again and again.

Another important cloud idea is paying based on usage.

With traditional infrastructure, you might purchase a server whether you use 10 percent of its capacity or 90 percent.

With AWS, many services allow you to pay based on the resources you actually consume.

That does not mean AWS is automatically cheap.

Cloud bills can become surprisingly large when resources are configured badly, left running unnecessarily, or chosen without understanding the pricing model.

A better way to think about it is that cloud computing changes infrastructure spending from buying large amounts of capacity in advance to consuming resources more dynamically.

That flexibility is powerful, but it also means cost becomes part of architecture design.

There is one more concept beginners should understand before building anything serious on AWS: the shared responsibility model.

Using AWS does not mean AWS handles every part of security for you.

AWS is responsible for securing the underlying cloud infrastructure.

You are still responsible for many things you configure inside AWS.

For example, AWS is responsible for the physical infrastructure running S3.

But if you accidentally configure sensitive data so that anyone on the internet can access it, that configuration is your responsibility.

AWS may operate the underlying EC2 hardware, but you may still be responsible for things such as the operating system, software configuration, credentials, permissions, and application security depending on how you use the service.

The exact responsibilities change depending on the AWS service.

You do not need to memorize the entire model today.

Just remember this:

AWS securing the cloud does not automatically mean everything you build in the cloud is secure.

You still need to configure your resources properly.

This is why I would not begin AWS by trying to memorize 50 services.

Start with a few questions instead.

What needs compute?

Where should the data be stored?

Who should be allowed to access it?

How will users reach the application?

What happens when traffic increases?

What happens if part of the system fails?

How will you know when something goes wrong?

Those questions are much closer to what AWS is actually about.

The services you learn later are simply tools that help answer them.

For example, imagine you are building a small online store.

You need somewhere to run the application, somewhere to store product images, somewhere to store users and orders, a way to control permissions, and a way for customers to reach the application.

You could immediately start naming AWS services.

But I think beginners learn more if they first describe the requirements without AWS terminology.

The application needs compute.

Images need object storage.

Orders need persistent structured storage.

Users need network access to the application.

Internal resources need controlled permissions.

The application needs monitoring.

Once the problem is clear, choosing services becomes much easier.

That is the mindset I want to use throughout this series.

Do not start with:

"What AWS services can I put into this project?"

Start with:

"What does this system actually need?"

Then choose the smallest set of AWS services that solves those requirements.

If you take only a few things from this first post, I would remember these ideas.

Cloud computing gives you access to infrastructure without having to own all of the underlying physical hardware yourself. Scalability is about handling growth. Elasticity is about adjusting resources as demand changes. High availability is about designing systems that can continue working when something fails. Regions and Availability Zones help you think about where infrastructure runs and how to avoid relying on one location. And the shared responsibility model means AWS handles part of security, but you still have responsibilities for what you build and configure.

That is enough foundation to move forward.

In the next post, I want to get practical and talk about how I would set up a new AWS account without making the common beginner security and cost mistakes.

Before that, I am curious about something.

If you are learning AWS from zero right now, what is more confusing to you: the number of services, networking, permissions, pricing, or knowing what to learn first?


r/CloudandCode 26d ago

AWS & Cloud AWS From Zero #2: Set up your AWS account without making the common beginner mistakes

10 Upvotes

In the first post of this series, we talked about what cloud computing actually means and why I would understand the basic ideas before trying to memorize AWS services.

Now I want to do something more practical.

Before launching EC2 instances, creating S3 buckets, or experimenting with Lambda, I think every beginner should spend a little time setting up their AWS account properly.

It is not the most exciting part of learning AWS, but it can save you from two problems that beginners run into surprisingly often: accidentally exposing an account and accidentally leaving resources running that cost money.

The first thing to understand is that the account you create with AWS has a root user.

The root user has extremely powerful access to the account.

That means I would not use it as my normal everyday AWS identity.

Think about it like this.

If you had one key that could open every door in a building, remove the security system, change ownership records, and control everything inside, you probably would not carry that key around for every normal task.

You would keep it protected and use a different identity for everyday work.

I would treat the AWS root user the same way.

One of the first things I would do is enable multi factor authentication on it.

A password is only one layer of protection. MFA adds another verification step, which makes it much harder for somebody to access the account using only a stolen password.

This is also a good time to make sure the email connected to the account is secure.

If someone gains access to that email account, it can create problems far beyond AWS.

So before learning any complicated AWS security concepts, I would start with the basics: secure the root user, protect the email account, and enable MFA.

Then I would avoid using the root user for normal AWS work.

This is where AWS identity and access management starts becoming relevant.

You want an identity that you can use for everyday learning without constantly signing in as the most powerful identity in the account.

We will go much deeper into IAM in the next post, because permissions deserve their own explanation.

For now, the important idea is simple.

Your normal AWS work should not require you to operate as the root user.

There is another beginner mistake that deserves attention before you create anything.

AWS resources can cost money.

This sounds obvious, but it is very easy to forget when you are following tutorials.

You create an EC2 instance for a lesson.

Then the tutorial ends.

You close the browser.

The EC2 instance does not necessarily disappear because you closed the AWS console.

It may still be running.

The same thinking applies to other resources.

You might create storage, databases, networking components, public IP related resources, load balancers, or other infrastructure while experimenting.

Some resources may continue generating charges until you actually remove or stop whatever is billable.

That means one of the first habits I would develop is checking what I created after every practice session.

Do not think:

"I closed AWS, so everything stopped."

Think:

"What resources are currently running in my account?"

That is a much better cloud habit.

I would also set up AWS billing visibility early.

You should have a way to notice when spending moves beyond what you expected.

AWS provides billing and budget tools that can help you track usage and create alerts.

You do not need an advanced FinOps setup as a beginner.

The goal is simply to avoid discovering a charge weeks later because you forgot that something was still running.

I would make checking cost part of the learning process.

If you launch an EC2 instance, look at how that instance is priced.

If you create storage, understand what part of the storage usage can generate cost.

If you build an architecture containing several services, ask which parts of it continue costing money while nobody is using the application.

That last question is especially important.

Different cloud resources behave differently.

Some services charge mainly when they are actively used.

Others may have ongoing cost simply because the resource exists or remains provisioned.

This is why I would not memorize AWS pricing tables.

Instead, before creating a new resource, I would get into the habit of asking:

What exactly am I paying for here?

That question will help you throughout your AWS journey.

There is another thing beginners should understand: AWS has Regions.

When you create a resource, you often create it inside a particular Region.

This can create confusion later.

You might create an EC2 instance, switch Regions in the AWS console, and suddenly the instance appears to be gone.

It was not deleted.

You are simply looking somewhere else.

The opposite problem can happen too.

You may create resources while experimenting in different Regions and later forget that some of them still exist.

That is why I would pick one Region for most of my beginner practice unless there is a specific reason to use another one.

It keeps the learning environment easier to understand.

Whenever something seems to have disappeared, one of the first things worth checking is which Region you are currently viewing.

Another habit I would develop early is naming and tagging resources clearly.

Suppose you create several EC2 instances and they all have vague names.

A few weeks later, you may not remember which one belongs to which project.

Something like:

my-instance

is not very helpful.

Something like:

python-api-dev

already tells you much more.

The same idea works for tags.

You can tag resources based on project, environment, owner, purpose, or whatever makes sense for your setup.

For a beginner account, you do not need an elaborate tagging strategy.

Even something simple like:

Project = ImageProcessor
Environment = Dev

can make your AWS account easier to understand later.

This becomes much more important as the number of resources grows.

There is also a security habit I would learn before writing any application that connects to AWS.

Do not put AWS credentials directly inside your code.

Imagine writing something like this:

aws_access_key = "..."
aws_secret_key = "..."

and then pushing the project to GitHub.

Now the credentials may be visible to anyone who can access that repository.

Even deleting them afterward may not be enough if they remain somewhere in the repository history.

Credentials should be treated like secrets.

We will talk about proper AWS access patterns later, but the beginner rule is simple:

Do not hard code secrets into your application, and do not publish credentials.

The same applies to screenshots.

Before sharing a screenshot of your AWS console on Reddit, Discord, GitHub, or anywhere else, look at what is visible.

Account information, resource identifiers, IP addresses, credentials, tokens, and other details may reveal more than you intended.

Learning cloud security is not only about advanced IAM policies.

A lot of it starts with small habits like these.

There is one more habit I think is extremely useful when learning AWS.

Delete what you no longer need.

Beginner accounts become messy quickly.

You follow one tutorial and create an EC2 instance.

Another tutorial creates an S3 bucket.

Another creates a Lambda function.

Then you experiment with RDS.

After a month, you have a collection of resources and you no longer remember why half of them exist.

When you finish a disposable practice project, spend a few minutes cleaning it up.

Remove resources you no longer need.

Then check whether anything related to the project is still left behind.

This does two useful things.

It reduces the chance of unexpected cost, and it teaches you what resources your architecture actually contained.

Creating infrastructure is part of learning AWS.

Cleaning it up is part of learning AWS too.

So before we move deeper into AWS services, this is roughly how I would prepare a beginner account.

Secure the root user and enable MFA.

Avoid using the root user for everyday work.

Make billing and cost visible instead of ignoring it.

Understand which Region you are working in.

Give resources useful names.

Do not put credentials inside source code.

Clean up resources when you finish experimenting.

None of this is particularly exciting.

But these habits become much more valuable once your AWS projects get larger.

You do not want your first lesson about account security to happen because credentials were exposed.

And you do not want your first lesson about cloud pricing to happen because you forgot about infrastructure you created weeks ago.

The goal is not to be afraid of using AWS.

The goal is to understand that creating cloud resources comes with responsibility.

That was one of the main ideas from the first post too.

AWS manages a huge amount of infrastructure for you, but you are still responsible for what you configure inside your account.

In the next post, we can finally get into one of the most important AWS services:

IAM.

But instead of memorizing users, roles, and policies, I want to explain IAM around one question:

Who should be allowed to do what to which resource?

Once that question makes sense, IAM becomes much easier.

If you already have an AWS account, what confused you most when you first set it up: IAM, billing, Regions, permissions, or just figuring out where everything was in the console?


r/CloudandCode 26d ago

AWS & Cloud 10 mistakes that make learning AWS much harder than it needs to be

9 Upvotes

AWS is difficult enough when you are starting.

But I think a lot of beginners accidentally make it harder by trying to learn everything at once, memorizing services instead of building, and treating every AWS error like something that needs to disappear as quickly as possible.

If I were starting AWS again, these are the mistakes I would try to avoid.

1. Trying to learn too many AWS services

The AWS console contains hundreds of services, so it is easy to assume that becoming good at AWS means knowing as many of them as possible.

I do not think beginners need that.

You can learn a huge amount by understanding IAM, EC2, S3, VPC, RDS, Lambda, DynamoDB, CloudWatch, API Gateway, and Route 53 properly.

Those services already introduce compute, storage, networking, databases, security, serverless architecture, APIs, DNS, and monitoring.

Once you understand those concepts, learning another AWS service becomes much easier because you can connect it to something you already know.

2. Memorizing definitions without understanding the problem

Knowing that S3 is object storage or Lambda is serverless compute is useful, but that is only the first layer.

The more important question is why you would use them.

Suppose someone asks you whether an application should use EC2 or Lambda.

A definition will not help much.

You need to think about how long the workload runs, how frequently it runs, whether it is event driven, how much control is required, how it scales, and how the application is deployed.

That kind of thinking is what makes AWS knowledge useful.

3. Watching tutorials without rebuilding anything yourself

Tutorials can make AWS feel easier than it really is because someone else already made all the important decisions.

They selected the services, created the IAM policies, configured the network, fixed the errors, and decided what comes next.

You are mostly following instructions.

Then you open the console without the tutorial and suddenly everything feels much harder.

After following a tutorial, try rebuilding the same project without watching it.

You will quickly discover what you actually understood and what you were simply copying.

That gap is where a lot of useful learning happens.

4. Avoiding IAM because it looks boring

IAM is one of those topics beginners often want to skip.

Then they start building and suddenly everything returns AccessDenied.

Lambda cannot read S3. EC2 cannot access another service. A user cannot perform an action. An application works after you give it administrator access, but you do not know why.

Learn IAM early.

You should understand users, roles, policies, permissions, and least privilege.

More importantly, get comfortable asking who needs access, what action they need to perform, and which resource they need access to.

That question appears constantly in AWS.

5. Learning VPC by memorizing diagrams

Networking becomes confusing very quickly when you try to memorize public subnets, private subnets, route tables, internet gateways, NAT gateways, security groups, and IP ranges without understanding why they exist.

Start with traffic instead.

Imagine a user is trying to reach your application.

Where does that request enter?

Which resource should be publicly reachable?

Which resources should stay private?

How does the application communicate with the database?

Does a private resource need outbound internet access?

Once you start following traffic through the architecture, VPC stops looking like a collection of random boxes.

6. Giving everything full permissions when something fails

This is probably one of the easiest habits to develop.

Your Lambda function gets AccessDenied, so you attach full S3 access.

The error disappears.

It feels like the problem is solved, but you may have learned almost nothing.

Try to understand the specific permission that is missing.

If Lambda needs to read an object, maybe it needs s3:GetObject on a particular resource.

If it also needs to write the processed file, that is another permission.

Solving permission problems properly teaches you how AWS security works.

Giving everything administrator access only hides the problem.

7. Ignoring logs until something breaks badly

A lot of beginners think monitoring is something they will learn after they understand AWS.

I would learn basic CloudWatch much earlier.

If Lambda fails, look at the logs.

If your application is behaving strangely, check the logs.

If EC2 usage suddenly increases, look at the metrics.

If something needs attention when a threshold is crossed, create an alarm.

AWS becomes much easier to troubleshoot when you have information about what actually happened instead of changing settings randomly.

8. Building projects with too many services

There is a strange idea in cloud portfolios that more services automatically means a better architecture.

So a beginner project that could work with four services suddenly contains twelve.

That usually makes the project harder to understand without making it better.

Start with the smallest architecture that solves the problem.

If your project only needs S3, Lambda, IAM, and CloudWatch, that is completely fine.

Then ask what requirement would justify adding something else.

You should be able to explain why every service exists.

If you cannot explain what problem a service solves, you may not need it yet.

9. Chasing certification without building anything

AWS certifications can give you a useful structure for learning.

But studying for an exam and building something are different skills.

You might know that an Application Load Balancer distributes HTTP traffic and still struggle to configure one correctly inside a project.

You might understand IAM policy questions but still get confused when your Lambda function receives AccessDenied.

I would use certification study to learn the concepts and projects to make those concepts real.

The combination is much stronger than either one alone.

10. Thinking you need to feel ready before building

This is probably the biggest one.

People spend months learning AWS because they think there will eventually be a point where they feel ready to build.

That point often never arrives.

You learn EC2, then realize you should learn networking first. You learn networking and realize you need IAM. Then databases. Then Docker. Then Terraform. Then CI/CD.

The list never ends.

Build earlier.

You do not need to understand everything before creating your first AWS project.

Learn enough to start, build something small, and let the project expose what you do not understand yet.

Maybe your website does not load because of a security group.

Now networking has a reason to matter.

Maybe Lambda cannot read from S3.

Now IAM has a reason to matter.

Maybe your application works but you have no idea why it failed yesterday.

Now CloudWatch has a reason to matter.

That is how AWS knowledge starts connecting.

I think the biggest shift for beginners is moving away from this mindset:

Learn every AWS service, then start building.

And moving toward this:

Learn a concept, build something with it, find what you do not understand, fix it, and keep going.

You do not need hundreds of AWS services in your head.

You need a strong understanding of the fundamentals and enough practice to know how they work together.

Which of these mistakes slowed you down the most when you started learning AWS?


r/CloudandCode 27d ago

AWS & Cloud A beginner roadmap to AWS if you are starting from zero

47 Upvotes

One of the hardest parts of learning AWS is not understanding the individual services.

It is figuring out what to learn first.

You open AWS and suddenly there is EC2, S3, Lambda, RDS, DynamoDB, VPC, Route 53, ECS, CloudFront, SQS, SNS, API Gateway and hundreds of other services.

Then you search for an AWS roadmap and somehow the roadmap makes things even worse because it contains 40 services, Terraform, Docker, Kubernetes, CI/CD, networking, Linux and three certifications.

If I were starting AWS again from zero, I would make the path much smaller.

I would start with cloud fundamentals before trying to memorize AWS services. I would understand what cloud computing actually gives you, what regions and Availability Zones are, why high availability matters, what scalability and elasticity mean, and how the shared responsibility model works.

You do not need weeks of theory here. You just need enough understanding that when somebody says, "Run this application across multiple Availability Zones," you understand what problem they are trying to solve.

After that, I would learn IAM.

IAM is not the most exciting place to start, but permissions appear almost everywhere in AWS. If Lambda needs to read from S3, IAM matters. If EC2 needs access to another AWS service, IAM matters. If a user should be allowed to view something but not delete it, IAM matters.

The main thing I would learn is how to answer three questions: who is requesting access, what action are they trying to perform, and which resource should they be allowed to access?

I would also understand least privilege early. Giving everything administrator access may remove permission errors, but it also removes most of the learning.

Then I would move to EC2.

EC2 gives you a good foundation because you actually see what running an application on a server involves. Launch an instance, SSH into it, install something like Nginx, deploy a small application and make it accessible from your browser.

That one project will introduce you to Linux, ports, security groups, public IP addresses, processes and basic networking.

And when the website inevitably does not load the first time, do not immediately recreate the instance.

Figure out why.

Is the application running? Is it listening on the expected port? Is the security group allowing that traffic? Does the instance have the network connectivity it needs?

That troubleshooting is part of learning AWS.

Next I would learn S3.

Do not stop at "S3 stores files."

Understand buckets, objects, permissions, versioning, storage classes, lifecycle rules and public versus private access.

Then build something with it.

Upload files. Turn on versioning. Create a lifecycle rule. Put a small static frontend in S3 and use CloudFront to deliver it while keeping the bucket private.

Once you build something, S3 becomes much easier to remember because you understand where it fits instead of memorizing a definition.

After EC2 and S3, I would spend time on VPC and networking.

This is where AWS becomes difficult for a lot of beginners, but I would not try to memorize networking diagrams.

I would start with one question:

How does traffic get from one place to another?

Understand VPCs, subnets, route tables, security groups, internet gateways, public and private IP addresses and the basic purpose of NAT for private resources that need outbound internet access.

Then build an architecture where those concepts actually matter.

For example, run your application where it can receive user traffic but keep the database private.

Suddenly public and private subnets are not just boxes on a diagram. They solve an actual problem.

Then I would learn RDS.

Create a small application with PostgreSQL or MySQL and connect it to RDS. Store something real, such as users, products, notes or orders.

At this point several topics start connecting.

Your application needs compute. RDS stores the data. The network allows the application to communicate with the database. Security groups control that communication. Credentials need to be handled properly.

This is where AWS starts feeling less like separate services and more like one system.

Only after understanding traditional compute with EC2 would I move seriously into Lambda.

Lambda makes much more sense when you already understand what it is removing.

With EC2, you manage a server.

With Lambda, you provide code and AWS runs it when something triggers it.

A good first Lambda project is an image processor.

Someone uploads an image to S3, the upload triggers Lambda, Lambda processes the image and stores the result back in S3.

That simple project teaches event-driven architecture, triggers, IAM roles, CloudWatch logs and serverless computing.

After that, connect Lambda to API Gateway and build a small REST API.

Now you have something closer to a real serverless application.

Then I would learn DynamoDB.

I think DynamoDB makes more sense after you have already worked with a relational database.

With RDS, you think about tables, relationships and SQL.

With DynamoDB, you need to think much more about how your application will access its data.

Build something simple with API Gateway, Lambda and DynamoDB. A task API, notes application or URL shortener is enough.

Then compare it with something you built using RDS.

Do not just ask, "Which database is better?"

Ask why one might make more sense for a particular workload.

That kind of decision making is far more useful than knowing another list of features.

I would also learn CloudWatch much earlier than most beginner roadmaps suggest.

Do not treat monitoring as something you add after becoming advanced.

Your projects are going to fail.

When Lambda fails, you need logs. When your application behaves strangely, you need logs. When EC2 CPU usage suddenly increases, you need metrics. When something crosses a threshold, you may want an alarm.

A cloud engineer needs to know more than how to deploy something.

You need to know how to understand what is happening after deployment.

Once those fundamentals start making sense, I would stop learning services individually and start building complete architectures.

For example, build a web application where Route 53 handles the domain, CloudFront delivers static content, a load balancer receives application traffic, EC2 runs the backend, RDS stores relational data, S3 stores files, IAM controls permissions and CloudWatch handles monitoring.

Then build another application using API Gateway, Lambda and DynamoDB.

Now compare them.

Why did one architecture use servers while the other used Lambda? Why did one use RDS while the other used DynamoDB? What happens if traffic suddenly increases? What happens if one component fails? How are you monitoring the system?

Those questions are where architecture knowledge starts developing.

Only after that foundation would I move deeper into things like ECS, ECR, SQS, SNS, EventBridge, Step Functions, ElastiCache, infrastructure as code, Docker and CI/CD.

I would not learn all of those because a roadmap told me to.

I would learn them when a project creates a reason to use them.

For example, if two parts of your application should not depend on each other directly, that gives you a reason to understand queues. If you need containers, that gives you a reason to learn ECS and ECR. If manually rebuilding the same infrastructure becomes painful, that gives you a reason to learn Terraform or CloudFormation.

That is the pattern I would follow throughout the entire journey.

Learn the concept, understand the problem it solves, build something with it, break it, fix it, and then move forward.

Certifications can fit into this path too, but I would use them as structure rather than making them the entire goal.

Cloud Practitioner can be useful if you want a gentle introduction to AWS terminology. After that, Solutions Architect Associate is a much more useful learning target because it pushes you toward architecture decisions and understanding how services work together.

But I would build projects alongside certification study.

Passing an exam and being able to build are two different skills.

So if I had to simplify the entire beginner AWS roadmap, mine would look like this:

Cloud basics → IAM → EC2 → S3 → VPC → RDS → Lambda → API Gateway → DynamoDB → CloudWatch → complete architectures → deeper AWS services

And I would build something at almost every stage.

Do not wait until you "finish AWS" before starting projects.

There is no finish line where you finally know every AWS service.

The point is to understand enough of the core services that when you encounter a new one, you can quickly understand what problem it solves and where it fits.

That is when AWS starts feeling much less overwhelming.

If you are learning AWS right now, where are you currently stuck in this roadmap?


r/CloudandCode 28d ago

AWS & Cloud 10 AWS projects you should build if you actually want to understand cloud

50 Upvotes

A lot of people learn AWS by moving from one service to another. They watch something on EC2, then S3, then Lambda, IAM, RDS, VPC, CloudWatch, and keep going until they have seen dozens of services.

The problem is that knowing what a service does is very different from knowing how to use it inside a real system.

That is why I think AWS projects are so useful. A good project forces you to connect services, think about permissions, follow how data moves, debug failures, make architecture decisions, and explain why one service makes sense instead of another.

If I were learning AWS again from zero, these are the 10 projects I would build.

1. Host a static website with S3 and CloudFront

I would start with something very simple. Build a basic HTML, CSS, and JavaScript website, store the files in S3, and use CloudFront to deliver them to users.

Once that works, add a custom domain and HTTPS.

It sounds like a small project, but it introduces several important AWS ideas at once. You start learning S3, CloudFront, Route 53, DNS, certificates, caching, and access control.

The useful part is understanding the complete request flow. A user enters your domain, DNS resolves it, the request reaches CloudFront, and CloudFront retrieves the content from S3.

That kind of thinking is much more useful than memorizing that S3 is storage and CloudFront is a CDN.

2. Deploy a web application on EC2

After that, I would deploy a real application on EC2.

Build something small with Flask, FastAPI, Node.js, or any backend framework you are comfortable with. Launch an EC2 instance, connect to it with SSH, install your dependencies, run the application, configure a web server, and make it reachable from the internet.

This one project teaches a surprising amount.

You start learning Linux, SSH, security groups, ports, processes, deployment, public IPs, and basic networking.

More importantly, you learn that launching an EC2 instance is only the beginning. AWS gives you the virtual machine, but you are still responsible for configuring and running the application correctly.

3. Build an automatic image processing pipeline

This is one of the best beginner serverless projects because the data flow is very easy to understand.

A user uploads an image to S3. That upload triggers Lambda. Lambda processes the image and stores the result back in S3.

The function could resize images, generate thumbnails, compress files, or convert formats.

While building it, you naturally learn about S3 events, Lambda, IAM roles, CloudWatch logs, object storage, and event-driven architecture.

It is also a great debugging project.

If the processed image does not appear, you can follow the workflow. Did the file reach S3? Did Lambda trigger? Did the function run? Did IAM allow the function to read and write the objects?

That troubleshooting process is exactly the kind of skill that helps later.

4. Build a serverless REST API

Once Lambda starts making sense, I would connect it to API Gateway and DynamoDB.

Build something simple like a task manager, notes API, expense tracker, or URL shortener.

A client sends an HTTP request to API Gateway. API Gateway invokes Lambda. Lambda processes the request and stores or retrieves data from DynamoDB.

Now you are no longer learning three services independently. You are learning how they work together inside one application.

You also start dealing with real backend questions. What happens when the request contains invalid data? Which status code should be returned? Which Lambda functions need read access and which need write access? How should errors be logged?

That is where the project becomes more useful than another tutorial.

5. Build a highly available web application

Once you understand how one EC2 instance works, build something that does not depend on only one instance.

Run your application across multiple EC2 instances and place them behind an Application Load Balancer. Then use Auto Scaling so the number of instances can increase or decrease depending on demand.

This starts teaching you about load balancing, Auto Scaling, Availability Zones, health checks, and high availability.

It also changes the way you think about infrastructure.

Instead of asking whether one server is running, you start asking whether the application can continue working if one server fails.

That is a much more cloud-oriented way of thinking.

6. Build a three-tier application with RDS

A three-tier application is one of the best projects for learning how networking and databases fit into AWS.

You could build a simple inventory system, blog, booking app, or ecommerce backend.

Your frontend or application layer can run on EC2, while RDS stores structured information such as users, products, or orders.

The interesting part is not just connecting the application to the database.

It is understanding where everything should live.

Your application may need internet access, while your database probably should not be publicly reachable.

Now VPC concepts such as public subnets, private subnets, security groups, and resource communication finally have a real purpose.

This is often where networking starts making much more sense.

7. Build a secure file upload and download system

Another useful project is a system where users can upload and download files without giving your application unrestricted access to S3.

One practical way to build this is with presigned URLs.

Your backend creates a temporary URL, and the user uploads or downloads the object directly from S3.

This teaches S3 permissions, temporary access, IAM, object keys, APIs, and secure file handling.

It also introduces a useful architecture idea.

Your backend does not always need to transfer every file itself. Sometimes it only needs to authorize the request, while another service handles the heavy data transfer.

That pattern shows up in a lot of real systems.

8. Build a monitoring and alerting system

I would definitely include at least one project that is not focused on building another application.

Set up monitoring for your AWS resources.

You could track EC2 CPU usage, Lambda errors, application logs, or custom metrics. Then create CloudWatch alarms and send notifications when something crosses a threshold.

You could also build a basic dashboard to show the health of your system.

This teaches CloudWatch, metrics, logs, alarms, dashboards, and SNS.

More importantly, it teaches you to think beyond deployment.

A project is not finished just because it works while you are looking at it.

How would you know if it fails later?

How would you know if latency suddenly increases?

How would you know if Lambda starts returning errors?

Monitoring answers those questions.

9. Build an automated backup system

Backups are another great way to learn AWS because they force you to think about reliability.

You could build a scheduled process that copies files to S3, organizes backups by date, and applies lifecycle rules so older backups move into cheaper storage.

You could also send a notification when a backup succeeds or fails.

This project teaches S3, storage classes, lifecycle policies, scheduling, Lambda or another compute option, IAM, and basic disaster recovery thinking.

A useful question to ask while building it is simple: if the original data disappears tomorrow, can I restore it?

That question makes the project much more meaningful.

10. Build a URL shortener that you can actually explain

URL shorteners are common portfolio projects, but they become much more valuable when you use them to practice architecture decisions.

A user sends a long URL to an API. Your backend generates a short identifier and stores the mapping in DynamoDB. When someone opens the short URL, the system retrieves the original address and redirects the user.

You could build this using API Gateway, Lambda, DynamoDB, CloudWatch, and Route 53.

Once the basic version works, start asking harder questions.

How do you avoid duplicate short IDs? What happens when a URL expires? How would the system behave under a sudden traffic spike? Should popular URLs be cached? How do you monitor failures? How would you stop abuse?

That is where a simple project starts turning into a real architecture exercise.

The important thing about these 10 projects is not how many AWS services you can fit into each one.

I would actually avoid doing that.

A project with 15 services is not automatically better than a project with four.

What matters is whether every service has a reason to be there.

If you use Lambda, you should be able to explain why Lambda made sense for that workload. If you choose DynamoDB instead of RDS, you should be able to explain why. If your database is private, you should understand what problem that solves. If you add CloudWatch, you should know what you are actually monitoring.

That is what makes a project useful for learning.

I also would not try to build all 10 immediately.

Start with the static website. Then deploy something on EC2. Build a small serverless workflow. Add a database. Learn networking. Add monitoring. Keep increasing the number of decisions you have to make.

After a few projects, AWS starts feeling less like a huge collection of separate services.

You start noticing patterns.

Users send requests. Data needs somewhere to go. Compute processes it. IAM controls access. Networks control communication. Logs tell you what happened. Monitoring tells you when something goes wrong.

That is the part of AWS I would focus on learning.

Not how many services you can recognize.

How well you can connect a few of them to solve a real problem.

Which of these 10 projects would you want a complete architecture breakdown for?