🧱 Building a Linux Web Server with Terraform & Ansible – Part 1: Provisioning a DigitalOcean Droplet

In this post, we’ll walk through how to use Terraform to create and configure a DigitalOcean droplet, which will serve as the foundation for deploying a Python Flask app. We’ll automate infrastructure provisioning step-by-step to make future deployments repeatable and easy.


🌐 Step 1: Configure the Terraform Provider

The first thing we need to do is set up the Terraform provider for DigitalOcean. This will allow us to download all the digitalocean specific modules for terraform.

📘 Official docs:
👉 DigitalOcean Terraform Provider

Inside your project, create a folder called terraform, and within it a file named providers.tf.

# providers.tf
terraform {
  required_providers {
    digitalocean = {
      source  = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

# Token from DIGITALOCEAN_TOKEN env var
provider "digitalocean" {}

🔐 Step 2: Authenticate with DigitalOcean

Terraform needs a Personal Access Token to communicate with the DigitalOcean API. While Terraform allows passing this as a variable, I recommend using an environment variable to avoid accidentally pushing secrets to version control.

🛠️ Generate your token here:
👉 Create a Personal Access Token

Then export it in your terminal:

export DIGITALOCEAN_TOKEN=<your_token_here>

Great! With the provider configured, we can initialize the Terraform project by running:

terraform init

💻 Step 3: Define Your Droplet Resource

Now we’ll define the resources we want Terraform to create—starting with our droplet and SSH key.

# droplet.tf
resource "digitalocean_ssh_key" "default" {
  name       = "Terraform Example"
  public_key = file("~/.ssh/tutorial.pub")
}

resource "digitalocean_droplet" "web" {
  image   = var.ubuntu_image
  name    = "web-1"
  region  = var.region
  size    = var.small_droplet

  ssh_keys = [digitalocean_ssh_key.default.fingerprint]

  monitoring = true
}

📘 Docs for available droplet fields:
👉 DigitalOcean Droplet Resource

Tip: Enabling monitoring gives you access to useful metrics like CPU and memory usage. This will be helpful later when we configure alerts.


🔑 Step 4: Generate an SSH Key (if needed)

Now, we need to generate an SSH key so we can securely access our droplet once it’s live. If you already have one you’d like to use, feel free to skip this step

cd ~/.ssh
ssh-keygen -t ed25519 # I called my key "tutorial"
eval `ssh-agent -s`   # Start the SSH agent
ssh-add ~/.ssh/tutorial # Add our new key to the agent

This key is what you’ll use to SSH into the server later.


📤 Step 5: Output the Droplet IP

Add an output so you can quickly grab the droplet’s public IP address:

# outputs.tf
output "droplet_ip" {
    value = digitalocean_droplet.web.ipv4_address
}

⚙️ Step 6: Set Your Variables

Terraform needs a few input variables: your desired region, image, and droplet size. You can find these by going through the droplet creation flow in the DigitalOcean UI and copying the CLI equivalent.

# variables.tf
variable "region" {
    type = string
    default = "fra1"
}

variable "ubuntu_image" {
    type = string
    default = "ubuntu-24-10-x64"
}

# s-1vcpu-512mb-10gb    $4 512MB RAM    1 CPU
# s-1vcpu-1gb           $6 1GB Ram      1 CPU
variable "small_droplet" {
    type = string
    default = "s-1vcpu-1gb"
}

🧪 Step 7: Apply the Terraform Plan

Once everything is set up, run the following commands to create your droplet:

terraform plan
terraform apply

Terraform will show you what it’s about to create. Confirm with yes, and your droplet will be live in a few moments 🚀


✅ What You’ve Accomplished

By now, you’ve:

  • Initialized a Terraform project
  • Configured authentication with DigitalOcean
  • Defined and provisioned a droplet
  • Set up secure SSH access
  • Output the server’s IP for easy connection

🔜 Next Up: Server Provisioning with Ansible

In the next part of the series, we’ll use Ansible to:

  • Install system packages
  • Configure users
  • Harden the server
  • Set up our Flask app environment

See you there!

Leave a Reply

Your email address will not be published. Required fields are marked *