# DigitalOcean Provider Guide\n\nThis guide covers using DigitalOcean as a cloud provider in the provisioning system. DigitalOcean is known for simplicity, straightforward pricing,\nand outstanding documentation, making it ideal for startups, small teams, and developers.\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Why DigitalOcean](#why-digitalocean)\n- [Setup and Configuration](#setup-and-configuration)\n- [Available Resources](#available-resources)\n- [Nickel Schema Reference](#nickel-schema-reference)\n- [Configuration Examples](#configuration-examples)\n- [Best Practices](#best-practices)\n- [Troubleshooting](#troubleshooting)\n\n## Overview\n\nDigitalOcean offers a simplified cloud platform with competitive pricing and outstanding developer experience. Key characteristics:\n\n- **Transparent Pricing**: No hidden fees, simple per-resource pricing\n- **Global Presence**: Data centers in North America, Europe, and Asia\n- **Managed Services**: Databases, Kubernetes (DOKS), App Platform\n- **Developer-Friendly**: Outstanding documentation and community support\n- **Performance**: Consistent performance, modern infrastructure\n\n### DigitalOcean Pricing Model\n\nUnlike AWS, DigitalOcean uses hourly billing with transparent monthly rates:\n\n- **Droplets**: $0.03/hour (typically billed monthly)\n- **Volumes**: $0.10/GB/month\n- **Managed Database**: Price varies by tier\n- **Load Balancer**: $10/month\n- **Data Transfer**: Generally included for inbound, charged for outbound\n\n### Supported Resources\n\n| Resource | Product Name | Status |\n| ---------- | -------------- | -------- |\n| Compute | Droplets | ✓ Full support |\n| Block Storage | Volumes | ✓ Full support |\n| Object Storage | Spaces | ✓ Full support |\n| Load Balancer | Load Balancer | ✓ Full support |\n| Database | Managed Databases | ✓ Full support |\n| Container Registry | Container Registry | ✓ Supported |\n| CDN | CDN | ✓ Supported |\n| DNS | Domains | ✓ Full support |\n| VPC | VPC | ✓ Full support |\n| Firewall | Firewall | ✓ Full support |\n| Reserved IPs | Reserved IPs | ✓ Supported |\n\n## Why DigitalOcean\n\n### When to Choose DigitalOcean\n\n**DigitalOcean is ideal for**:\n\n- **Startups**: Clear pricing, low minimum commitment\n- **Small Teams**: Simple management interface\n- **Developers**: Great documentation, API-driven\n- **Regional Deployment**: Global presence, predictable costs\n- **Managed Services**: Simple database and Kubernetes offerings\n- **Web Applications**: Outstanding fit for typical web workloads\n\n**DigitalOcean is NOT ideal for**:\n\n- **Highly Specialized Workloads**: Limited service portfolio vs AWS\n- **HIPAA/FedRAMP**: Limited compliance options\n- **Extreme Performance**: Not focused on HPC\n- **Enterprise with Complex Requirements**: Better served by AWS\n\n### Cost Comparison\n\n**Monthly Comparison**: 2 vCPU, 4 GB RAM\n\n- DigitalOcean: $24/month (constant pricing)\n- Hetzner: €6.90/month (~$7.50) - cheaper but harder to scale\n- AWS: $60/month on-demand (but $18 with spot)\n- UpCloud: $30/month\n\n**When DigitalOcean Wins**:\n- Simplicity and transparency (no reserved instances needed)\n- Managed database costs\n- Small deployments (1-5 servers)\n- Applications using DigitalOcean-specific services\n\n## Setup and Configuration\n\n### Prerequisites\n\n- DigitalOcean account with billing enabled\n- API token from DigitalOcean Control Panel\n- doctl CLI installed (optional but recommended)\n- Provisioning system with DigitalOcean provider plugin\n\n### Step 1: Create DigitalOcean API Token\n\n1. Go to [DigitalOcean Control Panel](https://cloud.digitalocean.com/)\n2. Navigate to **API** > **Tokens/Keys**\n3. Click **Generate New Token**\n4. Set expiration to 90 days or custom\n5. Select **Read & Write** scope\n6. Copy the token (you can only view it once)\n\n### Step 2: Configure Environment Variables\n\n```\n# Add to ~/.bashrc, ~/.zshrc, or env file\nexport DIGITALOCEAN_TOKEN="dop_v1_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"\n\n# Optional: Default region for all operations\nexport DIGITALOCEAN_REGION="nyc3"\n```\n\n### Step 3: Verify Configuration\n\n```\n# Using provisioning CLI\nprovisioning provider verify digitalocean\n\n# Or using doctl\ndoctl auth init\ndoctl compute droplet list\n```\n\n### Step 4: Configure Workspace\n\nCreate or update `config.toml` in your workspace:\n\n```\n[providers.digitalocean]\nenabled = true\ntoken_env = "DIGITALOCEAN_TOKEN"\ndefault_region = "nyc3"\n\n[workspace]\nprovider = "digitalocean"\nregion = "nyc3"\n```\n\n## Available Resources\n\n### 1. Droplets (Compute)\n\nDigitalOcean's core compute offering - cloud servers with hourly billing.\n\n**Resource Type**: `digitalocean.Droplet`\n\n**Available Sizes**:\n\n| Size Slug | vCPU | RAM | Storage | Price/Month |\n| ----------- | ------ | ----- | --------- | ------------ |\n| s-1vcpu-512 m-10gb | 1 | 512 MB | 10 GB SSD | $4 |\n| s-1vcpu-1gb-25gb | 1 | 1 GB | 25 GB SSD | $6 |\n| s-2vcpu-2gb-50gb | 2 | 2 GB | 50 GB SSD | $12 |\n| s-2vcpu-4gb-80gb | 2 | 4 GB | 80 GB SSD | $24 |\n| s-4vcpu-8gb | 4 | 8 GB | 160 GB SSD | $48 |\n| s-6vcpu-16gb | 6 | 16 GB | 320 GB SSD | $96 |\n| c-2 | 2 | 4 GB | 50 GB SSD | $40 (CPU-optimized) |\n| g-2vcpu-8gb | 2 | 8 GB | 50 GB SSD | $60 (GPU) |\n\n**Key Features**:\n- SSD storage\n- Hourly or monthly billing\n- Automatic backups\n- SSH key management\n- Private networking via VPC\n- Firewall rules\n- Monitoring and alerting\n\n### 2. Volumes (Block Storage)\n\nPersistent block storage that can be attached to Droplets.\n\n**Resource Type**: `digitalocean.Volume`\n\n**Characteristics**:\n- $0.10/GB/month\n- SSD-based\n- Snapshots for backup\n- Maximum 100 TB size\n- Automatic backups\n\n### 3. Spaces (Object Storage)\n\nS3-compatible object storage for files, backups, media.\n\n**Characteristics**:\n- $5/month for 250 GB\n- Then $0.015/GB for additional storage\n- $0.01/GB outbound transfer\n- Versioning support\n- CDN integration available\n\n### 4. Load Balancer\n\nLayer 4/7 load balancing with health checks.\n\n**Price**: $10/month\n\n**Features**:\n- Round robin, least connections algorithms\n- Health checks on Droplets\n- SSL/TLS termination\n- Sticky sessions\n- HTTP/HTTPS support\n\n### 5. Managed Databases\n\nPostgreSQL, MySQL, and Redis databases.\n\n**Price Examples**:\n- Single node PostgreSQL (1 GB RAM): $15/month\n- 3-node HA cluster: $60/month\n- Enterprise plans available\n\n**Features**:\n- Automated backups\n- Read replicas\n- High availability option\n- Connection pooling\n- Monitoring dashboard\n\n### 6. Kubernetes (DOKS)\n\nManaged Kubernetes service.\n\n**Price**: $12/month per cluster + node costs\n\n**Features**:\n- Managed control plane\n- Autoscaling node pools\n- Integrated monitoring\n- Container Registry integration\n\n### 7. CDN\n\nContent Delivery Network for global distribution.\n\n**Price**: $0.005/GB delivered\n\n**Features**:\n- 600+ edge locations\n- Purge cache by path\n- Custom domains with SSL\n- Edge caching\n\n### 8. Domains and DNS\n\nDomain registration and DNS management.\n\n**Features**:\n- Domain registration via Namecheap\n- Free DNS hosting\n- TTL control\n- MX records, CNAMEs, etc.\n\n### 9. VPC (Virtual Private Cloud)\n\nPrivate networking between resources.\n\n**Features**:\n- Free tier (1 VPC included)\n- Isolation between resources\n- Custom IP ranges\n- Subnet management\n\n### 10. Firewall\n\nNetwork firewall rules.\n\n**Features**:\n- Inbound/outbound rules\n- Protocol-specific (TCP, UDP, ICMP)\n- Source/destination filtering\n- Rule priorities\n\n## Nickel Schema Reference\n\n### Droplet Configuration\n\n```\nlet digitalocean = import "../../extensions/providers/digitalocean/nickel/main.ncl" in\n\ndigitalocean.Droplet & {\n  # Required\n  name = "my-droplet",\n  region = "nyc3",\n  size = "s-2vcpu-4gb",\n\n  # Optional\n  image = "ubuntu-22-04-x64",  # Default: ubuntu-22-04-x64\n  count = 1,  # Number of identical droplets\n  ssh_keys = ["key-id-1"],\n  backups = false,\n  ipv6 = true,\n  monitoring = true,\n  vpc_uuid = "vpc-id",\n\n  # Volumes to attach\n  volumes = [\n    {\n      size = 100,\n      name = "data-volume",\n      filesystem_type = "ext4",\n      filesystem_label = "data"\n    }\n  ],\n\n  # Firewall configuration\n  firewall = {\n    inbound_rules = [\n      {\n        protocol = "tcp",\n        ports = "22",\n        sources = {\n          addresses = ["0.0.0.0/0"],\n          droplet_ids = [],\n          tags = []\n        }\n      },\n      {\n        protocol = "tcp",\n        ports = "80",\n        sources = {\n          addresses = ["0.0.0.0/0"]\n        }\n      },\n      {\n        protocol = "tcp",\n        ports = "443",\n        sources = {\n          addresses = ["0.0.0.0/0"]\n        }\n      }\n    ],\n\n    outbound_rules = [\n      {\n        protocol = "tcp",\n        destinations = {\n          addresses = ["0.0.0.0/0"]\n        }\n      },\n      {\n        protocol = "udp",\n        ports = "53",\n        destinations = {\n          addresses = ["0.0.0.0/0"]\n        }\n      }\n    ]\n  },\n\n  # Tags\n  tags = ["web", "production"],\n\n  # User data (startup script)\n  user_data = "#!/bin/bash\napt-get update\napt-get install -y nginx"\n}\n```\n\n### Load Balancer Configuration\n\n```\ndigitalocean.LoadBalancer & {\n  name = "web-lb",\n  algorithm = "round_robin",  # or "least_connections"\n  region = "nyc3",\n\n  # Forwarding rules\n  forwarding_rules = [\n    {\n      entry_protocol = "http",\n      entry_port = 80,\n      target_protocol = "http",\n      target_port = 80,\n      certificate_id = null\n    },\n    {\n      entry_protocol = "https",\n      entry_port = 443,\n      target_protocol = "http",\n      target_port = 80,\n      certificate_id = "cert-id"\n    }\n  ],\n\n  # Health checks\n  health_check = {\n    protocol = "http",\n    port = 80,\n    path = "/health",\n    check_interval_seconds = 10,\n    response_timeout_seconds = 5,\n    healthy_threshold = 5,\n    unhealthy_threshold = 3\n  },\n\n  # Sticky sessions\n  sticky_sessions = {\n    type = "cookies",\n    cookie_name = "LB",\n    cookie_ttl_seconds = 300\n  }\n}\n```\n\n### Volume Configuration\n\n```\ndigitalocean.Volume & {\n  name = "data-volume",\n  size = 100,  # GB\n  region = "nyc3",\n  description = "Application data volume",\n  snapshots = true,\n\n  # To attach to a Droplet\n  attachment = {\n    droplet_id = "droplet-id",\n    mount_point = "/data"\n  }\n}\n```\n\n### Managed Database Configuration\n\n```\ndigitalocean.Database & {\n  name = "prod-db",\n  engine = "pg",  # or "mysql", "redis"\n  version = "14",\n  size = "db-s-1vcpu-1gb",\n  region = "nyc3",\n  num_nodes = 1,  # or 3 for HA\n\n  # High availability\n  multi_az = false,\n\n  # Backups\n  backup_restore = {\n    backup_created_at = "2024-01-01T00:00:00Z"\n  }\n}\n```\n\n## Configuration Examples\n\n### Example 1: Simple Web Server\n\n```\nlet digitalocean = import "../../extensions/providers/digitalocean/nickel/main.ncl" in\n\n{\n  workspace_name = "simple-web",\n\n  web_server = digitalocean.Droplet & {\n    name = "web-01",\n    region = "nyc3",\n    size = "s-1vcpu-1gb-25gb",\n    image = "ubuntu-22-04-x64",\n    ssh_keys = ["your-ssh-key-id"],\n\n    user_data = ''\n      #!/bin/bash\n      apt-get update\n      apt-get install -y nginx\n      systemctl start nginx\n      systemctl enable nginx\n    '',\n\n    firewall = {\n      inbound_rules = [\n        { protocol = "tcp", ports = "22", sources = { addresses = ["YOUR_IP/32"] } },\n        { protocol = "tcp", ports = "80", sources = { addresses = ["0.0.0.0/0"] } },\n        { protocol = "tcp", ports = "443", sources = { addresses = ["0.0.0.0/0"] } }\n      ]\n    },\n\n    monitoring = true\n  }\n}\n```\n\n### Example 2: Web Application with Database\n\n```\n{\n  web_tier = digitalocean.Droplet & {\n    name = "web-server",\n    region = "nyc3",\n    size = "s-2vcpu-4gb",\n    count = 2,\n\n    firewall = {\n      inbound_rules = [\n        { protocol = "tcp", ports = "22", sources = { addresses = ["0.0.0.0/0"] } },\n        { protocol = "tcp", ports = "80", sources = { addresses = ["0.0.0.0/0"] } },\n        { protocol = "tcp", ports = "443", sources = { addresses = ["0.0.0.0/0"] } }\n      ]\n    },\n\n    tags = ["web", "production"]\n  },\n\n  load_balancer = digitalocean.LoadBalancer & {\n    name = "web-lb",\n    region = "nyc3",\n    algorithm = "round_robin",\n\n    forwarding_rules = [\n      {\n        entry_protocol = "http",\n        entry_port = 80,\n        target_protocol = "http",\n        target_port = 8080\n      }\n    ],\n\n    health_check = {\n      protocol = "http",\n      port = 8080,\n      path = "/health",\n      check_interval_seconds = 10,\n      response_timeout_seconds = 5\n    }\n  },\n\n  database = digitalocean.Database & {\n    name = "app-db",\n    engine = "pg",\n    version = "14",\n    size = "db-s-1vcpu-1gb",\n    region = "nyc3",\n    multi_az = true\n  }\n}\n```\n\n### Example 3: High-Performance Storage\n\n```\n{\n  app_server = digitalocean.Droplet & {\n    name = "app-with-storage",\n    region = "nyc3",\n    size = "s-4vcpu-8gb",\n\n    volumes = [\n      {\n        size = 500,\n        name = "app-storage",\n        filesystem_type = "ext4"\n      }\n    ]\n  },\n\n  backup_storage = digitalocean.Volume & {\n    name = "backup-volume",\n    size = 1000,\n    region = "nyc3",\n    description = "Backup storage for app data"\n  }\n}\n```\n\n## Best Practices\n\n### 1. Droplet Management\n\n**Instance Sizing**\n- Start with smallest viable size (s-1vcpu-1gb)\n- Monitor CPU/memory usage\n- Scale vertically for predictable workloads\n- Use autoscaling with Kubernetes for bursty workloads\n\n**SSH Key Management**\n- Use SSH keys instead of passwords\n- Store private keys securely\n- Rotate keys regularly (at least yearly)\n- Different keys for different environments\n\n**Monitoring**\n- Enable monitoring on all Droplets\n- Set up alerting for CPU > 80%\n- Monitor disk usage\n- Alert on high memory usage\n\n### 2. Firewall Configuration\n\n**Principle of Least Privilege**\n- Only allow necessary ports\n- Specify source IPs when possible\n- Use SSH key authentication (no passwords)\n- Block unnecessary outbound traffic\n\n**Default Rules**\n```\n# Minimal firewall for web server\ninbound_rules = [\n  { protocol = "tcp", ports = "22", sources = { addresses = ["YOUR_OFFICE_IP/32"] } },\n  { protocol = "tcp", ports = "80", sources = { addresses = ["0.0.0.0/0"] } },\n  { protocol = "tcp", ports = "443", sources = { addresses = ["0.0.0.0/0"] } }\n],\n\noutbound_rules = [\n  { protocol = "tcp", destinations = { addresses = ["0.0.0.0/0"] } },\n  { protocol = "udp", ports = "53", destinations = { addresses = ["0.0.0.0/0"] } }\n]\n```\n\n### 3. Database Best Practices\n\n**High Availability**\n- Use 3-node clusters for production\n- Enable automated backups (retain for 30 days)\n- Test backup restore procedures\n- Use read replicas for scaling reads\n\n**Connection Pooling**\n- Enable PgBouncer for PostgreSQL\n- Set pool size based on app connections\n- Monitor connection count\n\n**Backup Strategy**\n- Daily automated backups (DigitalOcean manages)\n- Export critical data to Spaces weekly\n- Test restore procedures monthly\n- Keep backups for minimum 30 days\n\n### 4. Volume Management\n\n**Data Persistence**\n- Use volumes for stateful data\n- Don't store critical data on Droplet root volume\n- Enable automatic snapshots\n- Document mount points\n\n**Capacity Planning**\n- Monitor volume usage\n- Expand volumes as needed (no downtime)\n- Delete old snapshots to save costs\n\n### 5. Load Balancer Configuration\n\n**Health Checks**\n- Set appropriate health check paths\n- Conservative intervals (10-30 seconds)\n- Longer timeout to avoid false positives\n- Multiple healthy thresholds\n\n**Sticky Sessions**\n- Use if application requires session affinity\n- Set appropriate TTL (300-3600 seconds)\n- Monitor for imbalanced traffic\n\n### 6. Cost Optimization\n\n**Droplet Sizing**\n- Right-size instances to actual needs\n- Use snapshots to create custom images\n- Destroy unused Droplets\n\n**Reserved Droplets**\n- Pre-pay for predictable workloads\n- 25-30% savings vs hourly\n\n**Object Storage**\n- Use lifecycle policies to delete old data\n- Compress data before uploading\n- Use CDN for frequent access (reduces egress)\n\n## Troubleshooting\n\n### Issue: Droplet Not Accessible\n\n**Symptoms**: Cannot SSH to Droplet, connection timeout\n\n**Diagnosis**:\n1. Verify Droplet status in DigitalOcean Control Panel\n2. Check firewall rules allow port 22 from your IP\n3. Verify SSH key is loaded in SSH agent: `ssh-add -l`\n4. Check Droplet has public IP assigned\n\n**Solution**:\n```\n# Add to firewall\ndoctl compute firewall add-rules firewall-id \\n  --inbound-rules="protocol:tcp,ports:22,sources:addresses:YOUR_IP"\n\n# Test SSH\nssh -v -i ~/.ssh/key.pem root@DROPLET_IP\n\n# Or use VNC console in Control Panel\n```\n\n### Issue: Volume Not Mounting\n\n**Symptoms**: Volume created but not accessible, mount fails\n\n**Diagnosis**:\n```\n# Check volume attachment\ndoctl compute volume list\n\n# On Droplet, check block devices\nlsblk\n\n# Check filesystem\nsudo file -s /dev/sdb\n```\n\n**Solution**:\n```\n# Format volume (only first time)\nsudo mkfs.ext4 /dev/sdb\n\n# Create mount point\nsudo mkdir -p /data\n\n# Mount volume\nsudo mount /dev/sdb /data\n\n# Make permanent by editing /etc/fstab\necho '/dev/sdb /data ext4 defaults,nofail,discard 0 0' | sudo tee -a /etc/fstab\n```\n\n### Issue: Load Balancer Health Checks Failing\n\n**Symptoms**: Backends marked unhealthy, traffic not flowing\n\n**Diagnosis**:\n```\n# Test health check endpoint manually\ncurl -i http://BACKEND_IP:8080/health\n\n# Check backend logs\nssh backend-server\ntail -f /var/log/app.log\n```\n\n**Solution**:\n- Verify endpoint returns HTTP 200\n- Check backend firewall allows load balancer IPs\n- Adjust health check timing (increase timeout)\n- Verify backend service is running\n\n### Issue: Database Connection Issues\n\n**Symptoms**: Cannot connect to managed database\n\n**Diagnosis**:\n```\n# Test connectivity from Droplet\npsql -h db-host.db.ondigitalocean.com -U admin -d defaultdb\n\n# Check firewall\ndoctl compute firewall list-rules firewall-id\n```\n\n**Solution**:\n- Add Droplet to database's trusted sources\n- Verify connection string (host, port, username)\n- Check database is accepting connections\n- For 3-node cluster, use connection pool endpoint\n\n## Summary\n\nDigitalOcean provides a simple, transparent platform ideal for developers and small teams. Its key advantages are:\n\n✓ Simple pricing and transparent costs\n✓ Excellent documentation\n✓ Good performance for typical workloads\n✓ Managed services (databases, Kubernetes)\n✓ Global presence\n✓ Developer-friendly interface\n\nStart small with a single Droplet and expand to managed services as your application grows.\n\nFor more information, visit: [DigitalOcean Documentation](https://www.digitalocean.com/docs/)
