Synthèse automatique
Guide la rédaction de configurations OpenTofu/Terraform pour provisionner des ressources DigitalOcean telles que Droplets, VPC, bases de données managées et pare-feux.
Points forts
- Fournit des exemples HCL concrets pour VPC, Droplets, cloud-init, IP réservées et pare-feux
- Inclut un tableau des tailles de Droplets courantes avec leurs cas d'usage
- Montre des pratiques de sécurité utiles comme la surveillance, la restriction SSH et la désactivation de la connexion root
- Les extraits sont directement adaptables à un projet existant
Limites
- Ne couvre pas les produits DigitalOcean avancés comme Kubernetes, Spaces ou les load balancers
- Ne donne pas de recommandations sur le backend d'état, les modules ou l'organisation du code Terraform
- Le fichier fourni est tronqué dans la section sur la liste blanche d'IP dynamique
À utiliser lorsqu'il faut écrire ou étendre une infrastructure DigitalOcean en OpenTofu/Terraform avec des ressources de base.
À éviter si vous ciblez un autre fournisseur cloud ou si vous avez besoin de ressources DigitalOcean non décrites comme DOKS, Spaces ou les load balancers.
Analyse de sécurité
SûrThe skill is instructional Terraform/OpenTofu content for DigitalOcean resources; it does not run destructive commands, exfiltrate secrets, or obfuscate payloads. The declared Bash/Write/Edit tools are powerful but used for legitimate infrastructure authoring, and the examples follow normal cloud provisioning patterns with only minor hardening considerations.
- •Cloud-init example grants the deploy user passwordless sudo and docker group membership, which is a deliberate but elevated privilege choice.
- •Firewall example allows all outbound traffic and public HTTP/HTTPS; SSH is parameterized but no default restriction is shown.
- •Provider token is read from DIGITALOCEAN_TOKEN environment variable, avoiding hardcoded secrets.
Exemples
Write an OpenTofu configuration for a DigitalOcean Droplet in the nyc3 region using an s-2vcpu-4gb size, attached to a VPC, with cloud-init that installs Docker and creates a deploy user.Add a DigitalOcean firewall to my existing Droplet that allows SSH only from 203.0.113.0/24 and allows HTTP and HTTPS from anywhere.Create a DigitalOcean reserved IP and assign it to my app Droplet, exposing the IP as a Terraform output.name: digitalocean-coder description: This skill guides writing DigitalOcean infrastructure with OpenTofu/Terraform. Use when provisioning Droplets, VPCs, Managed Databases, Firewalls, or other DO resources. allowed-tools: Read, Write, Edit, Grep, Glob, Bash
DigitalOcean Coder
Overview
DigitalOcean provides simple, developer-friendly cloud infrastructure. This skill covers OpenTofu/Terraform patterns for DO resources.
Provider Setup
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}
provider "digitalocean" {
# Token from environment: DIGITALOCEAN_TOKEN
}
VPC (Virtual Private Cloud)
resource "digitalocean_vpc" "main" {
name = "${var.project}-${var.environment}-vpc"
region = var.region
ip_range = "10.10.0.0/16"
description = "VPC for ${var.project} ${var.environment}"
}
Droplets (Compute)
Basic Droplet
resource "digitalocean_droplet" "app" {
name = "${var.project}-${var.environment}-app"
region = var.region
size = var.droplet_size # s-1vcpu-1gb, s-2vcpu-4gb, etc.
image = "ubuntu-22-04-x64"
vpc_uuid = digitalocean_vpc.main.id
ssh_keys = var.ssh_key_ids
monitoring = true
ipv6 = false
tags = [var.project, var.environment]
}
Droplet with Cloud-Init
resource "digitalocean_droplet" "app" {
name = "${var.project}-app"
region = var.region
size = "s-1vcpu-2gb"
image = "ubuntu-22-04-x64"
vpc_uuid = digitalocean_vpc.main.id
ssh_keys = var.ssh_key_ids
monitoring = true
user_data = <<-EOT
#cloud-config
package_update: true
packages:
- docker.io
- docker-compose-plugin
users:
- name: deploy
groups: docker
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ${var.deploy_ssh_key}
runcmd:
- systemctl enable --now docker
- sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
- systemctl restart sshd
EOT
tags = [var.project]
}
Common Droplet Sizes
| Size | vCPUs | Memory | Use Case |
|------|-------|--------|----------|
| s-1vcpu-1gb | 1 | 1 GB | Testing, small apps |
| s-1vcpu-2gb | 1 | 2 GB | Small production |
| s-2vcpu-4gb | 2 | 4 GB | Medium apps |
| s-4vcpu-8gb | 4 | 8 GB | Production workloads |
| c-2 | 2 | 4 GB | CPU-intensive |
| m-2vcpu-16gb | 2 | 16 GB | Memory-intensive |
Reserved IP (Static IP)
resource "digitalocean_reserved_ip" "app" {
region = var.region
}
resource "digitalocean_reserved_ip_assignment" "app" {
ip_address = digitalocean_reserved_ip.app.ip_address
droplet_id = digitalocean_droplet.app.id
}
output "app_ip" {
value = digitalocean_reserved_ip.app.ip_address
}
Firewall
Basic Web Server Firewall
resource "digitalocean_firewall" "web" {
name = "${var.project}-web-firewall"
droplet_ids = [digitalocean_droplet.app.id]
# Inbound rules
inbound_rule {
protocol = "tcp"
port_range = "22"
source_addresses = var.ssh_allowed_ips # Restrict SSH access
}
inbound_rule {
protocol = "tcp"
port_range = "80"
source_addresses = ["0.0.0.0/0", "::/0"]
}
inbound_rule {
protocol = "tcp"
port_range = "443"
source_addresses = ["0.0.0.0/0", "::/0"]
}
# Outbound rules
outbound_rule {
protocol = "tcp"
port_range = "all"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
outbound_rule {
protocol = "udp"
port_range = "all"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
outbound_rule {
protocol = "icmp"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
}
Dynamic IP Whitelist
variable "db_allowed_ips" {
type = list(string)
default = []
description = "IPs allowed to access database directly"
}
resource "digitalocean_database_firewall" "postgres" {
cluster_id = digitalocean_database_cluster.postgres.id
# Always allow app droplet
rule {
type = "droplet"
value = digitalocean_droplet.app.id
}
# Dynamic IP whitelist for developers
dynamic "rule" {
for_each = var.db_allowed_ips
content {
type = "ip_addr"
value = rule.value
}
}
}
Managed Database
PostgreSQL Cluster
resource "digitalocean_database_cluster" "postgres" {
name = "${var.project}-${var.environment}-pg"
engine = "pg"
version = "16"
size = var.db_size # db-s-1vcpu-1gb, db-s-2vcpu-4gb
region = var.region
node_count = 1 # Increase for HA
# CRITICAL: Use private network
private_network_uuid = digitalocean_vpc.main.id
tags = [var.project, var.environment]
}
# Database firewall - restrict access
resource "digitalocean_database_firewall" "postgres" {
cluster_id = digitalocean_database_cluster.postgres.id
rule {
type = "droplet"
value = digitalocean_droplet.app.id
}
}
output "database_uri" {
value = digitalocean_database_cluster.postgres.uri
sensitive = true
}
output "database_private_uri" {
value = digitalocean_database_cluster.postgres.private_uri
sensitive = true
}
Database Sizes
| Size | vCPUs | Memory | Storage | Use Case |
|------|-------|--------|---------|----------|
| db-s-1vcpu-1gb | 1 | 1 GB | 10 GB | Development |
| db-s-1vcpu-2gb | 1 | 2 GB | 25 GB | Small production |
| db-s-2vcpu-4gb | 2 | 4 GB | 38 GB | Production |
| db-s-4vcpu-8gb | 4 | 8 GB | 115 GB | High traffic |
Redis Cluster
resource "digitalocean_database_cluster" "redis" {
name = "${var.project}-${var.environment}-redis"
engine = "redis"
version = "7"
size = "db-s-1vcpu-1gb"
region = var.region
node_count = 1
private_network_uuid = digitalocean_vpc.main.id
tags = [var.project]
}
Spaces (Object Storage)
resource "digitalocean_spaces_bucket" "assets" {
name = "${var.project}-assets"
region = var.spaces_region # nyc3, sfo3, ams3, sgp1, fra1
acl = "private" # or "public-read"
}
resource "digitalocean_spaces_bucket_cors_configuration" "assets" {
bucket = digitalocean_spaces_bucket.assets.id
region = var.spaces_region
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET", "PUT", "POST"]
allowed_origins = ["https://${var.domain}"]
max_age_seconds = 3600
}
}
output "spaces_endpoint" {
value = digitalocean_spaces_bucket.assets.bucket_domain_name
}
DNS Records
resource "digitalocean_domain" "main" {
name = var.domain
}
resource "digitalocean_record" "app" {
domain = digitalocean_domain.main.id
type = "A"
name = "@"
value = digitalocean_reserved_ip.app.ip_address
ttl = 300
}
resource "digitalocean_record" "www" {
domain = digitalocean_domain.main.id
type = "CNAME"
name = "www"
value = "@"
ttl = 300
}
SSH Keys
# Reference existing key
data "digitalocean_ssh_key" "deploy" {
name = "deploy-key"
}
# Or create new key
resource "digitalocean_ssh_key" "deploy" {
name = "${var.project}-deploy"
public_key = file("~/.ssh/deploy.pub")
}
Complete Production Stack
locals {
name_prefix = "${var.project}-${var.environment}"
}
# VPC
resource "digitalocean_vpc" "main" {
name = "${local.name_prefix}-vpc"
region = var.region
ip_range = "10.10.0.0/16"
}
# App Server
resource "digitalocean_droplet" "app" {
name = "${local.name_prefix}-app"
region = var.region
size = var.droplet_size
image = "ubuntu-22-04-x64"
vpc_uuid = digitalocean_vpc.main.id
ssh_keys = [data.digitalocean_ssh_key.deploy.id]
monitoring = true
user_data = file("${path.module}/cloud-init.yaml")
tags = [var.project, var.environment]
}
# Static IP
resource "digitalocean_reserved_ip" "app" {
region = var.region
}
resource "digitalocean_reserved_ip_assignment" "app" {
ip_address = digitalocean_reserved_ip.app.ip_address
droplet_id = digitalocean_droplet.app.id
}
# Firewall
resource "digitalocean_firewall" "app" {
name = "${local.name_prefix}-firewall"
droplet_ids = [digitalocean_droplet.app.id]
inbound_rule {
protocol = "tcp"
port_range = "22"
source_addresses = var.ssh_allowed_ips
}
inbound_rule {
protocol = "tcp"
port_range = "80"
source_addresses = ["0.0.0.0/0", "::/0"]
}
inbound_rule {
protocol = "tcp"
port_range = "443"
source_addresses = ["0.0.0.0/0", "::/0"]
}
outbound_rule {
protocol = "tcp"
port_range = "all"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
outbound_rule {
protocol = "udp"
port_range = "all"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
}
# Database
resource "digitalocean_database_cluster" "postgres" {
name = "${local.name_prefix}-pg"
engine = "pg"
version = "16"
size = var.db_size
region = var.region
node_count = 1
private_network_uuid = digitalocean_vpc.main.id
tags = [var.project]
}
resource "digitalocean_database_firewall" "postgres" {
cluster_id = digitalocean_database_cluster.postgres.id
rule {
type = "droplet"
value = digitalocean_droplet.app.id
}
}
# Outputs
output "app_ip" {
value = digitalocean_reserved_ip.app.ip_address
}
output "database_uri" {
value = digitalocean_database_cluster.postgres.private_uri
sensitive = true
}
Best Practices
Security
- Always use VPC for private networking
- Restrict database to droplet access only
- Use reserved IPs for consistent addressing
- Limit SSH to specific IPs via firewall
- Use cloud-init to disable root login
Cost Optimization
- Use appropriate droplet sizes
- Single-node databases for non-critical workloads
- Reserved IPs are free when assigned
- Monitor with built-in metrics
Networking
- Use
private_urifor database connections - Place all resources in same VPC
- Use firewall rules, not iptables
- Enable monitoring on droplets
Rapport de Post-Mortem
DevOps
Rédige des rapports post-mortem d'incidents structurés et blameless.
Créateur de Runbooks
DevOps
Crée des runbooks opérationnels clairs pour les procédures DevOps courantes.
Pré-vérification kube-coder (CI locale)
DevOps
Exécutez localement la suite CI complète de kube-coder avant de pousser : lint Helm, tests unitaires, builds SPA, vitest et vérifications shell. Garantit un CI vert dès le premier push.