# DigitalOcean Provider Guide

This guide covers using DigitalOcean as a cloud provider in the provisioning system. DigitalOcean is known for simplicity, straightforward pricing, and outstanding documentation, making it ideal for startups, small teams, and developers.

## Table of Contents

- [Overview](#overview)
- [Why DigitalOcean](#why-digitalocean)
- [Setup and Configuration](#setup-and-configuration)
- [Available Resources](#available-resources)
- [Nickel Schema Reference](#nickel-schema-reference)
- [Configuration Examples](#configuration-examples)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)

## Overview

DigitalOcean offers a simplified cloud platform with competitive pricing and outstanding developer experience. Key characteristics:

- **Transparent Pricing**: No hidden fees, simple per-resource pricing
- **Global Presence**: Data centers in North America, Europe, and Asia
- **Managed Services**: Databases, Kubernetes (DOKS), App Platform
- **Developer-Friendly**: Outstanding documentation and community support
- **Performance**: Consistent performance, modern infrastructure

### DigitalOcean Pricing Model

Unlike AWS, DigitalOcean uses hourly billing with transparent monthly rates:

- **Droplets**: $0.03/hour (typically billed monthly)
- **Volumes**: $0.10/GB/month
- **Managed Database**: Price varies by tier
- **Load Balancer**: $10/month
- **Data Transfer**: Generally included for inbound, charged for outbound

### Supported Resources

| Resource | Product Name | Status |
|----------|--------------|--------|
| Compute | Droplets | ✓ Full support |
| Block Storage | Volumes | ✓ Full support |
| Object Storage | Spaces | ✓ Full support |
| Load Balancer | Load Balancer | ✓ Full support |
| Database | Managed Databases | ✓ Full support |
| Container Registry | Container Registry | ✓ Supported |
| CDN | CDN | ✓ Supported |
| DNS | Domains | ✓ Full support |
| VPC | VPC | ✓ Full support |
| Firewall | Firewall | ✓ Full support |
| Reserved IPs | Reserved IPs | ✓ Supported |

## Why DigitalOcean

### When to Choose DigitalOcean

**DigitalOcean is ideal for**:

- **Startups**: Clear pricing, low minimum commitment
- **Small Teams**: Simple management interface
- **Developers**: Great documentation, API-driven
- **Regional Deployment**: Global presence, predictable costs
- **Managed Services**: Simple database and Kubernetes offerings
- **Web Applications**: Outstanding fit for typical web workloads

**DigitalOcean is NOT ideal for**:

- **Highly Specialized Workloads**: Limited service portfolio vs AWS
- **HIPAA/FedRAMP**: Limited compliance options
- **Extreme Performance**: Not focused on HPC
- **Enterprise with Complex Requirements**: Better served by AWS

### Cost Comparison

**Monthly Comparison**: 2 vCPU, 4 GB RAM

- DigitalOcean: $24/month (constant pricing)
- Hetzner: €6.90/month (~$7.50) - cheaper but harder to scale
- AWS: $60/month on-demand (but $18 with spot)
- UpCloud: $30/month

**When DigitalOcean Wins**:
- Simplicity and transparency (no reserved instances needed)
- Managed database costs
- Small deployments (1-5 servers)
- Applications using DigitalOcean-specific services

## Setup and Configuration

### Prerequisites

- DigitalOcean account with billing enabled
- API token from DigitalOcean Control Panel
- doctl CLI installed (optional but recommended)
- Provisioning system with DigitalOcean provider plugin

### Step 1: Create DigitalOcean API Token

1. Go to [DigitalOcean Control Panel](https://cloud.digitalocean.com/)
2. Navigate to **API** > **Tokens/Keys**
3. Click **Generate New Token**
4. Set expiration to 90 days or custom
5. Select **Read & Write** scope
6. Copy the token (you can only view it once)

### Step 2: Configure Environment Variables

```bash
# Add to ~/.bashrc, ~/.zshrc, or env file
export DIGITALOCEAN_TOKEN="dop_v1_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Optional: Default region for all operations
export DIGITALOCEAN_REGION="nyc3"
```

### Step 3: Verify Configuration

```bash
# Using provisioning CLI
provisioning provider verify digitalocean

# Or using doctl
doctl auth init
doctl compute droplet list
```

### Step 4: Configure Workspace

Create or update `config.toml` in your workspace:

```toml
[providers.digitalocean]
enabled = true
token_env = "DIGITALOCEAN_TOKEN"
default_region = "nyc3"

[workspace]
provider = "digitalocean"
region = "nyc3"
```

## Available Resources

### 1. Droplets (Compute)

DigitalOcean's core compute offering - cloud servers with hourly billing.

**Resource Type**: `digitalocean.Droplet`

**Available Sizes**:

| Size Slug | vCPU | RAM | Storage | Price/Month |
|-----------|------|-----|---------|------------|
| s-1vcpu-512 m-10gb | 1 | 512 MB | 10 GB SSD | $4 |
| s-1vcpu-1gb-25gb | 1 | 1 GB | 25 GB SSD | $6 |
| s-2vcpu-2gb-50gb | 2 | 2 GB | 50 GB SSD | $12 |
| s-2vcpu-4gb-80gb | 2 | 4 GB | 80 GB SSD | $24 |
| s-4vcpu-8gb | 4 | 8 GB | 160 GB SSD | $48 |
| s-6vcpu-16gb | 6 | 16 GB | 320 GB SSD | $96 |
| c-2 | 2 | 4 GB | 50 GB SSD | $40 (CPU-optimized) |
| g-2vcpu-8gb | 2 | 8 GB | 50 GB SSD | $60 (GPU) |

**Key Features**:
- SSD storage
- Hourly or monthly billing
- Automatic backups
- SSH key management
- Private networking via VPC
- Firewall rules
- Monitoring and alerting

### 2. Volumes (Block Storage)

Persistent block storage that can be attached to Droplets.

**Resource Type**: `digitalocean.Volume`

**Characteristics**:
- $0.10/GB/month
- SSD-based
- Snapshots for backup
- Maximum 100 TB size
- Automatic backups

### 3. Spaces (Object Storage)

S3-compatible object storage for files, backups, media.

**Characteristics**:
- $5/month for 250 GB
- Then $0.015/GB for additional storage
- $0.01/GB outbound transfer
- Versioning support
- CDN integration available

### 4. Load Balancer

Layer 4/7 load balancing with health checks.

**Price**: $10/month

**Features**:
- Round robin, least connections algorithms
- Health checks on Droplets
- SSL/TLS termination
- Sticky sessions
- HTTP/HTTPS support

### 5. Managed Databases

PostgreSQL, MySQL, and Redis databases.

**Price Examples**:
- Single node PostgreSQL (1 GB RAM): $15/month
- 3-node HA cluster: $60/month
- Enterprise plans available

**Features**:
- Automated backups
- Read replicas
- High availability option
- Connection pooling
- Monitoring dashboard

### 6. Kubernetes (DOKS)

Managed Kubernetes service.

**Price**: $12/month per cluster + node costs

**Features**:
- Managed control plane
- Autoscaling node pools
- Integrated monitoring
- Container Registry integration

### 7. CDN

Content Delivery Network for global distribution.

**Price**: $0.005/GB delivered

**Features**:
- 600+ edge locations
- Purge cache by path
- Custom domains with SSL
- Edge caching

### 8. Domains and DNS

Domain registration and DNS management.

**Features**:
- Domain registration via Namecheap
- Free DNS hosting
- TTL control
- MX records, CNAMEs, etc.

### 9. VPC (Virtual Private Cloud)

Private networking between resources.

**Features**:
- Free tier (1 VPC included)
- Isolation between resources
- Custom IP ranges
- Subnet management

### 10. Firewall

Network firewall rules.

**Features**:
- Inbound/outbound rules
- Protocol-specific (TCP, UDP, ICMP)
- Source/destination filtering
- Rule priorities

## Nickel Schema Reference

### Droplet Configuration

```nickel
let digitalocean = import "../../extensions/providers/digitalocean/nickel/main.ncl" in

digitalocean.Droplet & {
  # Required
  name = "my-droplet",
  region = "nyc3",
  size = "s-2vcpu-4gb",

  # Optional
  image = "ubuntu-22-04-x64",  # Default: ubuntu-22-04-x64
  count = 1,  # Number of identical droplets
  ssh_keys = ["key-id-1"],
  backups = false,
  ipv6 = true,
  monitoring = true,
  vpc_uuid = "vpc-id",

  # Volumes to attach
  volumes = [
    {
      size = 100,
      name = "data-volume",
      filesystem_type = "ext4",
      filesystem_label = "data"
    }
  ],

  # Firewall configuration
  firewall = {
    inbound_rules = [
      {
        protocol = "tcp",
        ports = "22",
        sources = {
          addresses = ["0.0.0.0/0"],
          droplet_ids = [],
          tags = []
        }
      },
      {
        protocol = "tcp",
        ports = "80",
        sources = {
          addresses = ["0.0.0.0/0"]
        }
      },
      {
        protocol = "tcp",
        ports = "443",
        sources = {
          addresses = ["0.0.0.0/0"]
        }
      }
    ],

    outbound_rules = [
      {
        protocol = "tcp",
        destinations = {
          addresses = ["0.0.0.0/0"]
        }
      },
      {
        protocol = "udp",
        ports = "53",
        destinations = {
          addresses = ["0.0.0.0/0"]
        }
      }
    ]
  },

  # Tags
  tags = ["web", "production"],

  # User data (startup script)
  user_data = "#!/bin/bash\napt-get update\napt-get install -y nginx"
}
```

### Load Balancer Configuration

```nickel
digitalocean.LoadBalancer & {
  name = "web-lb",
  algorithm = "round_robin",  # or "least_connections"
  region = "nyc3",

  # Forwarding rules
  forwarding_rules = [
    {
      entry_protocol = "http",
      entry_port = 80,
      target_protocol = "http",
      target_port = 80,
      certificate_id = null
    },
    {
      entry_protocol = "https",
      entry_port = 443,
      target_protocol = "http",
      target_port = 80,
      certificate_id = "cert-id"
    }
  ],

  # Health checks
  health_check = {
    protocol = "http",
    port = 80,
    path = "/health",
    check_interval_seconds = 10,
    response_timeout_seconds = 5,
    healthy_threshold = 5,
    unhealthy_threshold = 3
  },

  # Sticky sessions
  sticky_sessions = {
    type = "cookies",
    cookie_name = "LB",
    cookie_ttl_seconds = 300
  }
}
```

### Volume Configuration

```nickel
digitalocean.Volume & {
  name = "data-volume",
  size = 100,  # GB
  region = "nyc3",
  description = "Application data volume",
  snapshots = true,

  # To attach to a Droplet
  attachment = {
    droplet_id = "droplet-id",
    mount_point = "/data"
  }
}
```

### Managed Database Configuration

```nickel
digitalocean.Database & {
  name = "prod-db",
  engine = "pg",  # or "mysql", "redis"
  version = "14",
  size = "db-s-1vcpu-1gb",
  region = "nyc3",
  num_nodes = 1,  # or 3 for HA

  # High availability
  multi_az = false,

  # Backups
  backup_restore = {
    backup_created_at = "2024-01-01T00:00:00Z"
  }
}
```

## Configuration Examples

### Example 1: Simple Web Server

```nickel
let digitalocean = import "../../extensions/providers/digitalocean/nickel/main.ncl" in

{
  workspace_name = "simple-web",

  web_server = digitalocean.Droplet & {
    name = "web-01",
    region = "nyc3",
    size = "s-1vcpu-1gb-25gb",
    image = "ubuntu-22-04-x64",
    ssh_keys = ["your-ssh-key-id"],

    user_data = ''
      #!/bin/bash
      apt-get update
      apt-get install -y nginx
      systemctl start nginx
      systemctl enable nginx
    '',

    firewall = {
      inbound_rules = [
        { protocol = "tcp", ports = "22", sources = { addresses = ["YOUR_IP/32"] } },
        { protocol = "tcp", ports = "80", sources = { addresses = ["0.0.0.0/0"] } },
        { protocol = "tcp", ports = "443", sources = { addresses = ["0.0.0.0/0"] } }
      ]
    },

    monitoring = true
  }
}
```

### Example 2: Web Application with Database

```nickel
{
  web_tier = digitalocean.Droplet & {
    name = "web-server",
    region = "nyc3",
    size = "s-2vcpu-4gb",
    count = 2,

    firewall = {
      inbound_rules = [
        { protocol = "tcp", ports = "22", sources = { addresses = ["0.0.0.0/0"] } },
        { protocol = "tcp", ports = "80", sources = { addresses = ["0.0.0.0/0"] } },
        { protocol = "tcp", ports = "443", sources = { addresses = ["0.0.0.0/0"] } }
      ]
    },

    tags = ["web", "production"]
  },

  load_balancer = digitalocean.LoadBalancer & {
    name = "web-lb",
    region = "nyc3",
    algorithm = "round_robin",

    forwarding_rules = [
      {
        entry_protocol = "http",
        entry_port = 80,
        target_protocol = "http",
        target_port = 8080
      }
    ],

    health_check = {
      protocol = "http",
      port = 8080,
      path = "/health",
      check_interval_seconds = 10,
      response_timeout_seconds = 5
    }
  },

  database = digitalocean.Database & {
    name = "app-db",
    engine = "pg",
    version = "14",
    size = "db-s-1vcpu-1gb",
    region = "nyc3",
    multi_az = true
  }
}
```

### Example 3: High-Performance Storage

```nickel
{
  app_server = digitalocean.Droplet & {
    name = "app-with-storage",
    region = "nyc3",
    size = "s-4vcpu-8gb",

    volumes = [
      {
        size = 500,
        name = "app-storage",
        filesystem_type = "ext4"
      }
    ]
  },

  backup_storage = digitalocean.Volume & {
    name = "backup-volume",
    size = 1000,
    region = "nyc3",
    description = "Backup storage for app data"
  }
}
```

## Best Practices

### 1. Droplet Management

**Instance Sizing**
- Start with smallest viable size (s-1vcpu-1gb)
- Monitor CPU/memory usage
- Scale vertically for predictable workloads
- Use autoscaling with Kubernetes for bursty workloads

**SSH Key Management**
- Use SSH keys instead of passwords
- Store private keys securely
- Rotate keys regularly (at least yearly)
- Different keys for different environments

**Monitoring**
- Enable monitoring on all Droplets
- Set up alerting for CPU > 80%
- Monitor disk usage
- Alert on high memory usage

### 2. Firewall Configuration

**Principle of Least Privilege**
- Only allow necessary ports
- Specify source IPs when possible
- Use SSH key authentication (no passwords)
- Block unnecessary outbound traffic

**Default Rules**
```nickel
# Minimal firewall for web server
inbound_rules = [
  { protocol = "tcp", ports = "22", sources = { addresses = ["YOUR_OFFICE_IP/32"] } },
  { protocol = "tcp", ports = "80", sources = { addresses = ["0.0.0.0/0"] } },
  { protocol = "tcp", ports = "443", sources = { addresses = ["0.0.0.0/0"] } }
],

outbound_rules = [
  { protocol = "tcp", destinations = { addresses = ["0.0.0.0/0"] } },
  { protocol = "udp", ports = "53", destinations = { addresses = ["0.0.0.0/0"] } }
]
```

### 3. Database Best Practices

**High Availability**
- Use 3-node clusters for production
- Enable automated backups (retain for 30 days)
- Test backup restore procedures
- Use read replicas for scaling reads

**Connection Pooling**
- Enable PgBouncer for PostgreSQL
- Set pool size based on app connections
- Monitor connection count

**Backup Strategy**
- Daily automated backups (DigitalOcean manages)
- Export critical data to Spaces weekly
- Test restore procedures monthly
- Keep backups for minimum 30 days

### 4. Volume Management

**Data Persistence**
- Use volumes for stateful data
- Don't store critical data on Droplet root volume
- Enable automatic snapshots
- Document mount points

**Capacity Planning**
- Monitor volume usage
- Expand volumes as needed (no downtime)
- Delete old snapshots to save costs

### 5. Load Balancer Configuration

**Health Checks**
- Set appropriate health check paths
- Conservative intervals (10-30 seconds)
- Longer timeout to avoid false positives
- Multiple healthy thresholds

**Sticky Sessions**
- Use if application requires session affinity
- Set appropriate TTL (300-3600 seconds)
- Monitor for imbalanced traffic

### 6. Cost Optimization

**Droplet Sizing**
- Right-size instances to actual needs
- Use snapshots to create custom images
- Destroy unused Droplets

**Reserved Droplets**
- Pre-pay for predictable workloads
- 25-30% savings vs hourly

**Object Storage**
- Use lifecycle policies to delete old data
- Compress data before uploading
- Use CDN for frequent access (reduces egress)

## Troubleshooting

### Issue: Droplet Not Accessible

**Symptoms**: Cannot SSH to Droplet, connection timeout

**Diagnosis**:
1. Verify Droplet status in DigitalOcean Control Panel
2. Check firewall rules allow port 22 from your IP
3. Verify SSH key is loaded in SSH agent: `ssh-add -l`
4. Check Droplet has public IP assigned

**Solution**:
```bash
# Add to firewall
doctl compute firewall add-rules firewall-id \
  --inbound-rules="protocol:tcp,ports:22,sources:addresses:YOUR_IP"

# Test SSH
ssh -v -i ~/.ssh/key.pem root@DROPLET_IP

# Or use VNC console in Control Panel
```

### Issue: Volume Not Mounting

**Symptoms**: Volume created but not accessible, mount fails

**Diagnosis**:
```bash
# Check volume attachment
doctl compute volume list

# On Droplet, check block devices
lsblk

# Check filesystem
sudo file -s /dev/sdb
```

**Solution**:
```bash
# Format volume (only first time)
sudo mkfs.ext4 /dev/sdb

# Create mount point
sudo mkdir -p /data

# Mount volume
sudo mount /dev/sdb /data

# Make permanent by editing /etc/fstab
echo '/dev/sdb /data ext4 defaults,nofail,discard 0 0' | sudo tee -a /etc/fstab
```

### Issue: Load Balancer Health Checks Failing

**Symptoms**: Backends marked unhealthy, traffic not flowing

**Diagnosis**:
```bash
# Test health check endpoint manually
curl -i http://BACKEND_IP:8080/health

# Check backend logs
ssh backend-server
tail -f /var/log/app.log
```

**Solution**:
- Verify endpoint returns HTTP 200
- Check backend firewall allows load balancer IPs
- Adjust health check timing (increase timeout)
- Verify backend service is running

### Issue: Database Connection Issues

**Symptoms**: Cannot connect to managed database

**Diagnosis**:
```bash
# Test connectivity from Droplet
psql -h db-host.db.ondigitalocean.com -U admin -d defaultdb

# Check firewall
doctl compute firewall list-rules firewall-id
```

**Solution**:
- Add Droplet to database's trusted sources
- Verify connection string (host, port, username)
- Check database is accepting connections
- For 3-node cluster, use connection pool endpoint

## Summary

DigitalOcean provides a simple, transparent platform ideal for developers and small teams. Its key advantages are:

✓ Simple pricing and transparent costs
✓ Excellent documentation
✓ Good performance for typical workloads
✓ Managed services (databases, Kubernetes)
✓ Global presence
✓ Developer-friendly interface

Start small with a single Droplet and expand to managed services as your application grows.

For more information, visit: [DigitalOcean Documentation](https://www.digitalocean.com/docs/)
