Devops Developer Tools 1 min read

Stop Managing Forgejo by Hand! Use Terraform Instead

B
Bright Coding
Author
Share:
Stop Managing Forgejo by Hand! Use Terraform Instead
Advertisement

Stop Managing Forgejo by Hand! Use Terraform Instead

Picture this: It's 2 AM. Your team just deployed a new Forgejo instance for a critical client project. The CEO wants twenty repositories, five organizations, granular branch protections, and SSH deploy keys configured by morning. You're clicking through web UI screens like a zombie, copying API tokens, adding collaborators one by one, praying you don't miss a permission. Sound familiar?

Here's the brutal truth. Manual Forgejo administration doesn't scale. Every click is technical debt. Every forgotten setting is a security hole waiting to explode. And when that instance crashes? You're rebuilding from memory, from screenshots, from hope.

But what if your entire Forgejo configuration lived in code? Version-controlled. Reviewable. Reproducible at the push of a button. Enter the terraform-provider-forgejo — the secret weapon that transforms your self-hosted Forgejo from a fragile snowflake into bulletproof infrastructure.

This isn't just another provider. It's the bridge between GitOps philosophy and your private code forge. And in this guide, I'm exposing exactly how to wield it.


What Is terraform-provider-forgejo?

The terraform-provider-forgejo is an official infrastructure-as-code plugin developed by SVA System Vertrieb Alexander GmbH (svalabs) that enables complete lifecycle management of Forgejo resources through Terraform and OpenTofu. Built atop the robust Forgejo SDK for Go by Martijn van der Kleijn, it transforms API operations into declarative, version-controlled configurations.

Forgejo itself emerged as the community-driven fork of Gitea after corporate acquisition concerns, positioning itself as the truly open, self-hosted alternative for teams who refuse vendor lock-in. With over 14 resources and 10 data sources, this provider covers virtually every operational surface of your Forgejo instance.

Why is it trending now? Three forces are converging:

  • The GitOps revolution demands that everything — including your Git host itself — lives in Git
  • Regulatory pressure (SOC 2, ISO 27001) requires auditable, reproducible infrastructure changes
  • Forgejo adoption is accelerating as teams flee GitHub's pricing and GitLab's complexity

The provider sits at this intersection, offering 74.9% test coverage, automated release pipelines, and active maintenance. This isn't experimental software — it's production-hardened tooling from a German systems integrator with real enterprise deployments.


Key Features That Make This Provider Essential

Comprehensive Resource Coverage

The provider doesn't just create repositories — it orchestrates your entire Forgejo ecosystem. From organizations and teams to branch protections and action secrets, every configuration surface is exposed through clean Terraform abstractions.

Dual Authentication Flexibility

API token authentication is recommended for production, with granular scope control (write:organization, write:repository, write:user, optional write:admin). For development or legacy scenarios, username/password authentication remains available with environment variable fallback support.

Repository Lifecycle Mastery

Beyond basic creation, the provider handles:

  • Personal repositories — tied to the authenticated user
  • User repositories — administratively managed for other accounts
  • Organization repositories — with full org hierarchy support
  • Clone operations — importing external repositories
  • Pull mirrors — with configurable sync intervals like 12h0m0s

Destruction Protection

The built-in prevent_destroy lifecycle meta-argument guards against catastrophic data loss. Modify create-only attributes like auto_init or license without triggering destructive recreation.

Import-Ready Architecture

Existing manual configurations aren't left behind. Resources like repositories (owner/name), branch protections (owner/name/branch), users (login), and teams (org/team) all support Terraform import workflows.

OpenTofu Compatibility

In an era of Terraform licensing controversies, this provider explicitly supports both HashiCorp Terraform and the community-driven OpenTofu fork — future-proofing your infrastructure decisions.


Real-World Use Cases Where This Provider Shines

Use Case 1: Multi-Tenant SaaS Platform

You're building a platform where each customer gets isolated Forgejo organizations with standardized repository templates. Manual provisioning? Hours per tenant. With terraform-provider-forgejo:

module "customer_workspace" {
  source = "./modules/forgejo-tenant"
  
  for_each    = var.customers
  org_name    = each.value.org_name
  admin_users = each.value.admin_emails
  repo_template = "standard-saas-template"
}

Result: New customer onboarding drops from 45 minutes to 30 seconds. Compliance auditors see every permission change in Git history.

Use Case 2: Disaster Recovery & Environment Parity

Your production Forgejo holds 200+ repositories with intricate branch protection rules. When your staging environment drifts, bugs slip through. The provider enables:

# production.tfvars and staging.tfvars drive identical structures
# Only host endpoints differ

Result: Staging becomes a true production mirror. Disaster recovery means terraform apply to a fresh instance, not frantic wiki documentation.

Use Case 3: CI/CD Secret Rotation

Action secrets scattered across repositories become unmanageable security risks. Centralize with:

resource "forgejo_repository_action_secret" "registry_token" {
  for_each    = var.production_repos
  repository  = each.value
  name        = "CONTAINER_REGISTRY_TOKEN"
  data        = var.registry_token_encrypted
}

Result: Rotate one variable, propagate everywhere. No more "where did we use this token?" panic at 3 AM.

Use Case 4: Temporary Review Environments

Spin up complete Forgejo environments for security audits, penetration testing, or contractor access — then destroy cleanly:

resource "forgejo_organization" "audit_2024_q1" {
  name = "security-audit-${formatdate("YYYY-MM", timestamp())}"
}

# Automatic cleanup via terraform destroy or workspace deletion

Result: Ephemeral infrastructure with zero residual access. Audit trails that actually satisfy auditors.


Step-by-Step Installation & Setup Guide

Prerequisites

  • Terraform ≥ 1.0 or OpenTofu ≥ 1.6
  • Running Forgejo instance (local or remote)
  • Administrative access to generate API tokens

Step 1: Configure Provider Source

Create or modify your terraform.tf:

terraform {
  required_providers {
    forgejo = {
      source  = "svalabs/forgejo"
      version = "~> 1.4.0"  # Pin to stable release, allow patches
    }
  }
}

The ~> constraint permits patch updates (1.4.1, 1.4.2) while protecting against breaking changes in 1.5.0.

Step 2: Authenticate to Your Forgejo Instance

Recommended: API Token Method

Navigate in Forgejo: Settings → Applications → Access tokens → Generate new token

Select these scopes:

  • write:organization — manage orgs and teams
  • write:repository — create and configure repos
  • write:user — manage user resources
  • write:admin (optional) — required for user/SSH key management

Configure the provider:

provider "forgejo" {
  host      = "https://forgejo.yourcompany.com"
  api_token = var.forgejo_api_token  # Never hardcode secrets!
}

Set via environment variable for CI/CD safety:

export FORGEJO_API_TOKEN="gitea_xxxxxxxxxxxxxxxx"

Alternative: Username/Password

provider "forgejo" {
  host     = "http://localhost:3000"  # Development only
  username = var.forgejo_username
  password = var.forgejo_password
}

Environment fallbacks: FORGEJO_USERNAME, FORGEJO_PASSWORD

Step 3: Handle Self-Signed Certificates (If Needed)

For internal deployments with private CAs:

# Extract and trust the certificate
echo quit | openssl s_client -showcerts \
  -servername forgejo.internal.company.com \
  -connect forgejo.internal.company.com:443 \
  > /etc/ssl/certs/forgejo-ca.pem

# Update certificate store
update-ca-certificates  # Debian/Ubuntu
# or
update-ca-trust extract  # RHEL/CentOS/Fedora

Critical: The Forgejo API client does not support certificate ignore flags. Proper PKI is mandatory for HTTPS.

Step 4: Initialize and Validate

terraform init
terraform plan

Resolve any authentication errors before proceeding.

Advertisement

REAL Code Examples from the Repository

These examples are extracted directly from the official documentation, enhanced with production-ready context.

Example 1: Personal Repository Creation

The simplest entry point — creating a repository under your authenticated account:

resource "forgejo_repository" "example" {
  name        = "new_personal_repo"
  description = "Purely for testing..."
}

What's happening: Without an owner specified, the provider binds this repository to the user associated with your API token. This is ideal for individual projects or when the authenticated user is the default owner. The repository receives Forgejo defaults: public visibility, main default branch, no special protections.

Production tip: Always add lifecycle { prevent_destroy = true } once real code exists. The default state is dangerously disposable.


Example 2: Administrative User Repository Creation

When you need to provision repositories for other users (requires write:admin scope):

resource "forgejo_user" "owner" {
  login = "new_user"
  # Additional user attributes available: email, full_name, etc.
}

resource "forgejo_repository" "example" {
  owner       = forgejo_user.owner.login  # Reference created user
  name        = "new_user_repo"
  description = "Purely for testing..."
}

What's happening: This demonstrates Terraform's implicit dependency graph. The forgejo_repository resource references forgejo_user.owner.login, so Terraform knows to create the user first. The write:admin scope is mandatory here — without it, you'll receive a scope error that blocks creation.

Real-world pattern: Use this for automated onboarding scripts where new team members need pre-configured repository structures.


Example 3: Organization Repository with Full Configuration

The power move — complete organizational control with customized settings:

resource "forgejo_organization" "owner" {
  name = "new_org"
}

resource "forgejo_repository" "example" {
  owner          = forgejo_organization.owner.name
  name           = "new_org_repo"
  description    = "Purely for testing..."
  private        = true                    # Restrict visibility
  default_branch = "dev"                   # Non-standard default
  auto_init      = true                    # Initialize with README
  trust_model    = "collaborator"          # Commit signature trust

  # Fine-grained issue tracker configuration
  internal_tracker = {
    enable_time_tracker                   = false
    allow_only_contributors_to_track_time = false
    enable_issue_dependencies             = false
  }
}

What's happening: This showcases the provider's depth. The trust_model controls how commit signatures are validated — collaborator means only project collaborators' signatures are trusted, not arbitrary keys. The internal_tracker block disables time tracking and issue dependencies, simplifying the UI for teams that don't need these features.

Critical warning: auto_init is create-only. Change it after creation, and Terraform plans to destroy and recreate your repository — with all data lost. This is where prevent_destroy becomes essential.


Example 4: Pull Mirror Configuration

Keep external repositories synchronized automatically:

resource "forgejo_repository" "mirror" {
  name            = "mirror_test_repo"
  clone_addr      = "https://github.com/svalabs/terraform-provider-forgejo"
  mirror          = true                   # Enable mirroring behavior
  mirror_interval = "12h0m0s"             # Sync every 12 hours
}

What's happening: Forgejo pulls from the upstream clone_addr at the specified Go duration interval. The mirror = true flag distinguishes this from a one-time clone. This is invaluable for:

  • Air-gapped environments needing curated external code
  • Backup strategies for critical upstream dependencies
  • Compliance requirements mandating internal code copies

Gotcha: The mirror interval must use Go's duration format (12h0m0s, not cron syntax). Invalid formats fail during terraform plan.


Example 5: Protecting Against Accidental Destruction

The safety net every production configuration needs:

resource "forgejo_repository" "important" {
  name        = "production-api"
  description = "Core API service — DO NOT DELETE"
  private     = true

  lifecycle {
    prevent_destroy = true  # Terraform will refuse destruction
  }
}

What's happening: The lifecycle meta-argument operates at the Terraform core level, not the provider. When prevent_destroy = true, any operation that would delete this resource — including attribute changes that force recreation — errors out. You must explicitly remove this block to destroy.

Operational workflow: For planned decommissioning, comment out prevent_destroy, run terraform apply, then terraform destroy — or use targeted removal.


Advanced Usage & Best Practices

State Management for Team Environments

Never use local state for shared Forgejo management. Configure remote state immediately:

terraform {
  backend "s3" {
    bucket         = "terraform-state-forgejo"
    key            = "production/terraform.tfstate"
    region         = "eu-central-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

Modular Architecture

Extract repeated patterns into modules:

modules/
├── standard-repo/
│   ├── main.tf      # forgejo_repository with defaults
│   ├── variables.tf # owner, name, description
│   └── outputs.tf   # repo URL, clone addresses
└── protected-team/
    ├── main.tf      # org + team + branch_protection
    └── ...

Secret Rotation Without Downtime

Use Terraform's random_password resource with keepers for controlled rotation:

resource "random_password" "action_secret" {
  length  = 32
  special = false
  keepers = {
    rotation_date = var.force_rotation ? timestamp() : "initial"
  }
}

Drift Detection Integration

Schedule terraform plan -detailed-exitcode in CI. Exit code 2 indicates drift — trigger alerts before configuration chaos compounds.


Comparison with Alternatives

Capability terraform-provider-forgejo Manual Web UI Custom Scripts Ansible Modules
State tracking ✅ Native Terraform state ❌ None ❌ Manual file/db ⚠️ Limited
Plan preview terraform plan ❌ None ❌ None ⚠️ Check mode
Version control ✅ Full Git history ❌ None ✅ If committed ✅ If committed
Dependency graph ✅ Automatic ordering ❌ Manual sequence ❌ Manual coding ⚠️ Task ordering
Idempotency ✅ Built-in ❌ Click fatigue ⚠️ Must implement ⚠️ Must verify
Forgejo-specific ✅ Native resources ✅ Full features ⚠️ API coverage varies ❌ Generic git
OpenTofu support ✅ Explicit N/A N/A ⚠️ Uncertain
Learning curve Medium Low High Medium

The verdict: Manual administration dies at scale. Custom scripts reinvent Terraform's state engine poorly. Ansible lacks Forgejo-native modules. This provider is the purpose-built, future-proof choice.


FAQ

What Forgejo versions are supported?

The provider targets Forgejo's stable API releases. Check the GitHub releases page for version compatibility matrices. Generally, Forgejo 1.20+ is fully supported.

Can I use this with Gitea instead of Forgejo?

Not recommended. While Forgejo forked from Gitea, their APIs have diverged. The provider explicitly targets Forgejo's API surface. For Gitea, use the dedicated Lerentis/gitea provider.

Why does my API token fail with scope errors?

Regenerate your token with all required scopes: write:organization, write:repository, write:user. Add write:admin for user/SSH key management. The error message lists exactly what's missing.

How do I import existing repositories?

terraform import forgejo_repository.example "owner_name/repo_name"

Verify with terraform plan — expect no changes for correctly imported resources.

Is OpenTofu really supported, or just marketing?

Genuinely supported. The provider's test matrix includes OpenTofu builds. The source declaration uses both project names explicitly. This isn't future-washing — it's tested compatibility.

What about repository data backup?

The provider manages configuration, not content. Implement separate backup strategies for Git data (restic, Borg, Forgejo's built-in dump). Use prevent_destroy to guard against configuration-level accidents.

How do I contribute or report bugs?

See CONTRIBUTING.md for development setup. The project welcomes issues, documentation improvements, and resource expansions under MPL-2.0 licensing.


Conclusion

Manual Forgejo administration is a liability masquerading as convenience. Every web UI click is an unreviewed change. Every midnight configuration session is a disaster waiting for its 3 AM phone call.

The terraform-provider-forgejo transforms this chaos into controlled, auditable, reproducible infrastructure. With 14 resources, 10 data sources, explicit OpenTofu support, and production-hardened reliability from SVA System Vertrieb Alexander GmbH, it's the missing link in your GitOps toolchain.

Stop treating your code forge as a pet. Start managing it as cattle.

Your next step: Fork the repository, explore the examples/ directory, and run your first terraform plan against a test Forgejo instance. The 30 minutes you invest today will save you thirty hours of firefighting this year.

Infrastructure as code isn't the future — it's the present you should have adopted yesterday. With Forgejo and Terraform, that future is finally within reach.

Advertisement

Comments (0)

No comments yet. Be the first to share your thoughts!

Leave a Comment

Apps & Tools Open Source

Apps & Tools Open Source

Bright Coding Prompt

Bright Coding Prompt

Categories

Advertisement
Advertisement
Advertisement