Terraform Provider Overview

The official DanubeData Terraform provider allows you to manage your cloud infrastructure using Infrastructure as Code (IaC). Deploy VPS instances, databases, caches, storage buckets, and more with version-controlled, reproducible configurations.

Why Use Terraform?

  • Version Control: Track infrastructure changes in Git alongside your application code
  • Reproducible Deployments: Deploy identical environments across dev, staging, and production
  • Team Collaboration: Share configurations and collaborate with pull requests
  • Drift Detection: Detect and fix configuration drift automatically
  • Cost Visibility: Preview costs before deployment with terraform plan

Quick Start

1. Install Terraform

Download and install Terraform from terraform.io:

Bash
# macOS with Homebrew
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

# 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

# Verify installation
terraform version

2. Get Your API Token

  1. Log in to your DanubeData dashboard
  2. Navigate to Settings > API Tokens
  3. Click Create New Token
  4. Select the permissions you need (at minimum: read/write for resources you want to manage)
  5. Copy the token - it's shown only once!

3. Configure the Provider

Create a new directory for your Terraform configuration:

Bash
mkdir my-infrastructure
cd my-infrastructure

Create a main.tf file:

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

provider "danubedata" {
  # API token is read from DANUBEDATA_API_TOKEN environment variable
}

Set your API token as an environment variable:

Bash
export DANUBEDATA_API_TOKEN="your-api-token-here"

4. Initialize and Apply

Bash
# Initialize the provider
terraform init

# Preview changes
terraform plan

# Apply changes
terraform apply

Provider Configuration

The provider supports the following configuration options:

AttributeTypeRequiredDescription
api_tokenstringYesYour DanubeData API token. Can also be set via DANUBEDATA_API_TOKEN environment variable.
base_urlstringNoAPI endpoint URL. Defaults to https://danubedata.ro/api/v1. Can be set via DANUBEDATA_BASE_URL environment variable.

Authentication Methods

Recommended: Environment Variable

Bash
export DANUBEDATA_API_TOKEN="your-api-token"
HCL
provider "danubedata" {}

Alternative: Direct Configuration (not recommended for production)

HCL
provider "danubedata" {
  api_token = "your-api-token"  # Don't commit this to version control!
}

Using Terraform Variables

HCL
variable "danubedata_token" {
  type      = string
  sensitive = true
}

provider "danubedata" {
  api_token = var.danubedata_token
}

Then set the variable:

Bash
export TF_VAR_danubedata_token="your-api-token"

Available Resources

The provider includes the following resource types:

ResourceDescription
danubedata_vpsVirtual machines with shared or dedicated CPU
danubedata_databaseManaged MySQL, PostgreSQL, and MariaDB databases
danubedata_database_replicaRead replicas for a managed database
danubedata_cacheRedis, Valkey, and Dragonfly cache instances
danubedata_parameter_groupReusable database/cache configuration presets
danubedata_serverlessScale-to-zero serverless containers
danubedata_static_siteStatic site hosting
danubedata_static_site_domainCustom domain for a static site
danubedata_storage_bucketS3-compatible object storage buckets
danubedata_storage_access_keyAccess keys for object storage
danubedata_ssh_keySSH keys for VPS authentication
danubedata_firewallNetwork security rules
danubedata_vps_snapshotPoint-in-time VPS backups
danubedata_database_snapshotPoint-in-time database backups
danubedata_cache_snapshotPoint-in-time cache backups

See Terraform Resources for detailed documentation.

Available Data Sources

The provider includes these data sources for querying existing resources:

Data SourceDescription
danubedata_vpssList existing VPS instances
danubedata_vps_imagesList available OS images
danubedata_databasesList existing databases
danubedata_database_providersList available database engines
danubedata_database_snapshotsList database snapshots
danubedata_cachesList existing cache instances
danubedata_cache_providersList available cache providers
danubedata_cache_snapshotsList cache snapshots
danubedata_parameter_groupsList parameter groups
danubedata_serverless_containersList serverless containers
danubedata_static_sitesList static sites
danubedata_storage_bucketsList storage buckets
danubedata_storage_access_keysList storage access keys
danubedata_ssh_keysList existing SSH keys
danubedata_firewallsList firewalls
danubedata_vps_snapshotsList VPS snapshots

See Terraform Data Sources for detailed documentation.

Supported Datacenters

All resources are deployed to our single datacenter:

CodeLocationCountry
fsn1FalkensteinGermany

State Management

Terraform tracks your infrastructure state in a state file. The state — not your API token — records which resources Terraform already manages, so it is what decides whether a plan creates, changes or destroys something. For team collaboration, use a remote backend.

Using DanubeData Object Storage as Backend

HCL
terraform {
  backend "s3" {
    bucket = "terraform-state"
    key    = "my-project/terraform.tfstate"
    region = "fsn1"

    endpoints = { s3 = "https://s3.danubedata.ro" }

    use_path_style              = true
    use_lockfile                = true
    skip_credentials_validation = true
    skip_requesting_account_id  = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    skip_s3_checksum            = true
  }
}

The skip_* flags are required: our object storage is S3-compatible but is not AWS, so the AWS-specific credential, account-ID and metadata lookups have to be turned off. use_lockfile = true enables state locking against the bucket itself, with no DynamoDB table, so two CI runs cannot write the state at once — it needs Terraform 1.10 or later.

Set S3 credentials from a storage access key:

Bash
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"

Importing Existing Resources

You can import existing DanubeData resources into Terraform management:

Bash
# Import a VPS instance
terraform import danubedata_vps.my_server 12345

# Import a database
terraform import danubedata_database.my_db 67890

# Import a storage bucket
terraform import danubedata_storage_bucket.my_bucket abc123

Find resource IDs in the DanubeData dashboard or via the API.

Best Practices

Give Each Environment Its Own State

Separate environments need separate state. An API token decides which project a call goes to, but it does not change what Terraform already believes it manages — that comes from the state file.

Do not point one root module at several environments by changing a variable. If your state already holds a production resource and you re-run it with environment = "test", Terraform does not create something new: it compares the config against the resource it already tracks and plans to replace it. Attributes such as name, engine and database_name cannot be changed on a running instance, so the plan comes back as 1 to add, 1 to destroy — and the resource it destroys is the live production one.

Give each environment its own root module, its own state key and its own token:

Text
modules/stack/       shared resource definitions, taking env as a variable
envs/prod/           key prod/terraform.tfstate,  production token
envs/test/           key test/terraform.tfstate,  test token

Each environment directory holds only a backend block, a provider block and a call to the shared module:

HCL
# envs/test/main.tf
terraform {
  backend "s3" {
    bucket = "my-tfstate"
    key    = "test/terraform.tfstate"
    # ...remaining backend settings as above
  }
}

provider "danubedata" {}   # token from DANUBEDATA_API_TOKEN

module "stack" {
  source = "../../modules/stack"
  env    = "test"
}

Now terraform apply in envs/test/ starts from an empty state and creates the test resources, while production is untouched — because a different state file describes it.

Resource names are unique per project rather than globally, so the same name can be used in every environment and only values that must differ, such as a database's initial database name, need to include var.env.

Terraform workspaces are an alternative, but the API token still has to change per environment through the shell environment, so separate root modules are harder to get wrong.

Use One Project per Environment

Create a separate project (team) for each environment and issue each one its own API token, scoped to that project. Projects are the isolation boundary on our side: separate Kubernetes namespace, separate quotas and separate billing lines.

Mark Sensitive Outputs

HCL
output "database_password" {
  value     = danubedata_database.main.password
  sensitive = true
}

Use Terraform Cloud for Team Collaboration

For larger teams, consider using Terraform Cloud for:

  • Remote state management
  • Policy enforcement
  • VCS integration
  • Cost estimation

Troubleshooting

Authentication Errors

If you see "401 Unauthorized":

  1. Verify your API token is correct
  2. Check the token has the required permissions
  3. Ensure the DANUBEDATA_API_TOKEN environment variable is set

Provider Not Found

If Terraform can't find the provider:

Bash
terraform init -upgrade

Resource Timeouts

For long-running operations, configure timeouts:

HCL
resource "danubedata_vps" "app" {
  # ...

  timeouts {
    create = "10m"
    update = "10m"
    delete = "5m"
  }
}

Next Steps

Support