How I Deployed an App to AWS Using CI/CD + Terraform


As a DevOps and cloud enthusiast, I wanted to go beyond theoretical knowledge and create something real. In this post, I’ll walk through how I deployed a Dockerized application on AWS using Terraform and GitHub Actions. This project helped me apply core DevOps practices and build a production-ready pipeline.
Overview of the Stack
Terraform for infrastructure provisioning
EC2 for hosting the app
Docker to containerize the application
GitHub Actions for CI/CD
SCP + SSH for deployment automation
Step 1: Infrastructure as Code with Terraform
I started by defining all infrastructure in Terraform to make deployments consistent and version-controlled. The configuration included:
An EC2 instance with a public IP
A security group allowing SSH (22), HTTP (80), and app port (4000)
Optional Elastic Load Balancer for scalability
By writing reusable Terraform modules, I was able to spin up the environment with a single command.
Step 2: Dockerizing the Application
The app I deployed was a simple Node.js server. I created a Dockerfile
to containerize it:
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 4000
CMD ["node", "app.js"]
Containerization ensured the app would run identically across development and production.
Step 3: CI/CD Pipeline with GitHub Actions
Next, I automated the build and deployment process using GitHub Actions. On every push to main
, the pipeline:
Checked out the latest code
Established SSH access to the EC2 instance
Transferred files using
scp
Remotely built and ran the Docker container
Here’s a simplified snippet of the deploy.yml
workflow:
name: Deploy to EC2
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up SSH
run: |
echo "${{ secrets.EC2_SSH_KEY }}" > key.pem
chmod 600 key.pem
- name: Deploy and Restart App
run: |
scp -i key.pem -r . ubuntu@${{ secrets.EC2_HOST }}:/home/ubuntu/app
ssh -i key.pem ubuntu@${{ secrets.EC2_HOST }} '
cd app &&
docker build -t myapp . &&
docker stop myapp || true &&
docker rm myapp || true &&
docker run -d -p 4000:4000 --name myapp myapp
'
Secrets like EC2_SSH_KEY
and EC2_HOST
were stored securely in GitHub.
Step 4: Live Demo
After deployment, I could access the app at:
http://<EC2_PUBLIC_IP>:4000
Everything was running in the cloud with CI/CD automatically pushing updates on every commit.
Key Takeaways
Terraform makes infrastructure reproducible and scalable
Docker simplifies app deployment
GitHub Actions is powerful for automating delivery
Clean
.env
and.env.example
handling is crucial for secretsReal projects accelerate learning far more than passive tutorials
What’s Next
I plan to add CloudWatch monitoring and explore serverless patterns. I’m also expanding my portfolio with projects like:
Static site hosting on S3 + CloudFront
Auto-scaling EC2 groups
Secrets management with AWS SSM
Code and Demo
GitHub Repository: CI/CD Pipeline Project
Live App:
http://<your-ec2-ip>:4000
(replace with your IP)
Let’s Connect
If you’re a solo developer or early-stage startup looking to deploy to AWS with CI/CD and infrastructure automation, I can help.
Email: deykaustav357@gmail.com
Portfolio: Kaustav Dey DevOps & Cloud Specialist | AWS • Docker • Terraform • CI/CD
Subscribe to my newsletter
Read articles from Kaustav Dey directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
