AWS Builder Center

From Localhost to the Cloud: Deploying a Full-Stack Application on AWS

Learn how a full-stack application can move from a local development environment to a scalable AWS architecture using services such as Amazon EC2, Amazon RDS, Amazon S3, Elastic Load Balancing, and Amazon CloudWatch. This article explores the role of each service and the architectural decisions behind a reliable cloud deployment.

From Localhost to the Cloud: Deploying a Full-Stack Application on AWS

Building an application locally is only the beginning.
During development, everything may run perfectly on a single computer: the frontend communicates with the backend through localhost, the database runs locally, files are stored on the same machine, and logs appear directly in the terminal.
Then comes an important question:
How does this application become a real cloud application?
Moving from localhost to the cloud is not simply about uploading code to a server. It requires thinking about infrastructure, networking, databases, storage, security, monitoring, availability, and scalability.
In this article, I will explore how a traditional full-stack application could be structured on AWS using services such as Amazon EC2, Amazon RDS, Amazon S3, Elastic Load Balancing, and Amazon CloudWatch.
The objective is not to define the only possible architecture, but to understand the responsibilities of the main components involved in a cloud deployment.

Starting with a Traditional Application

Imagine a simple web application with three main components:
1
2
3
4
5
6
7
Frontend
|
v
Backend API
|
v
Database
During development, this could mean:
1
2
3
4
5
6
7
Browser
|
v
localhost:8080
|
v
Local PostgreSQL
This architecture is perfectly reasonable for development.
However, localhost only exists on the developer’s machine.
For real users to access the application, these components need infrastructure that is available through a network.
This is where cloud computing changes the architecture.

A First AWS Architecture

One possible AWS architecture could be:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Internet
|
v
Application Load Balancer
|
v
Amazon EC2
|
Backend API
/ \
v v
Amazon RDS Amazon S3
|
v
Amazon CloudWatch
Each component solves a different problem.
Amazon EC2 provides compute capacity.
Amazon RDS manages the relational database.
Amazon S3 stores objects and static files.
Elastic Load Balancing distributes incoming traffic.
Amazon CloudWatch provides monitoring and observability.
Let’s understand why separating these responsibilities matters.

Amazon EC2: Running the Application

Amazon Elastic Compute Cloud, or Amazon EC2, provides virtual computing capacity in AWS.
For a traditional backend application, an EC2 instance can run the application server.
For example, imagine a Java backend that produces a JAR file.
Conceptually, the deployment could involve:
1
2
3
4
5
6
7
8
9
10
11
12
13
Source Code
|
v
Build Application
|
v
application.jar
|
v
Amazon EC2
|
v
Java Application
The EC2 instance becomes the environment where the backend executes.
This immediately introduces several considerations that did not exist when everything ran locally.
Which instance type should be used?
Which ports should be accessible?
How will the application receive configuration?
How will new versions be deployed?
What happens if the instance becomes unavailable?
These questions demonstrate an important idea:
Deploying an application is not the same as designing a reliable architecture.

Amazon RDS: Moving the Database Out of the Application Server

A beginner cloud architecture might place the application and database on the same virtual machine.
Technically, that can work.
Architecturally, however, separating them usually provides important advantages.
Amazon Relational Database Service, or Amazon RDS, is a managed service for relational databases.
It supports database engines such as PostgreSQL and MySQL.
Instead of:
1
2
3
EC2
├── Backend
└── PostgreSQL
we can separate the components:
1
2
3
4
EC2
|
v
Amazon RDS
This separation makes each component easier to manage independently.
The application server handles application logic, while RDS handles the relational database.
It also reduces the amount of database infrastructure that developers need to manage directly.

Security Groups and the Database

Moving the database to the cloud introduces an important security question.
Should the database be publicly accessible from anywhere on the internet?
For most application architectures, the answer should be no.
The backend needs database access, but normal users do not.
Conceptually:
1
2
3
4
5
6
7
User
|
v
Application
|
v
Database
Not:
1
User ------> Database
AWS Security Groups can help control network traffic between resources.
For example, the database security group can be configured to accept database traffic from the application layer instead of exposing database access broadly.
This introduces one of the most important principles in cloud security:
Only provide the access that is actually required.
The same principle applies to IAM permissions and other AWS resources.

Amazon S3: Files Are Different from Database Records

Suppose the application allows users to upload:
  • profile pictures;
  • documents;
  • product images;
  • reports;
  • attachments.
One approach would be storing every file directly on the EC2 instance.
However, this creates a problem.
If the application eventually runs on multiple instances, which server owns the file?
Imagine this architecture:
1
2
3
4
Load Balancer
/ \
v v
EC2 #1 EC2 #2
If a file exists only on EC2 #1 and the next request reaches EC2 #2, the architecture becomes difficult to manage.
Amazon S3 provides object storage that can exist independently from individual application servers.
Now both instances can interact with the same storage service:
1
2
3
4
5
EC2 #1 ----\
\
> Amazon S3
/
EC2 #2 ----/
This is an important architectural improvement.
Application servers become less responsible for maintaining persistent local state.

Why Stateless Applications Matter

A useful concept in scalable architectures is making application instances as stateless as reasonably possible.
Consider two users:
1
2
User A ---> EC2 #1
User B ---> EC2 #2
If all critical application state exists only inside individual servers, distributing requests becomes difficult.
Instead, persistent data can live in dedicated services:
1
2
3
4
5
Application Data -> Amazon RDS

Files -> Amazon S3

Application Instances -> Amazon EC2
The EC2 instances focus primarily on executing application logic.
This makes horizontal scaling much easier.

Elastic Load Balancing: One Application, Multiple Instances

Initially, the application might only require one EC2 instance.
As traffic grows, one instance may no longer be enough.
Instead of replacing it with an increasingly powerful machine, another strategy is horizontal scaling.
For example:
1
2
3
4
5
6
7
Users
|
v
Application Load Balancer
/ | \
v v v
EC2 #1 EC2 #2 EC2 #3
The Application Load Balancer distributes incoming requests among available targets.
This also improves architecture beyond pure performance.
If one application instance becomes unavailable, requests can potentially be directed toward healthy instances instead.
This leads to another important lesson:
Scalability and availability are closely connected to architecture.

Vertical vs. Horizontal Scaling

There are two useful ways to think about scaling.

Vertical Scaling

Increase the resources of one machine.
1
2
3
4
Small EC2
|
v
Larger EC2
This is simple, but a single machine still has limits.

Horizontal Scaling

Increase the number of application instances.
1
EC2
becomes:
1
EC2 + EC2 + EC2
Horizontal scaling is one reason stateless application design becomes valuable.
If application instances depend heavily on their own local state, adding and removing instances becomes much more complicated.

Auto Scaling

Once multiple instances are possible, another question appears:
Do we need the same amount of infrastructure all the time?
Probably not.
Traffic can change throughout the day.
An application might receive relatively little traffic during one period and significantly more traffic later.
Amazon EC2 Auto Scaling can help adjust the number of instances according to configured policies and application requirements.
Conceptually:
1
2
3
4
5
6
7
8
9
Low Traffic
EC2 #1

↓ traffic increases

High Traffic
EC2 #1
EC2 #2
EC2 #3
Later, capacity can decrease again when appropriate.
This introduces elasticity, one of the fundamental characteristics associated with cloud computing.

Amazon CloudWatch: Knowing What Is Happening

Deploying an application successfully does not mean the work is finished.
Consider a user reporting:
“The application is slow.”
Where is the problem?
It could be:
  • the application;
  • the database;
  • an external API;
  • infrastructure capacity;
  • a specific endpoint;
  • an unexpected error.
Without observability, developers are largely guessing.
Amazon CloudWatch provides capabilities for monitoring AWS resources and applications through metrics, logs, alarms, and related observability features.
Instead of asking only:
“Is the server running?”
we can start asking:
“How is the application behaving?”
For example, teams may monitor:
1
2
3
4
5
CPU Utilization
Request Count
Response Errors
Application Logs
Database Metrics
Monitoring becomes even more important as the architecture grows.

What Happens When the Application Fails?

Failure should be considered during architecture design rather than only after an incident occurs.
Suppose the architecture contains only:
1
2
3
4
User
|
v
EC2
If that instance fails, the application may become unavailable.
Now consider:
1
2
3
4
Load Balancer
/ \
v v
EC2 #1 EC2 #2
The architecture has another application instance available.
This does not magically make every application highly available. Databases, networking, deployment strategies, dependencies, and other components still need to be designed appropriately.
But redundancy is an important part of reducing single points of failure.

Configuration and Secrets

Another common mistake when moving applications to the cloud is hardcoding credentials directly into source code.
For example:
1
2
DB_PASSWORD=my-password
AWS_ACCESS_KEY=...
Sensitive credentials should not be committed to a public Git repository.
AWS provides services and mechanisms for managing configuration and secrets more safely.
Applications running on AWS can also use IAM roles where appropriate instead of storing long-lived AWS credentials inside the application.
This improves both security and maintainability.

IAM and Least Privilege

Imagine the application only needs to upload images to one specific S3 bucket.
Does it need administrative access to the entire AWS account?
No.
AWS Identity and Access Management allows permissions to be defined for users, roles, and resources.
A useful principle is least privilege:
Give an application only the permissions required to perform its responsibilities.
If the backend only needs specific S3 operations, its permissions should reflect that limited requirement.
The same thinking applies to databases, monitoring, deployment automation, and other AWS services.

Automating Deployment

Manually connecting to a server and replacing files can work during early experiments.
But as an application evolves, deployment should become repeatable.
A basic software delivery workflow could be:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Developer
|
v
Git Repository
|
v
Build
|
v
Tests
|
v
Deploy
|
v
AWS Environment
This is where CI/CD practices become valuable.
Instead of deployment being a sequence of manual steps remembered by one developer, it becomes an automated process.
Automation reduces inconsistencies and makes frequent deployments easier to manage.

Infrastructure as Code

There is another part of the application that can be versioned: the infrastructure itself.
Instead of manually creating every resource through a graphical interface, Infrastructure as Code allows infrastructure to be described through configuration or code.
AWS CloudFormation is one AWS option for defining infrastructure.
This changes the infrastructure workflow from:
1
2
3
4
5
Click
Configure
Click
Create
Remember Settings
to something closer to:
1
2
3
4
5
6
7
Infrastructure Definition
|
v
Version Control
|
v
AWS Resources
This can make environments easier to reproduce and review.

Thinking About Cost

Cloud architecture also requires cost awareness.
A technically impressive architecture is not necessarily an efficient architecture.
For a small project with almost no users, immediately creating many large instances may be unnecessary.
At the same time, choosing infrastructure only because it appears inexpensive can create reliability or performance problems.
The architecture should reflect actual requirements.
Important questions include:
  • How many users are expected?
  • How much traffic will the application receive?
  • How much data will be stored?
  • Does the application need high availability?
  • Which resources run continuously?
  • Which resources can scale according to demand?
Cost should be treated as an architectural constraint, not as an afterthought.

The Evolution of the Architecture

We started with:
1
2
3
4
5
6
7
Browser
|
v
localhost
|
v
Local Database
A cloud architecture could eventually evolve toward:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Internet
|
v
Application Load Balancer
|
+---------+---------+
| |
v v
EC2 #1 EC2 #2
| |
+---------+---------+
|
+---------+---------+
| |
v v
Amazon RDS Amazon S3

|
v
Amazon CloudWatch
Additional capabilities can then be introduced according to the application’s actual requirements:
1
2
3
4
5
6
7
Auto Scaling
IAM
Secrets Management
CI/CD
Infrastructure as Code
Backups
Observability
The important part is that these services should not be added simply because they exist.
Each service should solve a specific architectural problem.

What I Learned from Thinking Beyond Localhost

The biggest difference between local development and cloud architecture is not the programming language.
The application code may remain very similar.
What changes is the environment around it.
A cloud application forces developers to think about questions such as:
  • Where should persistent data live?
  • What happens when a server fails?
  • How should files be stored?
  • Who can access each resource?
  • How can the application scale?
  • How do we know when something goes wrong?
  • How can deployments become repeatable?
  • How much will the architecture cost?
These questions move software development beyond simply making the code work.
They introduce the broader discipline of software and cloud architecture.

Conclusion

Moving an application from localhost to AWS is much more than putting code on a virtual machine.
A well-structured cloud application separates responsibilities.
Amazon EC2 can provide compute capacity, Amazon RDS can manage relational data, Amazon S3 can provide object storage, Elastic Load Balancing can distribute traffic, and Amazon CloudWatch can help developers understand how the environment is behaving.
IAM, security groups, Auto Scaling, CI/CD, and Infrastructure as Code can further improve the architecture as requirements grow.
Perhaps the most important lesson is that cloud services should not be added simply to make an architecture look sophisticated.
Every component should answer a question.
What problem does this service solve?
Understanding that question is one of the first steps toward moving from simply deploying applications to actually designing cloud systems.

This article presents an educational AWS architecture. Production systems should be designed according to their specific security, availability, performance, compliance, backup, and cost requirements.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article