Terraform Examples

Real-world Terraform configurations for common use cases.

Basic VPS with SSH Key

Deploy a simple VPS with SSH key authentication.

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

# Create SSH key
resource "danubedata_ssh_key" "main" {
  name       = "my-ssh-key"
  public_key = file("~/.ssh/id_ed25519.pub")
}

# Create VPS
resource "danubedata_vps" "web" {
  name             = "web-server"
  image            = "ubuntu-24.04"
  datacenter       = "fsn1"
  resource_profile = "small_shared"
  auth_method      = "ssh_key"
  ssh_key_id       = danubedata_ssh_key.main.id
}

output "public_ip" {
  value = danubedata_vps.web.public_ip
}

output "ssh_command" {
  value = "ssh ubuntu@${danubedata_vps.web.public_ip}"
}

output "monthly_cost" {
  value = "${danubedata_vps.web.monthly_cost} EUR/month"
}

Web Application Stack

Deploy a complete web application stack with VPS, PostgreSQL database, and Redis cache.

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

variable "environment" {
  type    = string
  default = "production"
}

variable "datacenter" {
  type    = string
  default = "fsn1"
}

# SSH Key
resource "danubedata_ssh_key" "deploy" {
  name       = "${var.environment}-deploy-key"
  public_key = file("~/.ssh/id_ed25519.pub")
}

# Application Server
resource "danubedata_vps" "app" {
  name             = "${var.environment}-app"
  image            = "ubuntu-24.04"
  datacenter       = var.datacenter
  resource_profile = "medium_shared"
  auth_method      = "ssh_key"
  ssh_key_id       = danubedata_ssh_key.deploy.id
}

# PostgreSQL Database
resource "danubedata_database" "main" {
  name             = "${var.environment}-db"
  database_name    = "myapp"
  engine           = "postgresql"
  version          = "16"
  resource_profile = "medium"
  datacenter       = var.datacenter
}

# Redis Cache
resource "danubedata_cache" "sessions" {
  name             = "${var.environment}-cache"
  cache_provider   = "redis"
  resource_profile = "small"
  datacenter       = var.datacenter
}

# Outputs
output "app_ip" {
  value = danubedata_vps.app.public_ip
}

output "database_endpoint" {
  value = danubedata_database.main.endpoint
}

output "database_port" {
  value = danubedata_database.main.port
}

output "cache_endpoint" {
  value = danubedata_cache.sessions.endpoint
}

output "total_monthly_cost" {
  value = "${danubedata_vps.app.monthly_cost + danubedata_database.main.monthly_cost + danubedata_cache.sessions.monthly_cost} EUR/month"
}

Multi-Environment Setup

Manage dev, staging, and production environments with workspaces.

main.tf

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

# Environment-specific configuration
locals {
  environments = {
    dev = {
      vps_profile = "nano_shared"
      db_profile  = "small"
      datacenter  = "fsn1"
    }
    staging = {
      vps_profile = "small_shared"
      db_profile  = "small"
      datacenter  = "fsn1"
    }
    production = {
      vps_profile = "medium_shared"
      db_profile  = "medium"
      datacenter  = "fsn1"
    }
  }

  env = local.environments[terraform.workspace]
}

# SSH Key (shared across environments)
data "danubedata_ssh_keys" "existing" {}

# VPS
resource "danubedata_vps" "app" {
  name             = "${terraform.workspace}-app"
  image            = "ubuntu-24.04"
  datacenter       = local.env.datacenter
  resource_profile = local.env.vps_profile
  auth_method      = "ssh_key"
  ssh_key_id       = data.danubedata_ssh_keys.existing.ssh_keys[0].id
}

# Database
resource "danubedata_database" "main" {
  name             = "${terraform.workspace}-db"
  database_name    = "app"
  engine           = "postgresql"
  resource_profile = local.env.db_profile
  datacenter       = local.env.datacenter
}

output "environment" {
  value = terraform.workspace
}

output "app_ip" {
  value = danubedata_vps.app.public_ip
}

output "db_endpoint" {
  value = danubedata_database.main.endpoint
}

Usage

Bash
# Create workspaces
terraform workspace new dev
terraform workspace new staging
terraform workspace new production

# Deploy to dev
terraform workspace select dev
terraform apply

# Deploy to staging
terraform workspace select staging
terraform apply

# Deploy to production
terraform workspace select production
terraform apply

S3-Compatible Storage with Access Keys

Set up object storage with access keys for your application.

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

# Storage bucket for uploads
resource "danubedata_storage_bucket" "uploads" {
  name               = "my-app-uploads"
  display_name       = "Application Uploads"
  region             = "fsn1"
  versioning_enabled = true
  encryption_enabled = true
}

# Storage bucket for backups
resource "danubedata_storage_bucket" "backups" {
  name               = "my-app-backups"
  display_name       = "Database Backups"
  region             = "fsn1"
  versioning_enabled = true
  encryption_enabled = true
  public_access      = false
}

# Access key for application
resource "danubedata_storage_access_key" "app" {
  name = "app-storage-key"
}

# Access key for backup system (with expiration)
resource "danubedata_storage_access_key" "backup" {
  name       = "backup-storage-key"
  expires_at = "2025-12-31T23:59:59Z"
}

# Outputs for application configuration
output "s3_endpoint" {
  value = "https://s3.danubedata.ro"
}

output "uploads_bucket" {
  value = danubedata_storage_bucket.uploads.minio_bucket_name
}

output "backups_bucket" {
  value = danubedata_storage_bucket.backups.minio_bucket_name
}

output "app_access_key" {
  value = danubedata_storage_access_key.app.access_key_id
}

output "app_secret_key" {
  value     = danubedata_storage_access_key.app.secret_access_key
  sensitive = true
}

# AWS CLI configuration helper
output "aws_cli_config" {
  value = <<-EOT
    # Add to ~/.aws/config:
    [profile danubedata]
    region = eu-central-1

    # Add to ~/.aws/credentials:
    [danubedata]
    aws_access_key_id = ${danubedata_storage_access_key.app.access_key_id}
    aws_secret_access_key = <run: terraform output -raw app_secret_key>

    # Usage:
    aws --profile danubedata --endpoint-url https://s3.danubedata.ro s3 ls
  EOT
}

Serverless API with Database

Deploy a serverless container with a connected database.

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

# Database for the API
resource "danubedata_database" "api_db" {
  name             = "api-database"
  database_name    = "api"
  engine           = "postgresql"
  version          = "16"
  resource_profile = "small"
  datacenter       = "fsn1"
}

# Serverless API
resource "danubedata_serverless" "api" {
  name             = "my-api"
  deployment_type  = "image"
  image_url        = "ghcr.io/myorg/my-api:latest"
  resource_profile = "small"
  port             = 8080
  min_instances    = 0
  max_instances    = 10

  environment_variables = {
    NODE_ENV     = "production"
    DATABASE_URL = "postgresql://${danubedata_database.api_db.username}@${danubedata_database.api_db.endpoint}:${danubedata_database.api_db.port}/${danubedata_database.api_db.database_name}"
    LOG_LEVEL    = "info"
  }
}

output "api_url" {
  value = danubedata_serverless.api.url
}

output "database_endpoint" {
  value = danubedata_database.api_db.endpoint
}

VPS with Firewall

Deploy a VPS with custom firewall rules.

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

variable "allowed_ssh_ips" {
  type    = list(string)
  default = ["0.0.0.0/0"]  # Replace with your IP ranges
}

# SSH Key
resource "danubedata_ssh_key" "main" {
  name       = "server-key"
  public_key = file("~/.ssh/id_ed25519.pub")
}

# Firewall
resource "danubedata_firewall" "web" {
  name           = "web-server-firewall"
  description    = "Firewall for web servers"
  default_action = "drop"

  # Allow SSH from specific IPs
  rules {
    name             = "allow-ssh"
    action           = "allow"
    direction        = "inbound"
    protocol         = "tcp"
    port_range_start = 22
    port_range_end   = 22
    source_ips       = var.allowed_ssh_ips
    priority         = 100
  }

  # Allow HTTP
  rules {
    name             = "allow-http"
    action           = "allow"
    direction        = "inbound"
    protocol         = "tcp"
    port_range_start = 80
    port_range_end   = 80
    source_ips       = ["0.0.0.0/0"]
    priority         = 200
  }

  # Allow HTTPS
  rules {
    name             = "allow-https"
    action           = "allow"
    direction        = "inbound"
    protocol         = "tcp"
    port_range_start = 443
    port_range_end   = 443
    source_ips       = ["0.0.0.0/0"]
    priority         = 300
  }

  # Allow all outbound
  rules {
    name             = "allow-outbound"
    action           = "allow"
    direction        = "outbound"
    protocol         = "tcp"
    port_range_start = 1
    port_range_end   = 65535
    source_ips       = ["0.0.0.0/0"]
    priority         = 1000
  }
}

# VPS
resource "danubedata_vps" "web" {
  name             = "web-server"
  image            = "ubuntu-24.04"
  datacenter       = "fsn1"
  resource_profile = "small_shared"
  auth_method      = "ssh_key"
  ssh_key_id       = danubedata_ssh_key.main.id
}

output "server_ip" {
  value = danubedata_vps.web.public_ip
}

Scheduled Snapshots

Create VPS snapshots for backup purposes.

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

# VPS
resource "danubedata_vps" "production" {
  name             = "production-server"
  image            = "ubuntu-24.04"
  datacenter       = "fsn1"
  resource_profile = "medium_shared"
  auth_method      = "ssh_key"
  ssh_key_id       = var.ssh_key_id
}

# Manual snapshot (create before major changes)
resource "danubedata_vps_snapshot" "pre_upgrade" {
  name            = "pre-upgrade-${formatdate("YYYY-MM-DD", timestamp())}"
  description     = "Snapshot before system upgrade"
  vps_instance_id = danubedata_vps.production.id
}

output "snapshot_id" {
  value = danubedata_vps_snapshot.pre_upgrade.id
}

Database with Replicas (Future)

Deploy a database with read replicas for high availability.

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

# Primary database
resource "danubedata_database" "primary" {
  name             = "app-primary"
  database_name    = "myapp"
  engine           = "postgresql"
  version          = "16"
  resource_profile = "large"
  datacenter       = "fsn1"
}

# Application configuration
output "primary_endpoint" {
  value       = danubedata_database.primary.endpoint
  description = "Primary database endpoint for writes"
}

output "primary_port" {
  value = danubedata_database.primary.port
}

output "connection_info" {
  value = {
    host     = danubedata_database.primary.endpoint
    port     = danubedata_database.primary.port
    database = danubedata_database.primary.database_name
    username = danubedata_database.primary.username
  }
  sensitive = true
}

Full Infrastructure Module

Create a reusable module for deploying a complete application stack.

modules/app-stack/main.tf

HCL
variable "name" {
  type        = string
  description = "Application name"
}

variable "datacenter" {
  type    = string
  default = "fsn1"
}

variable "vps_profile" {
  type    = string
  default = "small_shared"
}

variable "db_profile" {
  type    = string
  default = "small"
}

variable "ssh_key_id" {
  type        = string
  description = "SSH key ID for VPS access"
}

# VPS
resource "danubedata_vps" "app" {
  name             = "${var.name}-app"
  image            = "ubuntu-24.04"
  datacenter       = var.datacenter
  resource_profile = var.vps_profile
  auth_method      = "ssh_key"
  ssh_key_id       = var.ssh_key_id
}

# Database
resource "danubedata_database" "db" {
  name             = "${var.name}-db"
  database_name    = replace(var.name, "-", "_")
  engine           = "postgresql"
  version          = "16"
  resource_profile = var.db_profile
  datacenter       = var.datacenter
}

# Cache
resource "danubedata_cache" "cache" {
  name             = "${var.name}-cache"
  cache_provider   = "redis"
  resource_profile = "small"
  datacenter       = var.datacenter
}

# Outputs
output "vps_ip" {
  value = danubedata_vps.app.public_ip
}

output "db_endpoint" {
  value = danubedata_database.db.endpoint
}

output "cache_endpoint" {
  value = danubedata_cache.cache.endpoint
}

output "monthly_cost" {
  value = danubedata_vps.app.monthly_cost + danubedata_database.db.monthly_cost + danubedata_cache.cache.monthly_cost
}

main.tf (using the module)

HCL
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {}

# SSH Key
resource "danubedata_ssh_key" "deploy" {
  name       = "deploy-key"
  public_key = file("~/.ssh/id_ed25519.pub")
}

# Deploy multiple applications
module "frontend" {
  source      = "./modules/app-stack"
  name        = "frontend"
  datacenter  = "fsn1"
  vps_profile = "small_shared"
  db_profile  = "small"
  ssh_key_id  = danubedata_ssh_key.deploy.id
}

module "backend" {
  source      = "./modules/app-stack"
  name        = "backend"
  datacenter  = "fsn1"
  vps_profile = "medium_shared"
  db_profile  = "medium"
  ssh_key_id  = danubedata_ssh_key.deploy.id
}

output "frontend" {
  value = {
    ip           = module.frontend.vps_ip
    db_endpoint  = module.frontend.db_endpoint
    monthly_cost = module.frontend.monthly_cost
  }
}

output "backend" {
  value = {
    ip           = module.backend.vps_ip
    db_endpoint  = module.backend.db_endpoint
    monthly_cost = module.backend.monthly_cost
  }
}

output "total_monthly_cost" {
  value = "${module.frontend.monthly_cost + module.backend.monthly_cost} EUR/month"
}

CI/CD with GitHub Actions

Example GitHub Actions workflow for Terraform.

.github/workflows/terraform.yml

YAML
name: Terraform

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  TF_VERSION: "1.6.0"

jobs:
  terraform:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Init
        run: terraform init
        env:
          DANUBEDATA_API_TOKEN: ${{ secrets.DANUBEDATA_API_TOKEN }}

      - name: Terraform Format Check
        run: terraform fmt -check

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        run: terraform plan -no-color
        env:
          DANUBEDATA_API_TOKEN: ${{ secrets.DANUBEDATA_API_TOKEN }}

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        run: terraform apply -auto-approve
        env:
          DANUBEDATA_API_TOKEN: ${{ secrets.DANUBEDATA_API_TOKEN }}

Next Steps