Hey there π
Check it out here: GitHub Repository Link
So I've been working with Terraform for a while now, and honestly? It's been a love-hate relationship. More hate than love on some days, if I'm being real.
You know those moments when you're staring at your terminal at 2 AM because a state lock won't release? Or when you accidentally destroy half your infrastructure because you used count instead of for_each? Yeah, we've all been there. Or at least, I hope I'm not the only one.
Why I Built This
After going through the same painful issues over and over (and probably Googling "terraform circular dependency" more times than I'd like to admit), I decided to collect everything in one place. Not just theory or best practices that look good on paper I mean actual working code that you can copy and paste when things go wrong at 2 AM.
The repository includes:
Ready-to-use modules (VPC, EC2, RDS, S3, Security Groups)
Complete environment setups (dev, staging, production)
Real solutions to problems that actually happen
Scripts that make your life easier
A Makefile because who remembers all those commands anyway?
What's Inside
- The Modules You Actually Need Not the fancy stuff, just the basics done right:
VPC Module: Public/private subnets, NAT gateways, the whole setup
EC2 Module: Instances with proper security and monitoring
RDS Module: Database with encryption, backups, and auto-generated passwords
S3 Module: Buckets with versioning, encryption, lifecycle rules
Security Groups: Properly structured, no circular dependencies
Each module is battle-tested. I use these in production, and they work.
2. Environment Structure That Makes Sense
environments/
βββ dev/
βββ staging/
βββ production/
Each environment has its own state file, its own backend, and its own everything. Because mixing dev and prod is how disasters happen.
3. The "Oh Crap" Solutions Section
This is probably my favorite part. Real problems with real solutions:
State Locked Forever? Here's how to unlock it safely.
Circular Dependency Hell? Use security group rules instead of inline blocks.
Everything's Being Destroyed? Add lifecycle rules, use for_each instead of count.
Provider Version Conflicts? Lock your versions properly.
I didn't just write about these issues - I included the exact code that fixes them.
4. Scripts That Save Time
init-backend.sh: Sets up your S3 bucket and DynamoDB table for state management
validate-terraform.sh: Runs all checks before you commit
cleanup-workspaces.sh: Because workspace management is annoying
5. A Makefile For the Lazy (Like Me)
bashmake plan ENV=dev
make apply ENV=production
make validate
make security
make clean
Done.
No more typing long commands or forgetting flags.
The Stuff I Wish Someone Told Me Earlier
Use for_each, Not count
Seriously. I learned this the hard way when I removed one availability zone from a list and Terraform decided to recreate ALL my subnets. With for_each, removing one AZ only affects that specific resource.
hcl# DON'T do this
resource "aws_subnet" "private" {
count = length(var.azs)
# ...
}
# DO this instead
resource "aws_subnet" "private" {
for_each = toset(var.azs)
# ...
}
Never Hardcode Secrets
I know it's tempting when you're testing something quickly. But just don't. Use Secrets Manager or Parameter Store. The repo shows you exactly how.
State Locks Are Your Friend (Until They're Not)
Always use DynamoDB for state locking. But when it gets stuck? Don't panic. Check the docs folder - I wrote a whole troubleshooting guide.
Format Your Code
Run terraform fmt before every commit. Future you will thank present you. Or set up pre-commit hooks and never think about it again.
Real Talk About Modules
I see a lot of people either:
Putting everything in one giant main.tf file (chaos)
Creating overly complex modules that do too much (also chaos)
The modules in this repo are focused. Each one does ONE thing well. Need a VPC? Use the VPC module. Need a database? Use the RDS module. Mix and match as needed.
What This Repo Is NOT
This is not a framework. It's not "the one true way" to do Terraform. It's not going to revolutionize your DevOps workflow.
It's a reference. A starting point. A "here's what worked for me, maybe it'll work for you too" kind of thing.
The Validation Process
Because we all know that one person who applies without planning first...
bashmake validate # Checks everything
make format # Formats your code
make lint # Runs tflint if you have it
make security # Runs tfsec security scan
All of this runs before you push. Saves you from embarrassing PR comments.
Contributing
Look, I don't know everything. I've probably made mistakes in this repo. Some best practices might be outdated by the time you read this.
That's why it's open for contributions. If you find a bug, fix it. If you have a better solution, share it. If you think something is missing, add it.
The goal is to make this actually useful for people, not to have a perfect repo that I gatekeep.
Lessons I Learned Building This
1. Documentation matters more than you think
I added comments and README files everywhere. Because I've opened my own code months later and had no idea what I was doing.
2. Working examples > theory
Every module has a usage example. Every common issue has a solution with code. No "exercise left to the reader" nonsense.
3. Keep it simple
I removed probably 30% of what I initially built because it was overcomplicated. If you can't understand it in 5 minutes, it's too complex.
4. Test everything
I deployed every module to a test environment. Found bugs. Fixed them. Then found more bugs. That's how it works.
Getting Started
bashgit clone <repo-url>
cd terraform-infrastructure
# Set up your backend
./scripts/init-backend.sh your-bucket-name terraform-locks us-east-1
# Copy example variables
cd environments/dev
cp terraform.tfvars.example terraform.tfvars
# Edit with your values
vim terraform.tfvars
Initialize and plan
make init ENV=dev
make plan ENV=dev
That's it. No complicated setup. No dependencies hell. Just Terraform.
Final Thoughts
Building infrastructure shouldn't feel like black magic. It shouldn't require you to memorize 47 different command flags or spend hours debugging cryptic error messages.
This repo is my attempt to make it a bit easier. It's not perfect, but it's better than what I had when I started.
If it helps even one person avoid a 2 AM debugging session, I'll consider it a success.
Check it out here: GitHub Repository Link
And if you use it and find it helpful (or find bugs), let me know. I'd love to hear about it.
Happy terraforming π
P.S. If you've never used Terraform before, this might be a good starting point. If you're a Terraform expert, you'll probably find things to improve. Either way, contributions are welcome.
P.P.S. Yes, I know there are other Terraform best practices repos out there. This one is mine. It has my specific pain points and solutions. Maybe yours are similar. Maybe not. That's okay.
Found this helpful? Give it a β on GitHub. Have suggestions? Open an issue. Want to argue about best practices? The comments are below.
Top comments (0)