Building a fully serverless application on AWS can feel overwhelming at first, but this hands-on project made the entire process clear, practical, and surprisingly enjoyable. In this guide, I walk through how I built HealthHub, a cloud-native healthcare appointment system powered by AWS Lambda, API Gateway, DynamoDB, Cognito, and a Vite-based frontend. From creating the VPC and EC2 workstation to deploying backend services with the Serverless Framework and finally launching the frontend app, this article documents every step — so you can follow along and build your own production-ready serverless project.
Step 1: Creating A VPC
Create a VPC (healthhub-vpc) in N. Virgina (us-east-1) region. The VPC should have a public subnet with an 'Internet GateWay (IGW)' for public access of the Workstation EC2 instance to be created next.
Step 2: Create An EC2 Instance WorkStation
Create an ec2 instance with the following attributes:
- Instance Type: t2.medium
- VPC: healthhub-vpc
- Subnet: public
- Assign Public IPV4 Address: True
- Ingress Ports Allowed:
- 22 (tcp, ssh)
- 5173 (tcp, app port)
Step 3: Create IAM Role For EC2 Instance
Create an IAM Role with the name hh-role. The role should be given AdministratorAccess.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
Step 4: Attach IAM Role to EC2 Instance
Attach the IAM Role hh-role with the EC2 Instance healthhub-workstation so that the instance can call out to all AWS services.
Step 5: Setting Up The WorkStation
Log in to the healthhub-workstation EC2 instance. And then check that the required packages are installed or not.
[ec2-user@ip-10-0-4-216 ~]$ aws --version
aws-cli/2.30.4 Python/3.9.24 Linux/6.1.158-178.288.amzn2023.x86_64 source/x86_64.amzn.2023
[ec2-user@ip-10-0-4-216 ~]$ node -v
-bash: node: command not found
[ec2-user@ip-10-0-4-216 ~]$ npm -v
-bash: npm: command not found
[ec2-user@ip-10-0-4-216 ~]$ serverless --version
-bash: serverless: command not found
Install the following dependencies:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install --lts
node -v
npm -v
npm install -g serverless@3
serverless --version
Here is the expected output:
[ec2-user@ip-10-0-4-216 ~]$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 16555 100 16555 0 0 758k 0 --:--:-- --:--:-- --:--:-- 808k
=> Downloading nvm as script to '/home/ec2-user/.nvm'
=> Appending nvm source string to /home/ec2-user/.bashrc
=> Appending bash_completion source string to /home/ec2-user/.bashrc
=> Close and reopen your terminal to start using nvm or run the following to use it now:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
[ec2-user@ip-10-0-4-216 ~]$ source ~/.bashrc
[ec2-user@ip-10-0-4-216 ~]$ nvm install --lts
Installing latest LTS version.
Downloading and installing node v24.11.1...
Downloading https://nodejs.org/dist/v24.11.1/node-v24.11.1-linux-x64.tar.xz...
######################################################################################################################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v24.11.1 (npm v11.6.2)
Creating default alias: default -> lts/* (-> v24.11.1)
[ec2-user@ip-10-0-4-216 ~]$ node -v
v24.11.1
[ec2-user@ip-10-0-4-216 ~]$ npm -v
11.6.2
[ec2-user@ip-10-0-4-216 ~]$ npm install -g serverless@3
npm warn deprecated lodash.get@4.4.2: This package is deprecated. Use the optional chaining (?.) operator instead.
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm warn deprecated querystring@0.2.1: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm warn deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm warn deprecated superagent@7.1.6: Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net
added 619 packages in 37s
134 packages are looking for funding
run `npm fund` for details
npm notice
npm notice New patch version of npm available! 11.6.2 -> 11.6.4
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.6.4
npm notice To update run: npm install -g npm@11.6.4
npm notice
[ec2-user@ip-10-0-4-216 ~]$ serverless --version
Framework Core: 3.40.0
Plugin: 7.2.3
SDK: 4.5.1
Step 6: Implementing The Application BackEnd
Download and install the HealthHub application backend and its dependencies with the following commands:
wget https://tcb-bootcamps.s3.us-east-1.amazonaws.com/aicloud-bootcamp/v1/module3/healthhub-module-3.zip
unzip healthhub-module-3.zip
cd healthhub-module-3/health-hub-backend/
npm install
for service in src/services/*; do (cd "$service" && npm install) done
To deploy the resources into AWS, run the following command:
npm run deploy
This will take a few minutes to deploy. Once deployed, go to AWS Console and check the stacks in CloudFormation.
Also check the following services:
- Cognito User Pools
- API Gateway Endpoints
- DynamoDB Tables
- Lambda Functions
- CloudWatch Logs
Step 7: Implementing The Application FrontEnd
Go to the health-hub-frontend directory and run the following command to install the necessary dependencies:
cd ../health-hub-frontend
npm install
Copy the .env.example file to .env and put the value of VITE_API_BASE_URL.
cp .env.example .env
nano .env
The URL can be found in API Gateway in the AWS Console.
Step 8: Run The Application
After setting up the API Key, run the application using the following command:
[ec2-user@ip-10-0-4-216 health-hub-frontend]$ npm run dev -- --host
> health-hub@0.0.0 dev
> vite --host
VITE v5.3.5 ready in 249 ms
➜ Local: http://localhost:5173/
➜ Network: http://10.0.4.216:5173/
➜ press h + enter to show help
Access the Health-Hub web application using your browser, enter the following IP address:
<Your-IP-Address>:5173
Then create two tests account, one for the doctor and one for the patient.
Log in as a patient and then book an appointment. Sign out and then log back in as a doctor to confirm that the appointment is properly booked.
Step 9: Cleaning Up Everything
Once done checking out the application and the related AWS Services that are running for the application, clean up using the following command:
cd health-hub-backend
sls remove
[ec2-user@ip-10-0-4-216 healthhub-module-3]$ cd health-hub-backend/
[ec2-user@ip-10-0-4-216 health-hub-backend]$ sls remove
Running "serverless" from node_modules
Removing stage dev
✔ user-service › removed › 12s
✔ appointment-service › removed › 37s
✔ doctor-service › removed › 32s
✔ patient-service › removed › 32s
[ec2-user@ip-10-0-4-216 health-hub-backend]$
The services might take a few minutes to get removed from AWS Console.
PS. Remember to delete the EC2 instance manually, otherwise it will charge extra cost.
✅ My Final Thoughts
This project taught me how to:
- Use Serverless Framework to orchestrate AWS resources
- Deploy a serverless backend (Lambda, DynamoDB, API Gateway)
- Build a Vite frontend hosted on S3
- Secure everything with Cognito
- Monitor with CloudWatch











Top comments (0)