Explore plans starting at ₹699/mo →
DevOps

Infrastructure as Code with Terraform on Cloud Servers: A Complete Guide

S
ServerRaja
11 min read
#Infrastructure#Linux#Networking#Automation#DevOps#Guide#Cloud Computing
Infrastructure as Code with Terraform on Cloud Servers: A Complete Guide

What is Infrastructure as Code?

Infrastructure as Code (IaC) treats your server infrastructure the same way you treat application code. Instead of manually clicking through dashboards or running ad-hoc commands, you define your desired infrastructure state in configuration files. Terraform, developed by HashiCorp, is the industry-standard tool for IaC across multiple cloud providers.

With ServerRaja cloud servers, Terraform lets you define your entire infrastructure stack in version-controlled files that can be reviewed, tested, and deployed just like application code.

Installing Terraform

Install Terraform on your local machine or CI/CD runner:

# Ubuntu/Debian
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

# CentOS/RHEL sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo sudo yum install terraform

# Verify installation terraform version ```

Terraform Project Structure

Organize your infrastructure code with a clear directory structure:

infrastructure/
├── main.tf            # Main resource definitions
├── variables.tf       # Input variable declarations
├── outputs.tf         # Output value definitions
├── providers.tf       # Provider configuration
├── terraform.tfvars   # Variable values (not committed to git)
├── versions.tf        # Required provider versions
└── modules/
    ├── networking/
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    └── compute/
        ├── main.tf
        ├── variables.tf
        └── outputs.tf

Writing Your First Configuration

Create the provider configuration in `providers.tf`:

terraform {
  required_version = ">= 1.5.0"

required_providers { openstack = { source = "terraform-provider-openstack/openstack" version = "~> 1.54.0" } }

backend "s3" { bucket = "terraform-state" key = "production/terraform.tfstate" region = "us-east-1" } }

provider "openstack" { auth_url = var.auth_url region = var.region tenant_name = var.tenant_name user_name = var.username password = var.password } ```

Define variables in `variables.tf`:

variable "auth_url" {
  description = "OpenStack authentication URL"
  type        = string
}

variable "region" { description = "Cloud region" type = string default = "us-east-1" }

variable "instance_count" { description = "Number of web servers" type = number default = 2 }

variable "instance_flavor" { description = "Server size" type = string default = "v2-4c8g" } ```

Provisioning Cloud Resources

Create compute instances in `main.tf`:

resource "openstack_compute_instance_v2" "web_server" {
  count           = var.instance_count
  name            = "web-server-${count.index + 1}"
  image_name      = "Ubuntu-22.04"
  flavor_name     = var.instance_flavor
  key_pair        = openstack_compute_keypair_v2.deployer.name
  security_groups = [openstack_networking_secgroup_v2.web.name]

network { uuid = openstack_networking_network_v2.internal.id }

user_data = <<-EOF #!/bin/bash apt-get update apt-get install -y nginx systemctl enable nginx systemctl start nginx EOF

tags = ["web", "production"] }

resource "openstack_compute_keypair_v2" "deployer" { name = "terraform-deployer" public_key = file("~/.ssh/id_ed25519.pub") } ```

Define networking resources:

resource "openstack_networking_network_v2" "internal" {
  name           = "internal-network"
  admin_state_up = true
}

resource "openstack_networking_subnet_v2" "internal" { name = "internal-subnet" network_id = openstack_networking_network_v2.internal.id cidr = "10.0.1.0/24" ip_version = 4

dns_nameservers = ["8.8.8.8", "8.8.4.4"] }

resource "openstack_networking_secgroup_v2" "web" { name = "web-security-group" description = "Security group for web servers" }

resource "openstack_networking_secgroup_rule_v2" "ssh" { direction = "ingress" ethertype = "IPv4" protocol = "tcp" port_range_min = 22 port_range_max = 22 remote_ip_prefix = "0.0.0.0/0" security_group_id = openstack_networking_secgroup_v2.web.id }

resource "openstack_networking_secgroup_rule_v2" "http" { direction = "ingress" ethertype = "IPv4" protocol = "tcp" port_range_min = 443 port_range_max = 443 remote_ip_prefix = "0.0.0.0/0" security_group_id = openstack_networking_secgroup_v2.web.id } ```

Using Terraform Modules

Create reusable modules to avoid repetition. Here is a networking module:

# modules/networking/main.tf
resource "openstack_networking_network_v2" "this" {
  name           = var.network_name
  admin_state_up = true
}

resource "openstack_networking_subnet_v2" "this" { name = "${var.network_name}-subnet" network_id = openstack_networking_network_v2.this.id cidr = var.cidr dns_nameservers = var.dns_servers }

output "network_id" { value = openstack_networking_network_v2.this.id }

output "subnet_id" { value = openstack_networking_subnet_v2.this.id } ```

Call the module from your root configuration:

module "networking" {
  source       = "./modules/networking"
  network_name = "production"
  cidr         = "10.0.0.0/16"
  dns_servers  = ["8.8.8.8", "1.1.1.1"]
}

Terraform Workflow Commands

The standard Terraform workflow follows these steps:

# Initialize the working directory
terraform init

# Preview changes before applying terraform plan -out=tfplan

# Review the plan output carefully terraform show tfplan

# Apply the changes terraform apply tfplan

# View current state terraform show

# List all managed resources terraform state list

# Destroy infrastructure when no longer needed terraform destroy ```

State Management Best Practices

Terraform state tracks the mapping between your configuration and real infrastructure. Use remote state backends like S3 or Terraform Cloud, enable state locking, and never edit state files manually. Implement state separation for different environments:

# Move a resource in state without recreating
terraform state mv openstack_compute_instance_v2.web_server openstack_compute_instance_v2.app_server

# Import existing infrastructure terraform import openstack_compute_instance_v2.existing_server <server-id> ```

Conclusion

Terraform brings discipline, repeatability, and version control to infrastructure management on ServerRaja cloud servers. Start by codifying your existing infrastructure using `terraform import`, then adopt a workflow where all changes go through plan and apply. Pair Terraform with your CI/CD pipeline for fully automated infrastructure deployments.

Terraform IaC for Cloud Servers | ServerRaja