OrkStageOrkStage

DigitalOcean

Connect a DigitalOcean team with an API token and Spaces keys, prepare the state bucket, and see what OrkStage creates on App Platform and managed databases.

Preview

The DigitalOcean adapter is covered by unit tests and its OpenTofu modules pass tofu validate. It has not been verified against a live team yet.

OrkStage creates DigitalOcean resources with the OpenTofu modules in orkstage-modules/modules/digitalocean, one isolated state per resource, kept in a Spaces bucket of your own team. Health, logs, deployments and actions use the DigitalOcean REST API.

One cloud target is one DigitalOcean team.

What OrkStage creates

Template resourceCapabilityWhat gets created
networkvpc (default)VPC. DigitalOcean picks a free IP range.
compute.container-serviceapp-platform (default)App Platform app with one service component from an image. Size from cpu and memoryMiB, CPU autoscaling on dedicated sizes, health check, encrypted database URLs.
database.postgresqlmanaged-postgres (default)Managed PostgreSQL in the VPC. Trusted sources are limited to the VPC range unless publicAccess. HA adds a standby node in the same datacenter.
cache.redismanaged-valkey (default)Managed Valkey, Redis compatible, TLS, up to two standby nodes, VPC only
object-storagespaces (default)Spaces bucket with versioning and expiration lifecycle, private unless publicAccess
ingressapp-platform-ingress (default)No infrastructure: each service applies its route path prefix to its own app

Database credentials are never module outputs. PostgreSQL and Valkey publish secret_ref = do-db://<cluster id>, and the adapter reads the connection details from the DigitalOcean API (readSecret) when a resource on another provider needs them. App Platform services receive <ID>_URL for each DigitalOcean database they depend on as a SECRET variable.

Target configuration

config fieldRequiredExampleMeaning
stateBucketyesacme-orkstage-tfstateExisting Spaces bucket for OpenTofu state
stateRegionyesnyc3Spaces region of that bucket

Credential secret

{
  "token": "<DigitalOcean API token>",
  "spacesAccessKeyId": "<Spaces access key>",
  "spacesSecretAccessKey": "<Spaces secret key>"
}

The values reach OpenTofu only as runner environment variables (DIGITALOCEAN_TOKEN, SPACES_ACCESS_KEY_ID, SPACES_SECRET_ACCESS_KEY, and AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for the state backend).

Prepare state storage

Create the bucket once, before validating the target. OrkStage never creates it.

# Spaces key with access to every bucket (state and the buckets OrkStage manages)
doctl spaces keys create orkstage --grants 'bucket=;permission=fullaccess'

# Bucket for state, versioned so an older state can be restored
export AWS_ACCESS_KEY_ID=<access key> AWS_SECRET_ACCESS_KEY=<secret key>
aws s3api create-bucket --bucket acme-orkstage-tfstate --endpoint-url https://nyc3.digitaloceanspaces.com --region us-east-1
aws s3api put-bucket-versioning --bucket acme-orkstage-tfstate --versioning-configuration Status=Enabled --endpoint-url https://nyc3.digitaloceanspaces.com --region us-east-1

The backend signs as us-east-1 against https://<stateRegion>.digitaloceanspaces.com, as DigitalOcean documents, and locks state with use_lockfile.

Token permissions

A full access token works. A custom scoped token needs create, read, update and delete on vpc, app and database, plus account:read and tag:create. Validation probes the VPC, App Platform and database scopes and fails when a scope needed by the resources about to be deployed is missing.

Regions

Regions are datacenter slugs: nyc3, sfo3, ams3, fra1, sgp1, lon1, tor1, blr1, syd1, atl1, nyc1.

App Platform joins a VPC only from one datacenter per region: ams3, atl1, blr1, fra1, lon1, nyc1, sfo3, sgp1, syd1, tor1. In other regions (for example nyc3) a service cannot reach a private database, and deploying such a pair fails validation. Use one of those regions or give the database public access. Spaces is not offered in nyc1.

Actions for triggers

CapabilityActionParametersEffect
app-platformredeployforceBuild (boolean, default true)New App Platform deployment of the current spec, pulling the image again
app-platformrestartnoneRolling restart of the service instances without a new deployment

Deployment history and run logs come from the App Platform API.

Known limits

  • App Platform pulls images from DigitalOcean Container Registry, Docker Hub and GHCR only. Private Docker Hub or GHCR images need registry credentials, which are not wired yet.
  • Autoscaling needs a dedicated CPU instance size. Shared sizes run a fixed instance count.
  • Credentials of dependencies on other providers reach the service as <ID>_CREDENTIALS_REF references, not values.
  • Services do not receive Spaces keys for their buckets, only the bucket name and endpoint.
  • Managed database backups are daily with 7 days of recovery. Retention is not configurable.
  • From 15 October 2026 (new accounts) and 30 November 2026 (all accounts), new Standard Edition PostgreSQL clusters cannot add standby nodes or use plans above 4 GiB. Use overrides.digitalocean.size with an Advanced Edition slug when you need them.
  • A VPC spans the datacenter, so availability zones and NAT gateways are not modelled.
  • There is no load balancer capability yet. ingress is App Platform routing only.
  • Production resources keep force_destroy off on buckets. DigitalOcean has no deletion protection flag for database clusters.

On this page