DigitalOcean Droplet Stack
Hardened droplet(s) with VPC, firewall, volume, reserved IP, and cloud-init bootstrap.
Verification
Static-verifiedPassed: validated and lint-clean (provider-schema-validated for AWS/Azure/GCP; Terraform-language lint elsewhere).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan clean (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-06-28 · how we verify
Documentation
do-droplet-stack
Hardened droplet(s) with VPC, firewall, volume, reserved IP, and cloud-init
bootstrap. One module call gives you N identical droplets in a dedicated VPC
behind a deny-by-default cloud firewall, with optional per-droplet block-storage
data volumes and a reserved (static) IP that survives droplet rebuilds. Works
with Terraform and OpenTofu (>= 1.6), DigitalOcean provider
>= 2.0, < 3.0.
Secure defaults:
- Deny-by-default cloud firewall — no inbound port is open (including SSH) until you allowlist sources
- SSH-key-only access (
ssh_key_idsis required; no password logins) - Dedicated VPC per stack (private traffic never shares the region default VPC)
- Monitoring agent on by default; public IPv6 off by default
Usage
module "stack" {
source = "./do-droplet-stack"
name = "web"
region = "fra1"
droplet_count = 2
ssh_key_ids = ["12345678"]
ssh_source_addresses = ["203.0.113.0/24"] # bastion / office CIDR
inbound_rules = [
{ protocol = "tcp", port_range = "443", source_addresses = ["0.0.0.0/0", "::/0"] },
]
volume_size_gb = 50
enable_reserved_ip = true
tags = ["env:prod"]
}
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
name | string | — | Base name for all resources (required) |
region | string | — | DigitalOcean region slug, e.g. fra1 (required) |
ssh_key_ids | list(string) | — | SSH key IDs/fingerprints for root access (required, non-empty) |
droplet_count | number | 1 | Number of identical droplets (1–20) |
size | string | s-1vcpu-2gb | Droplet size slug |
image | string | ubuntu-24-04-x64 | Image slug or custom image ID |
user_data | string | null | Cloud-init bootstrap (changing replaces droplets) |
monitoring | bool | true | Install the DO monitoring agent |
backups | bool | false | Automated droplet backups (+20% cost) |
ipv6 | bool | false | Public IPv6 on droplets |
droplet_agent | bool | true | Agent for web-console access |
create_vpc | bool | true | Create a dedicated VPC for the stack |
vpc_uuid | string | null | Existing VPC UUID (when create_vpc = false) |
vpc_ip_range | string | null | CIDR for the created VPC (null = auto) |
ssh_source_addresses | list(string) | [] | CIDRs allowed to reach SSH; empty = SSH closed |
inbound_rules | list(object) | [] | Extra inbound rules {protocol, port_range, source_addresses} |
volume_size_gb | number | 0 | Data volume per droplet in GiB; 0 = disabled |
volume_filesystem_type | string | ext4 | ext4 or xfs |
enable_reserved_ip | bool | false | Reserved (static) IP on the first droplet |
tags | list(string) | [] | DO tags applied to all taggable resources |
Outputs
droplet_ids, droplet_urns, droplet_public_ipv4, droplet_private_ipv4,
droplet_ipv6, vpc_uuid, firewall_id, volume_ids, reserved_ip — all
maps are keyed by droplet name.
Requirements
- Terraform or OpenTofu
>= 1.6 digitalocean/digitaloceanprovider>= 2.0, < 3.0
Verification
Static-validated (fmt, validate, tflint). Live apply/destroy testing pending cloud sandbox availability — see catalog status.
License
Commercial — IaC Bazaar EULA. © IaC Bazaar. Original work (not derived from a third-party module).