Terraform on DigitalOcean: The Complete Beginner’s Guide (2026)

Terraform on DigitalOcean: The Complete Beginner’s Guide (2026)

DigitalOcean’s simple API and flat pricing make it the best cloud provider for learning Terraform. In this guide, you’ll go from zero to deploying a production-ready infrastructure — Droplets, Kubernetes clusters, managed databases, and networking — all defined in code.

Disclosure: Some links in this article are affiliate links. If you purchase through these links, we may earn a small commission at no extra cost to you.

Prerequisites:
– A DigitalOcean account (sign up with $200 free credit)
– Terraform installed (brew install terraform or download)
– A DigitalOcean API token (Settings → API → Generate New Token)

Project Setup

Create a new directory and initialize Terraform:

mkdir do-infrastructure && cd do-infrastructure

Create providers.tf:

terraform {
  required_providers {
    digitalocean = {
      source  = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

variable "do_token" {
  description = "DigitalOcean API token"
  type        = string
  sensitive   = true
}

provider "digitalocean" {
  token = var.do_token
}

Create terraform.tfvars (add to .gitignore):

do_token = "your-api-token-here"

Initialize the project:

terraform init

Deploying Your First Droplet

Create droplets.tf:

# Look up the latest Ubuntu image
data "digitalocean_images" "ubuntu" {
  filter {
    key    = "distribution"
    values = ["Ubuntu"]
  }
  filter {
    key    = "status"
    values = ["available"]
  }
  sort {
    key       = "created"
    direction = "desc"
  }
}

# Create an SSH key
resource "digitalocean_ssh_key" "default" {
  name       = "terraform-key"
  public_key = file("~/.ssh/id_rsa.pub")
}

# Create a Droplet
resource "digitalocean_droplet" "web" {
  image    = "ubuntu-24-04-x64"
  name     = "web-server"
  region   = "nyc1"
  size     = "s-1vcpu-2gb"
  ssh_keys = [digitalocean_ssh_key.default.fingerprint]

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

output "web_ip" {
  value = digitalocean_droplet.web.ipv4_address
}

Deploy it:

terraform plan    # Preview changes
terraform apply   # Create resources

Networking: VPC, Firewall, Load Balancer

VPC (Virtual Private Cloud)

resource "digitalocean_vpc" "production" {
  name     = "production-vpc"
  region   = "nyc1"
  ip_range = "10.10.10.0/24"
}

# Update droplet to use VPC
resource "digitalocean_droplet" "web" {
  image    = "ubuntu-24-04-x64"
  name     = "web-server"
  region   = "nyc1"
  size     = "s-1vcpu-2gb"
  vpc_uuid = digitalocean_vpc.production.id
  ssh_keys = [digitalocean_ssh_key.default.fingerprint]
}

Firewall

resource "digitalocean_firewall" "web" {
  name = "web-firewall"
  droplet_ids = [digitalocean_droplet.web.id]

  inbound_rule {
    protocol         = "tcp"
    port_range       = "22"
    source_addresses = ["your.ip.address/32"]
  }

  inbound_rule {
    protocol         = "tcp"
    port_range       = "80"
    source_addresses = ["0.0.0.0/0", "::/0"]
  }

  inbound_rule {
    protocol         = "tcp"
    port_range       = "443"
    source_addresses = ["0.0.0.0/0", "::/0"]
  }

  outbound_rule {
    protocol              = "tcp"
    port_range            = "all"
    destination_addresses = ["0.0.0.0/0", "::/0"]
  }

  outbound_rule {
    protocol              = "udp"
    port_range            = "all"
    destination_addresses = ["0.0.0.0/0", "::/0"]
  }
}

Load Balancer

resource "digitalocean_loadbalancer" "web" {
  name   = "web-lb"
  region = "nyc1"
  vpc_uuid = digitalocean_vpc.production.id

  forwarding_rule {
    entry_port     = 80
    entry_protocol = "http"
    target_port     = 80
    target_protocol = "http"
  }

  healthcheck {
    port     = 80
    protocol = "http"
    path     = "/"
  }

  droplet_ids = [digitalocean_droplet.web.id]
}

output "lb_ip" {
  value = digitalocean_loadbalancer.web.ip
}

Managed Kubernetes Cluster

This is where DigitalOcean really shines — managed Kubernetes at a fraction of AWS/GCP prices.

Create kubernetes.tf:

resource "digitalocean_kubernetes_cluster" "production" {
  name    = "production-cluster"
  region  = "nyc1"
  version = "1.31.1-do.3"
  vpc_uuid = digitalocean_vpc.production.id

  node_pool {
    name       = "default-pool"
    size       = "s-2vcpu-4gb"
    auto_scale = true
    min_nodes  = 2
    max_nodes  = 5
    tags       = ["production"]
  }
}

# Save kubeconfig for kubectl access
resource "local_file" "kubeconfig" {
  content  = digitalocean_kubernetes_cluster.production.kube_config[0].raw_config
  filename = "${path.module}/kubeconfig.yaml"
}

output "cluster_endpoint" {
  value = digitalocean_kubernetes_cluster.production.endpoint
}

Managed Database

resource "digitalocean_database_cluster" "postgres" {
  name       = "app-database"
  engine     = "pg"
  version    = "16"
  size       = "db-s-1vcpu-1gb"
  region     = "nyc1"
  node_count = 1

  private_network_uuid = digitalocean_vpc.production.id
}

# Restrict database access to your Kubernetes cluster
resource "digitalocean_database_firewall" "postgres" {
  cluster_id = digitalocean_database_cluster.postgres.id

  rule {
    type  = "k8s"
    value = digitalocean_kubernetes_cluster.production.id
  }
}

output "db_connection" {
  value     = digitalocean_database_cluster.postgres.uri
  sensitive = true
}

Spaces (Object Storage)

resource "digitalocean_spaces_bucket" "assets" {
  name   = "myapp-assets-bucket"
  region = "nyc3"
  acl    = "private"

  cors_rule {
    allowed_headers = ["*"]
    allowed_methods = ["GET"]
    allowed_origins = ["https://myapp.com"]
    max_age_seconds = 3600
  }

  lifecycle_rule {
    enabled = true
    expiration {
      days = 90
    }
    prefix = "tmp/"
  }
}

resource "digitalocean_cdn" "assets" {
  origin = digitalocean_spaces_bucket.assets.bucket_domain_name
}

Managing State

For team collaboration, store Terraform state remotely using DigitalOcean Spaces:

terraform {
  backend "s3" {
    endpoint                    = "nyc3.digitaloceanspaces.com"
    bucket                      = "terraform-state-bucket"
    key                         = "production/terraform.tfstate"
    region                      = "us-east-1"  # Required but unused
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_requesting_account_id  = true
    skip_s3_checksum            = true
  }
}

Complete Production Stack

Here’s everything together — what a small production infrastructure looks like:

├── providers.tf          # Provider config + variables
├── vpc.tf                # VPC and networking
├── kubernetes.tf         # DOKS cluster
├── database.tf           # Managed PostgreSQL
├── storage.tf            # Spaces + CDN
├── firewall.tf           # Network security
├── outputs.tf            # Useful outputs
├── terraform.tfvars      # Secrets (gitignored)
└── terraform.tfstate     # State (remote in production)

Monthly cost estimate for this stack:

Resource Size Monthly Cost
Kubernetes (2 nodes) s-2vcpu-4gb $48
PostgreSQL db-s-1vcpu-1gb $15
Load Balancer Standard $12
Spaces (25GB) Standard $5
Total ~$80/month

Compare that to AWS (EKS + RDS + ALB + S3): easily $200+/month for equivalent resources.

Tips and Best Practices

  1. Use workspaces for multi-environment management:
    bash
    terraform workspace new staging
    terraform workspace new production

  2. Use modules for reusable components:
    hcl
    module "web_cluster" {
    source = "./modules/kubernetes"
    region = "nyc1"
    min_nodes = var.environment == "production" ? 3 : 1
    }

  3. Tag everything for cost tracking and organization

  4. Use terraform plan in CI to preview changes before applying

  5. Destroy dev environments when not in use:
    bash
    terraform workspace select dev
    terraform destroy -auto-approve

Recommended Terraform Resources

Terraform has a steep learning curve. These resources will accelerate your progress beyond this guide:

Next Steps

  1. Sign up for DigitalOcean ($200 free credit) if you haven’t already
  2. Follow this guide step by step
  3. Add ArgoCD to your cluster for GitOps deployments — see our CI/CD tools comparison
  4. Set up monitoring with Prometheus and Grafana

Ready to start? Get $200 free credit on DigitalOcean and build your entire infrastructure as code.

Related: Best Cloud Hosting for Kubernetes in 2026 | How to Build a DevOps Home Lab