When I started learning infrastructure as code, I kept mixing up Terraform and Ansible. They’re both written as code, and they both deal with servers. Building my own lab is what finally made the difference click.
The short version
Terraform builds the house. Ansible furnishes it.
| Terraform | Ansible | |
|---|---|---|
| Main job | Creates infrastructure (provisioning) | Sets up what’s inside it (configuration) |
| In my lab | Network, firewall, public IPs, 2 VMs | MySQL, Apache, PHP, WordPress |
| How you write it | HCL: you describe the end result | YAML: a list of tasks |
| How it knows what exists | A state file | Checks each server every run |
Terraform: building the infrastructure
Here’s a small piece of my Terraform. It describes the firewall rule that only allows SSH from my home IP address:
security_rule {
name = "allow-ssh-from-admin"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
destination_port_range = "22"
source_address_prefix = var.admin_cidr
}
The workflow is always the same: terraform init, then terraform plan to preview the changes, then terraform apply to make them. The plan step is the safety check, because it shows exactly what will change before anything happens.
Ansible: configuring the servers
Once the servers exist, Ansible connects to them over SSH and sets them up. Here’s the task that installs Apache and PHP on my web server:
- name: Install Apache and PHP
ansible.builtin.apt:
name:
- apache2
- php
- php-mysql
- libapache2-mod-php
state: present
Ansible is agentless, so nothing has to be installed on the servers first. It just needs SSH access.
How they hand off to each other
This is my favorite part. When Terraform finishes, it writes Ansible’s inventory file, the list of servers and their IP addresses. So Ansible always knows the real addresses, and I never have to copy them by hand.
[web]
web ansible_host=<web server IP>
[db]
db ansible_host=<database server IP>
What I learned
If I rebuilt my original LAMP project today, Terraform would create the server, and Ansible would install Apache, MySQL, and PHP and create each client’s user and permissions. What took me hours by hand would be two commands.


