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
- Terraform Overview - Getting started guide
- Terraform Resources - Resource documentation
- Terraform Data Sources - Data source documentation
- Terraform Registry - Official provider docs