Are you still managing servers, databases, and cloud services manually? Every time a teammate touches a config, something breaks. And you're tired of hearing "it works on my machine" while production is down.
At Meteora Web, we’ve been there. We manage stacks for clients every day, and when the chaos grows, infrastructure as code with Terraform is the answer. Not a trend: a necessity for reproducible deployments, safe rollbacks, and a single source of truth.
In this guide, we focus on three operational pillars of Terraform: providers, state, and modules. No theory: code you can use now, common mistakes to avoid, and a concrete perspective for your business.
Why Use Terraform for Infrastructure as Code Instead of Clicking Consoles?
Every time you configure a server via web console, you’re accumulating technical debt. No audit trail, no reproducibility. With Terraform you declare the desired state; it applies and maintains it. If someone manually deletes a resource, the next terraform apply recreates it. Sounds like magic, it’s just code.
Sponsored Protocol
The concrete problem it solves
Imagine you need to replicate the production environment for a new client: same MariaDB server, same S3 bucket, same VPC. Doing it by hand takes hours and mistakes. With Terraform, a 50-line file and one terraform apply replicate an environment. We’ve done this for clients moving from shared hosting to managed AWS infrastructure: from 3 days of work to 20 minutes.
How to Choose a Terraform Provider and What Criteria Matter for Your Business?
Providers are plugins that talk to cloud services: AWS, Azure, Google Cloud, but also Cloudflare, GitHub, Kubernetes, Proxmox. Choosing the right provider means evaluating:
- Maturity: an official HashiCorp provider is more reliable than a third-party one.
- Coverage: does it support all the resources you need? For AWS the AWS provider is vast; for niche services, double-check.
- Maintenance: providers with recent commits and responsive issue handling.
Practical example: AWS provider with authentication
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-south-2"
# Credentials from environment variables or ~/.aws/credentials
}
Important rule: never hardcode credentials. Use environment variables or tools like AWS Vault. We’ve seen clients with access keys hardcoded on GitHub — an avoidable security hole.
Sponsored Protocol
How to Manage Terraform State in a Team Without Conflicts or Data Loss?
The state file (terraform.tfstate) is Terraform’s heart: it maps real resources to your code. Lose it or share it poorly, and Terraform won’t know what to manage. State must be remote and locked for teamwork.
S3 backend with DynamoDB locking — the standard setup
terraform {
backend "s3" {
bucket = "my-company-terraform-state"
key = "prod/network/terraform.tfstate"
region = "eu-south-2"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Without locking, two people run apply simultaneously and corrupt the state. With DynamoDB, only one wins. We solved this for a client with four developers on the same infrastructure: zero conflicts since then.
Sponsored Protocol
Common state mistakes
- Local state in a team: sharing via Git? No: state in .gitignore. Use remote backend.
- State with sensitive data: never push a .tfstate file containing passwords. Use
terraform state showonly in a secure local environment. - No backup: enable versioning on the S3 bucket. If someone accidentally deletes the state, you can restore it.
How to Structure Terraform Modules to Avoid a Single 2000-Line File?
If you put everything in one main.tf, after a few resources it becomes unreadable. Modules are like reusable components: one module for VPC, one for database, one for Kubernetes cluster. Each module does one thing and does it well.
A minimal web server module on AWS
Create directory modules/webserver:
# modules/webserver/main.tf
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = var.subnet_id
tags = {
Name = var.name
}
}
# modules/webserver/variables.tf
variable "ami_id" {}
variable "instance_type" { default = "t3.micro" }
variable "subnet_id" {}
variable "name" {}
Then in the root module:
Sponsored Protocol
module "web_prod" {
source = "./modules/webserver"
ami_id = "ami-0123456789abcdef0"
instance_type = "t3.small"
subnet_id = aws_subnet.public.id
name = "web-prod-01"
}
Benefit: you can reuse the same module for staging, production, disaster recovery — just change variables. We have a base module for WordPress servers that we use across all projects: saves hours of boilerplate.
Terraform Registry and public modules
Don’t reinvent the wheel. The Terraform Registry offers thousands of verified modules. Example: for an RDS database, use terraform-aws-modules/rds/aws. Install it easily:
module "database" {
source = "terraform-aws-modules/rds/aws"
version = "~> 6.0"
identifier = "mydb"
engine = "mysql"
# ... other variables
}
What to Do Next — Operational Checklist to Start with Terraform
- Install Terraform (locally or in CI/CD).
- Choose a remote backend (S3 + DynamoDB for AWS, Terraform Cloud for multi-cloud).
- Create your first provider (for the cloud you use most) and apply a simple resource (e.g., a bucket).
- Structure the project: use separate directories per environment (prod/staging) and reusable modules.
- Lock the state with locking and versioning.
- Never hardcode secrets — use environment variables or tools like Vault.
- Read the official docs: Terraform documentation.
At Meteora Web, we use Terraform daily — from Linux servers to Kubernetes clusters. If you want to learn how to integrate it into a CI/CD pipeline, start with our DevOps and CI/CD pillar guide.
Sponsored Protocol
Remember: infrastructure as code is not a luxury for big companies. It’s the tool that turns chaos into control. And we see it every day in Italian SMEs. Start today.