How to Use DigitalOcean's Spaces as a Remote State Backend for IaC

I recently started building a remote homelab within Digital Ocean’s cloud space and I wanted to see if I could leverage their Spaces Object Storage as a compatible remote backend for OpenTofu. At this point I have been using OpenTofu’s “local” backend setup to manage my state file but this isn’t a sustainable method nor actually used in professional setting. So lets migrate our local state over to a remote object storage.

Prerequisites:

  1. Using =>1.6 OpenTofu version

  2. Create your Digital Ocean account and project

  3. Create a Spaces storage bucket (click here for instructions)

  4. Create a Spaces access key (click here for instructions)

Approach

Spaces Object Storage is an S3 compatible object storage service. With this in mind we are going to reuse OpenTofu’s S3 backend support and extend it to a Spaces storage bucket. If you have have completed the required prerequisites, we can proceed forward.

Instructions

Set up required Environment Variables

Using environment variables is the recommended way to provide your Spaces access key. Other methods, such as tofu init -backend-config or hardcoding values, may expose secrets in your .terraform folder and plan files.

OpenTofu’s S3 backend leverages AWS_ prefixed environment variables for configuration. We will use these same variables but supply our Spaces access key values in place of AWS values.

export AWS_ACCESS_KEY_ID="<your_access_key>"
export AWS_SECRET_ACCESS_KEY="<your_secret_key>"

Replace the <your_access_key> and <your_secret_key> placeholders with your actual values.

Setup S3 Backend Configuration

Here is an example of my remote backend configuration. It uses OpenTofu’s S3 backend with DigitalOcean Spaces bucket values.

terraform {
  required_version = "~> 1.9.0"

  backend "s3" {
    endpoints = {
      s3 = "<spaces_bucket_region>.digitaloceanspaces.com"
    }

    bucket = "<spaces_bucket_name>"
    key    = "<path/and/state/file/name>"

    # Deactivate a few AWS-specific checks
    skip_credentials_validation = true
    skip_requesting_account_id  = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    skip_s3_checksum            = true
    region                      = "us-east-1"
  }
}

Values required:

  1. S3 : Replace <spaces_bucket_region> with the region of the bucket you created.

  2. bucket : Replace <spaces_bucket_name> with the name of your bucket.

  3. key : Update <path/and/state/file/name> with path and file name you would like to store your OpenTofu state under. If the path does not exist OpenTofu will create it when your initialize your IaC space.

Migrate or Initialize your State

At this point you should be ready to start using your newly setup remote state in DigitalOcean

Migrate local state to remote

tofu init -migrate-state

Initialize empty OpenTofu space

tofu init

Reference

0
Subscribe to my newsletter

Read articles from Christian Herrera directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Christian Herrera
Christian Herrera

Hey, I'm Chris 👨🏽‍💻👋🏽🤙🏽 I’m a seasoned Platform Engineer based in the LA area with extensive experience leading cloud engineering projects. I specialize in designing, deploying, and managing scalable, high-performance infrastructure using Kubernetes, Terraform, and cloud-native technologies. 💻 Currently, I’m leading Kubernetes-focused initiatives to enhance Developer Experience (DevEx) across cloud platforms like GCP and AWS. By streamlining workflows, optimizing infrastructure, and automating processes, I’m driving efficiency and empowering development teams to work faster and smarter. I’m deeply committed to building scalable, reliable, and cost-effective systems while mentoring teams to implement cloud-native best practices and elevate the overall development process.