No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Matthew Baggett faf0f432c4
Correct the usage: clone it, do not serve it as a network mirror
Forgejo cannot serve this repo as an OpenTofu network_mirror. The protocol
requires the index JSON be returned as application/json; Forgejo serves every
raw file as text/plain on /raw, /media and the API endpoint alike, as an XSS
precaution, and it is not per-file configurable. tofu init fails with 'response
has invalid Content-Type'. Measured against Forgejo 16.0.1, not assumed.

A clone plus filesystem_mirror gets the same result with no reverse proxy in
front, and without making every init depend on git.grey.ooo being up.

Records the trap that cost the most time: an unfiltered filesystem_mirror
alongside an unfiltered direct does NOT act as a catch-all. direct wins, and
every provider is fetched from the registry as though no mirror were
configured. With explicit include lists on both, all four consuming roots
resolve offline.
2026-08-30 23:44:08 +01:00
.github/workflows Seed the mirror with six pinned providers 2026-08-30 23:34:45 +01:00
registry.opentofu.org Seed the mirror with six pinned providers 2026-08-30 23:34:45 +01:00
registry.terraform.io/arsolitt/garagehq Seed the mirror with six pinned providers 2026-08-30 23:34:45 +01:00
.gitignore Seed the mirror with six pinned providers 2026-08-30 23:34:45 +01:00
.terraform.lock.hcl Seed the mirror with six pinned providers 2026-08-30 23:34:45 +01:00
providers.tf Seed the mirror with six pinned providers 2026-08-30 23:34:45 +01:00
README.md Correct the usage: clone it, do not serve it as a network mirror 2026-08-30 23:44:08 +01:00

tofu-providers

An OpenTofu network mirror, served straight out of this repo's raw file URLs.

providers.tf pins the versions; CI runs tofu providers mirror and commits the archives in the layout the protocol expects. No extra software hosts it — the protocol is plain GETs for JSON and zips, and tofu providers mirror emits relative archive URLs, which is what makes the tree portable to any base URL.

Using it — clone it, do not point a network_mirror at it

Forgejo cannot serve this as a network_mirror. The protocol requires the index JSON be returned as application/json; Forgejo serves every raw file as text/plain; charset=utf-8 — on /raw, /media and the API endpoint alike — as an XSS precaution, and it is not per-file configurable. tofu init fails with "response has invalid Content-Type: must be application/json". Measured against Forgejo 16.0.1.

Clone it and use a filesystem_mirror instead. Same result, no reverse proxy, and no dependency on git.grey.ooo at init time:

provider_installation {
  filesystem_mirror {
    path = "/abs/path/to/this/clone"
    include = [
      "registry.terraform.io/arsolitt/*",
      "registry.opentofu.org/kreuzwerker/*",
      "registry.opentofu.org/hashicorp/*",
      "registry.opentofu.org/bpg/*",
    ]
  }
  direct { exclude = [ ...the same four... ] }
}

The include list is required, not tidiness. An unfiltered filesystem_mirror alongside an unfiltered direct does not act as a catch-all — direct wins and every provider is fetched from the registry as though the mirror were not configured. Adding a namespace means adding it in both lists.

Paths in filesystem_mirror resolve against the working directory, not the config file, so it must be absolute.

What this is not

Not the source. The upstream repositories are pull-mirrored separately, as mirrors/Arsolitt-terraform-provider-garagehq and mirrors/kreuzwerker-terraform-provider-docker. Those protect against the upstream repo disappearing; this protects against the registry being unreachable. Different risks, different mirrors — one does not substitute for the other.

The trade being made

Every tofu init that uses this depends on git.grey.ooo being up — including the one you run while trying to fix git.grey.ooo. A local filesystem mirror has no such circularity, so consumers should keep one configured ahead of this in provider_installation and treat this as the shared, always-current copy.

Pinning is the point

A mirror that tracks "latest" is a slower registry, not a mirror. Versions move only when providers.tf is edited, and the CI commit records what changed.