DEV Community

Cover image for From Silent Failures to Reliable Deployments: Building a Two-Tier AWS Architecture with Terraform
Chioma Nwosu
Chioma Nwosu

Posted on

From Silent Failures to Reliable Deployments: Building a Two-Tier AWS Architecture with Terraform

Deploying applications in the cloud is often presented as a straightforward process — provision infrastructure, deploy code, and everything works.

In reality, things rarely go that smoothly.

In this project, I built and deployed a two-tier web application on AWS using Terraform, automating everything from infrastructure provisioning to application setup. What made this experience truly valuable wasn’t just the final working system — it was the debugging journey that transformed a fragile deployment into a reliable one.

Project Overview

The goal was to deploy a full-stack application with:

Frontend & Backend: Node.js app running on EC2
Database: MySQL on Amazon RDS
Infrastructure: Provisioned entirely with Terraform
Automation: Bash user data script
Architecture

The system follows a classic two-tier architecture:

EC2 (Public Subnet): Hosts the application
RDS (Private Subnet): Stores application data
VPC: Custom networking environment
Security Groups: Control traffic between layers
What I Built
Custom VPC with public and private subnets
Internet Gateway and route tables
EC2 instance with automated setup
RDS MySQL instance in private subnets
Security groups enforcing least privilege
Nginx reverse proxy configuration
PM2 process management for Node.js

All of this was provisioned using Terraform, ensuring repeatability and consistency.

Automation with User Data

To eliminate manual setup, I used a user data script to:

Install dependencies (Node.js, Nginx, MySQL client)
Clone the application repository
Configure database connection dynamically
Run database schema and seed scripts
Start the application using PM2
Configure Nginx as a reverse proxy

This allowed the application to be fully configured on instance launch.

The Challenges (Real Learning Begins Here)

  1. Database Connection Failure

I encountered a SequelizeHostNotFoundError, which indicated that the application couldn’t resolve the RDS endpoint.

Fix:

Verified Terraform outputs
Ensured correct database host configuration

  1. Broken Application Due to JSON Error

The app crashed due to:

Unexpected string in JSON

Fix:

Corrected formatting issues in the configuration file

  1. The “Working” System with No Data

This was the most interesting issue.

Tables were created successfully
Application was running
But the Book table was empty

At first glance, everything looked correct.

The Root Cause

After deeper investigation, I discovered:

The seed script for books was not executed because of a misnamed file:

db/book_seed.sql ❌
db/books_seed.sql ✅

Because the user data script did not enforce failure, this error was silently ignored.

Key Insight

Automation without proper error handling can give a false sense of success.

Fixing the Problem

I implemented the following improvements:

✅ Corrected File Reference

Updated the script to point to the correct seed file.

✅ Fail-Fast Mechanism

Added:

set -e

This ensures the script stops immediately on failure.

✅ Logging for Debugging

Used:

/var/log/cloud-init-output.log

to trace execution and identify issues quickly.

Final Result

After fixing the issues and redeploying:

Infrastructure provisioned successfully
Application deployed automatically
Database fully populated
Application accessible via public IP
System fully repeatable with Terraform
Key Lessons Learned
Small mistakes (like file names) can break automation
Logs are essential for debugging cloud deployments
Always design scripts to fail loudly, not silently
Infrastructure as Code requires validation, not just execution
Troubleshooting is a core DevOps skill
Conclusion

This project reinforced that DevOps is not just about automation — it’s about building reliable, observable, and maintainable systems.

The difference between a beginner and an engineer isn’t avoiding errors — it’s understanding and fixing them effectively.

What’s Next
Adding CI/CD pipeline
Implementing monitoring and alerting
Improving deployment idempotency

Top comments (0)