How to Install OpenTofu on WSL2 Ubuntu

OpenTofu is an open-source fork of Terraform, maintained by the Linux Foundation under the MPL 2.0 license. We switched to it after Terraform Cloud’s per-resource pricing got too expensive for our team. This post covers how to install OpenTofu on WSL2 Ubuntu, why it exists, and the common commands you’ll use daily. Examples are run on WSL2 Ubuntu in Windows, but they work on any Ubuntu system.

OpenTofu vs Terraform: What’s Different?

Same HCL syntax, same provider ecosystem, nearly identical CLI. Just replace terraform with tofu. But there are real differences.

Licensing

AspectOpenTofuTerraform
LicenseMPL 2.0 (OSI-approved open source)BSL 1.1 (source-available, not open source)
Commercial useUnrestrictedRestricted for competitive offerings
GovernanceLinux Foundation, community-drivenHashiCorp/IBM, single-vendor controlled

Prerequisites

How to Install OpenTofu on WSL2 Ubuntu

Two options: the quick installer script, or manual APT repository setup.

Option 1: Installer Script (Quick)

curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
chmod +x install-opentofu.sh
./install-opentofu.sh --install-method deb
rm -f install-opentofu.sh

The script downloads GPG keys, adds the repo, and installs the tofu package. The --install-method deb flag tells it to use APT.

Option 2: Manual APT Repository Setup

Step 1: Install dependencies.

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg

Step 2: Add GPG keys.

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://get.opentofu.org/opentofu.gpg | sudo tee /etc/apt/keyrings/opentofu.gpg >/dev/null
curl -fsSL https://packages.opentofu.org/opentofu/tofu/gpgkey | sudo gpg --no-tty --batch --dearmor -o /etc/apt/keyrings/opentofu-repo.gpg >/dev/null
sudo chmod a+r /etc/apt/keyrings/opentofu.gpg /etc/apt/keyrings/opentofu-repo.gpg

Step 3: Add the repository.

echo \
  "deb [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main
deb-src [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main" \
  | sudo tee /etc/apt/sources.list.d/opentofu.list > /dev/null
sudo chmod a+r /etc/apt/sources.list.d/opentofu.list

Step 4: Install.

sudo apt-get update
sudo apt-get install -y tofu

Verify the Installation

tofu version

Expected output:

OpenTofu v1.11.5
on linux_amd64

The binary is tofu, not opentofu.

Running Your First tofu init

Create a project directory and a basic main.tf:

mkdir ~/my-infra && cd ~/my-infra

Add this to main.tf:

terraform {
  required_version = ">= 1.11.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  backend "s3" {
    bucket         = "your-tfstate-bucket"
    key            = "my-infra/terraform.tfstate"
    region         = "ap-southeast-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

provider "aws" {
  region = "ap-southeast-1"
}

OpenTofu still uses the terraform {} block name — it’s backward compatible. Replace your-tfstate-bucket and terraform-locks with your actual values. No remote backend yet? Remove the backend "s3" block and it’ll use local state.

Initialize:

tofu init

This downloads providers, configures the backend, and creates the .terraform.lock.hcl lock file. Output looks like:

Initializing the backend...

Successfully configured the backend "s3"! OpenTofu will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.x.x...
- Installed hashicorp/aws v5.x.x

OpenTofu has been successfully initialized!

If you were previously using Terraform on WSL Ubuntu, same workflow — different command name.

Common OpenTofu Commands

Core Workflow

CommandWhat It Does
tofu initInitialize project, download providers and modules
tofu validateCheck configuration syntax
tofu planPreview changes
tofu applyApply changes to infrastructure
tofu destroyTear down all managed resources

Planning and Applying

Save a plan and apply it later (useful for CI/CD):

tofu plan -out=tfplan
tofu apply tfplan

Skip the confirmation prompt:

tofu apply -auto-approve

Target or exclude specific resources:

# Target a specific resource
tofu apply -target=aws_instance.web_server

# Exclude a resource (OpenTofu-only)
tofu plan -exclude=module.monitoring

Working with Variables

tofu plan -var 'instance_type=t3.medium'
tofu plan -var-file=production.tfvars

Importing Existing Resources

Bring manually-created infrastructure under OpenTofu management:

tofu import aws_instance.web_server i-0abc123def456789

You need the resource block written in your .tf file first. After importing, run tofu plan to check for drift and adjust your config to match.

Or use import blocks for a declarative approach — better for teams since the import is in code:

import {
  to = aws_instance.web_server
  id = "i-0abc123def456789"
}

resource "aws_instance" "web_server" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"
}

Run tofu plan and tofu apply — import happens as part of the regular workflow.

State Management

# List all resources in state
tofu state list

# Show details of a specific resource
tofu state show aws_instance.web_server

# Download state from remote backend
tofu state pull > terraform.tfstate.backup

# Push local state to remote backend (use carefully)
tofu state push terraform.tfstate

# Rename a resource in state (prevents destroy + recreate)
tofu state mv aws_instance.old_name aws_instance.new_name

# Remove resource from state without destroying it
tofu state rm aws_instance.web_server

Other Useful Commands

# Format .tf files
tofu fmt

# Show outputs
tofu output

# Show current state in readable format
tofu show

# Workspace management
tofu workspace list
tofu workspace new staging
tofu workspace select staging

# Unlock a stuck state lock
tofu force-unlock LOCK_ID

Migrating from Terraform to OpenTofu

The migration is straightforward:

  1. Install OpenTofu alongside Terraform (different binaries, no conflict)
  2. Run tofu init in your existing project — it reads the same .tf files
  3. Run tofu plan — if the plan is clean, migration is done
  4. Update CI/CD pipelines to use tofu instead of terraform
  5. Remove Terraform when you’re confident

Watch out for:

  • required_version pinned to a specific Terraform version — update to >= 1.11.0 or remove it
  • Provider hash mismatches — run tofu init -upgrade to regenerate the lock file
  • Terraform Cloud backend — pull state first with terraform state pull, configure a new backend (S3, GCS), then push with tofu state push

If you had Terraform set up before, check How to Upgrade Terraform to a Specific Version to understand how it was installed so you can cleanly remove it.

Bonus: Client-Side State Encryption

One of OpenTofu’s best features. With Terraform, state is plain JSON — even with S3 server-side encryption, the data travels unencrypted to the API. OpenTofu encrypts it locally before sending.

Basic example with passphrase-based encryption:

terraform {
  encryption {
    key_provider "pbkdf2" "main" {
      passphrase = var.state_passphrase
    }

    method "aes_gcm" "main" {
      keys = key_provider.pbkdf2.main
    }

    state {
      method = method.aes_gcm.main
    }

    plan {
      method = method.aes_gcm.main
    }
  }
}

For production, use AWS KMS or another KMS instead of a passphrase.

Conclusion

OpenTofu is a drop-in replacement for Terraform that’s genuinely open source, has features Terraform doesn’t, and costs nothing. If Terraform Cloud pricing is eating into your budget, switching to OpenTofu with an S3 backend is worth the 30 minutes it takes.

If you’re setting up AWS from scratch, check How to Configure AWS SSO CLI Access for Linux Ubuntu to avoid managing long-lived access keys. For managing multiple OpenTofu versions, tofuenv works like nvm but for tofu.